Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add new entry in Release_Notes. master next
authorArnaud Giersch <arnaud.giersch@univ-fcomte.fr>
Mon, 27 Nov 2023 08:42:04 +0000 (09:42 +0100)
committerArnaud Giersch <arnaud.giersch@univ-fcomte.fr>
Mon, 27 Nov 2023 08:42:04 +0000 (09:42 +0100)
861 files changed:
.circleci/config.yml
.github/workflows/ci-batsim.yml
.github/workflows/ci-bigdft.yml
.github/workflows/ci-starpu.yml
.github/workflows/ci-wrench.yml
.github/workflows/docker-stable.yml
.github/workflows/docker.yml
.github/workflows/git.yml
.gitignore
.gitlab-ci.yml
.mailmap
AUTHORS
BuildSimGrid.sh
CMakeLists.txt
COPYING
ChangeLog
FindSimGrid.cmake
MANIFEST.in
NEWS
doc/doxygen/inside_release.doc
doc/doxygen/outcomes_vizu.doc
doc/doxygen/uhood_switch.doc
docs/Build.sh
docs/find-missing.ignore
docs/find-missing.py
docs/requirements.txt
docs/source/Configuring_SimGrid.rst
docs/source/Doxyfile
docs/source/Installing_SimGrid.rst
docs/source/Introduction.rst
docs/source/Models.rst
docs/source/Platform_routing.rst
docs/source/Plugins.rst
docs/source/Release_Notes.rst
docs/source/Start_your_own_project.rst
docs/source/Tutorial_DAG.rst
docs/source/Tutorial_Model-checking.rst
docs/source/app_s4u.rst
docs/source/app_smpi.rst
docs/source/conf.py
docs/source/img/battery_degradation.svg [new file with mode: 0644]
docs/source/img/dag.svg [moved from docs/source/tuto_dag/img/dag.svg with 100% similarity]
docs/source/img/dag1.svg [moved from docs/source/tuto_dag/img/dag1.svg with 100% similarity]
docs/source/img/dag2.svg [moved from docs/source/tuto_dag/img/dag2.svg with 100% similarity]
docs/source/tuto_dag/dag_lab1.cpp [deleted file]
docs/source/tuto_dag/dag_lab2-1.cpp [deleted file]
docs/source/tuto_dag/dag_lab2-2.cpp [deleted file]
docs/source/tuto_dag/dag_lab2-3.cpp [deleted file]
docs/source/tuto_dag/small_platform.xml [deleted file]
docs/source/tuto_disk/CMakeLists.txt
docs/source/tuto_disk/Dockerfile
docs/source/tuto_mc/ndet-receive-s4u.cpp
docs/source/tuto_network_calibration/CMakeLists.txt
docs/source/tuto_network_calibration/Dockerfile
docs/source/tuto_network_calibration/dahu_platform_ckmeans.cpp
docs/source/tuto_network_calibration/dahu_platform_dhist.cpp
docs/source/tuto_network_calibration/network_calibration_tutorial.ipynb
docs/source/tuto_network_calibration/network_calibration_tutorial.rst
docs/source/tuto_s4u/draw_gantt.R
examples/README.rst
examples/c/CMakeLists.txt
examples/c/activityset-testany/activityset-testany.c [new file with mode: 0644]
examples/c/activityset-testany/activityset-testany.tesh [new file with mode: 0644]
examples/c/activityset-waitall/activityset-waitall.c [new file with mode: 0644]
examples/c/activityset-waitall/activityset-waitall.tesh [new file with mode: 0644]
examples/c/activityset-waitallfor/activityset-waitallfor.c [new file with mode: 0644]
examples/c/activityset-waitallfor/activityset-waitallfor.tesh [new file with mode: 0644]
examples/c/activityset-waitany/activityset-waitany.c [new file with mode: 0644]
examples/c/activityset-waitany/activityset-waitany.tesh [new file with mode: 0644]
examples/c/app-chainsend/broadcaster.c
examples/c/app-chainsend/chainsend.h
examples/c/app-chainsend/peer.c
examples/c/comm-waitall/comm-waitall.c [deleted file]
examples/c/comm-waitall/comm-waitall.tesh [deleted file]
examples/c/comm-waitall/comm-waitall_d.xml [deleted file]
examples/c/comm-waitany/comm-waitany.c [deleted file]
examples/c/comm-waitany/comm-waitany.tesh [deleted file]
examples/c/comm-waitany/comm-waitany_d.xml [deleted file]
examples/c/exec-waitany/exec-waitany.c [deleted file]
examples/c/exec-waitany/exec-waitany.tesh [deleted file]
examples/c/platform-failures/platform-failures.tesh
examples/cpp/CMakeLists.txt
examples/cpp/activityset-testany/s4u-activityset-testany.cpp [moved from examples/cpp/activity-testany/s4u-activity-testany.cpp with 59% similarity]
examples/cpp/activityset-testany/s4u-activityset-testany.tesh [new file with mode: 0644]
examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp [new file with mode: 0644]
examples/cpp/activityset-waitall/s4u-activityset-waitall.tesh [new file with mode: 0644]
examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp [new file with mode: 0644]
examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.tesh [new file with mode: 0644]
examples/cpp/activityset-waitany/s4u-activityset-waitany.cpp [moved from examples/cpp/activity-waitany/s4u-activity-waitany.cpp with 56% similarity]
examples/cpp/activityset-waitany/s4u-activityset-waitany.tesh [new file with mode: 0644]
examples/cpp/app-chainsend/s4u-app-chainsend.cpp
examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp [new file with mode: 0644]
examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh [new file with mode: 0644]
examples/cpp/battery-connector/s4u-battery-connector.cpp [new file with mode: 0644]
examples/cpp/battery-connector/s4u-battery-connector.tesh [new file with mode: 0644]
examples/cpp/battery-degradation/plot_battery_degradation.py [new file with mode: 0644]
examples/cpp/battery-degradation/s4u-battery-degradation.cpp [new file with mode: 0644]
examples/cpp/battery-degradation/s4u-battery-degradation.tesh [new file with mode: 0644]
examples/cpp/battery-energy/s4u-battery-energy.cpp [new file with mode: 0644]
examples/cpp/battery-energy/s4u-battery-energy.tesh [new file with mode: 0644]
examples/cpp/battery-simple/s4u-battery-simple.cpp [new file with mode: 0644]
examples/cpp/battery-simple/s4u-battery-simple.tesh [new file with mode: 0644]
examples/cpp/chiller-simple/s4u-chiller-simple.cpp [new file with mode: 0644]
examples/cpp/chiller-simple/s4u-chiller-simple.tesh [new file with mode: 0644]
examples/cpp/clusters-multicpu/s4u-clusters-multicpu.cpp
examples/cpp/comm-failure/s4u-comm-failure.cpp
examples/cpp/comm-failure/s4u-comm-failure.tesh
examples/cpp/comm-ready/s4u-comm-ready.cpp
examples/cpp/comm-testany/s4u-comm-testany.cpp [deleted file]
examples/cpp/comm-testany/s4u-comm-testany.tesh [deleted file]
examples/cpp/comm-waitall/s4u-comm-waitall.cpp [deleted file]
examples/cpp/comm-waitall/s4u-comm-waitall.tesh [deleted file]
examples/cpp/comm-waitany/s4u-comm-waitany.cpp [deleted file]
examples/cpp/comm-waitany/s4u-comm-waitany.tesh [deleted file]
examples/cpp/dag-comm/s4u-dag-comm.cpp
examples/cpp/dag-comm/s4u-dag-comm.tesh
examples/cpp/dag-failure/s4u-dag-failure.cpp
examples/cpp/dag-from-dax-simple/dag.xml [moved from docs/source/tuto_dag/simple_dax.xml with 100% similarity]
examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.cpp [new file with mode: 0644]
examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.tesh [new file with mode: 0644]
examples/cpp/dag-from-dax/s4u-dag-from-dax.cpp
examples/cpp/dag-from-dot-simple/dag.dot [moved from docs/source/tuto_dag/simple_dot.dot with 100% similarity]
examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.cpp [new file with mode: 0644]
examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.tesh [new file with mode: 0644]
examples/cpp/dag-from-dot/s4u-dag-from-dot.cpp
examples/cpp/dag-from-json-simple/dag.json [moved from docs/source/tuto_dag/simple_json.json with 81% similarity]
examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.cpp [new file with mode: 0644]
examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.tesh [new file with mode: 0644]
examples/cpp/dag-io/s4u-dag-io.cpp
examples/cpp/dag-io/s4u-dag-io.tesh
examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
examples/cpp/dag-simple/s4u-dag-simple.cpp
examples/cpp/dag-simple/s4u-dag-simple.tesh
examples/cpp/dag-tuto/s4u-dag-tuto.cpp [new file with mode: 0644]
examples/cpp/dag-tuto/s4u-dag-tuto.tesh [new file with mode: 0644]
examples/cpp/dht-kademlia/message.hpp
examples/cpp/energy-exec-ptask/s4u-energy-exec-ptask.cpp
examples/cpp/energy-link/s4u-energy-link.cpp
examples/cpp/exec-dependent/s4u-exec-dependent.cpp
examples/cpp/exec-failure/s4u-exec-failure.cpp
examples/cpp/exec-ptask-multicore-latency/s4u-exec-ptask-multicore-latency.cpp
examples/cpp/exec-ptask-multicore/s4u-exec-ptask-multicore.cpp
examples/cpp/exec-threads/s4u-exec-threads.cpp
examples/cpp/exec-waitany/s4u-exec-waitany.cpp [deleted file]
examples/cpp/exec-waitany/s4u-exec-waitany.tesh [deleted file]
examples/cpp/io-dependent/s4u-io-dependent.cpp
examples/cpp/io-disk-raw/s4u-io-disk-raw.cpp
examples/cpp/io-file-system/s4u-io-file-system.cpp
examples/cpp/maestro-set/s4u-maestro-set.cpp
examples/cpp/mc-bugged1-liveness/promela_bugged1_liveness [deleted file]
examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner [deleted file]
examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh [deleted file]
examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp [deleted file]
examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh [deleted file]
examples/cpp/mc-bugged1/s4u-mc-bugged1.tesh
examples/cpp/mc-bugged2-liveness/promela_bugged2_liveness [deleted file]
examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.cpp [deleted file]
examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.tesh [deleted file]
examples/cpp/mc-bugged2/s4u-mc-bugged2.tesh
examples/cpp/mc-electric-fence/s4u-mc-electric-fence.tesh
examples/cpp/mc-failing-assert/s4u-mc-failing-assert-nodpor.tesh
examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh [deleted file]
examples/cpp/mc-failing-assert/s4u-mc-failing-assert.tesh
examples/cpp/mess-wait/s4u-mess-wait.cpp [new file with mode: 0644]
examples/cpp/mess-wait/s4u-mess-wait.tesh [new file with mode: 0644]
examples/cpp/network-factors/s4u-network-factors.cpp
examples/cpp/network-nonlinear/s4u-network-nonlinear.cpp
examples/cpp/network-ns3/s4u-network-ns3-notime.tesh [moved from examples/cpp/network-ns3/s4u-network-ns3.tesh with 76% similarity]
examples/cpp/network-ns3/s4u-network-ns3-timed.tesh [new file with mode: 0644]
examples/cpp/network-wifi/s4u-network-wifi.cpp
examples/cpp/platform-comm-serialize/s4u-platform-comm-serialize.cpp
examples/cpp/platform-failures/s4u-platform-failures.cpp
examples/cpp/platform-failures/s4u-platform-failures.tesh
examples/cpp/plugin-jbod/s4u-plugin-jbod.cpp [new file with mode: 0644]
examples/cpp/plugin-jbod/s4u-plugin-jbod.tesh [new file with mode: 0644]
examples/cpp/plugin-link-load/s4u-plugin-link-load.cpp
examples/cpp/plugin-prodcons/s4u-plugin-prodcons.cpp
examples/cpp/solar-panel-simple/s4u-solar-panel-simple.cpp [new file with mode: 0644]
examples/cpp/solar-panel-simple/s4u-solar-panel-simple.tesh [new file with mode: 0644]
examples/cpp/synchro-barrier/s4u-mc-synchro-barrier.tesh
examples/cpp/synchro-barrier/s4u-synchro-barrier.cpp
examples/cpp/synchro-condition-variable-waituntil/s4u-synchro-condition-variable-waituntil.cpp
examples/cpp/synchro-mutex/s4u-mc-synchro-mutex.tesh
examples/cpp/synchro-semaphore/s4u-mc-synchro-semaphore.tesh
examples/cpp/task-dispatch/s4u-task-dispatch.cpp [new file with mode: 0644]
examples/cpp/task-dispatch/s4u-task-dispatch.tesh [new file with mode: 0644]
examples/cpp/task-io/s4u-task-io.cpp [new file with mode: 0644]
examples/cpp/task-io/s4u-task-io.tesh [new file with mode: 0644]
examples/cpp/task-microservice/s4u-task-microservice.cpp [new file with mode: 0644]
examples/cpp/task-microservice/s4u-task-microservice.tesh [new file with mode: 0644]
examples/cpp/task-parallelism/s4u-task-parallelism.cpp [new file with mode: 0644]
examples/cpp/task-parallelism/s4u-task-parallelism.tesh [new file with mode: 0644]
examples/cpp/task-simple/s4u-task-simple.cpp [new file with mode: 0644]
examples/cpp/task-simple/s4u-task-simple.tesh [new file with mode: 0644]
examples/cpp/task-storm/s4u-task-storm.cpp [new file with mode: 0644]
examples/cpp/task-storm/s4u-task-storm.tesh [new file with mode: 0644]
examples/cpp/task-switch-host/s4u-task-switch-host.cpp [new file with mode: 0644]
examples/cpp/task-switch-host/s4u-task-switch-host.tesh [new file with mode: 0644]
examples/cpp/task-variable-load/s4u-task-variable-load.cpp [new file with mode: 0644]
examples/cpp/task-variable-load/s4u-task-variable-load.tesh [new file with mode: 0644]
examples/cpp/trace-categories/s4u-trace-categories.cpp
examples/cpp/trace-masterworkers/s4u-trace-masterworkers.cpp
examples/cpp/trace-process-migration/s4u-trace-process-migration.cpp
examples/cpp/trace-process-migration/s4u-trace-process-migration.tesh
examples/platforms/griffon.cpp
examples/platforms/routing_cluster.cpp
examples/platforms/supernode.cpp
examples/python/CMakeLists.txt
examples/python/activityset-testany/activityset-testany.py [new file with mode: 0644]
examples/python/activityset-testany/activityset-testany.tesh [moved from examples/cpp/activity-testany/s4u-activity-testany.tesh with 87% similarity]
examples/python/activityset-waitall/activityset-waitall.py [new file with mode: 0644]
examples/python/activityset-waitall/activityset-waitall.tesh [new file with mode: 0644]
examples/python/activityset-waitallfor/activityset-waitallfor.py [new file with mode: 0644]
examples/python/activityset-waitallfor/activityset-waitallfor.tesh [new file with mode: 0644]
examples/python/activityset-waitany/activityset-waitany.py [new file with mode: 0644]
examples/python/activityset-waitany/activityset-waitany.tesh [moved from examples/cpp/activity-waitany/s4u-activity-waitany.tesh with 59% similarity]
examples/python/clusters-multicpu/clusters-multicpu.py
examples/python/comm-failure/comm-failure.py
examples/python/comm-failure/comm-failure.tesh
examples/python/comm-ready/comm-ready.py
examples/python/comm-testany/comm-testany.py [deleted file]
examples/python/comm-testany/comm-testany.tesh [deleted file]
examples/python/comm-waitall/comm-waitall.py [deleted file]
examples/python/comm-waitall/comm-waitall.tesh [deleted file]
examples/python/comm-waitallfor/comm-waitallfor.py [deleted file]
examples/python/comm-waitallfor/comm-waitallfor.tesh [deleted file]
examples/python/comm-waitany/comm-waitany.py [deleted file]
examples/python/comm-waitany/comm-waitany.tesh [deleted file]
examples/python/network-nonlinear/network-nonlinear.py
examples/python/platform-comm-serialize/platform-comm-serialize.py
examples/python/platform-failures/platform-failures.tesh
examples/python/plugin-host-load/plugin-host-load.py [new file with mode: 0644]
examples/python/plugin-host-load/plugin-host-load.tesh [new file with mode: 0644]
examples/python/task-io/task-io.py [new file with mode: 0644]
examples/python/task-io/task-io.tesh [new file with mode: 0644]
examples/python/task-simple/task-simple.py [new file with mode: 0644]
examples/python/task-simple/task-simple.tesh [new file with mode: 0644]
examples/python/task-switch-host/task-switch-host.py [new file with mode: 0644]
examples/python/task-switch-host/task-switch-host.tesh [new file with mode: 0644]
examples/python/task-variable-load/task-variable-load.py [new file with mode: 0644]
examples/python/task-variable-load/task-variable-load.tesh [new file with mode: 0644]
examples/smpi/CMakeLists.txt
examples/smpi/comm_dynamic_costs/comm-dynamic-cost.cpp
examples/smpi/gemm/gemm.c
examples/smpi/gemm/gemm.tesh
examples/smpi/mc/bugged1_liveness.c [deleted file]
examples/smpi/mc/hostfile_bugged1_liveness [deleted file]
examples/smpi/mc/hostfile_non_termination [deleted file]
examples/smpi/mc/mutual_exclusion.c
examples/smpi/mc/non_termination1.c [deleted file]
examples/smpi/mc/non_termination2.c [deleted file]
examples/smpi/mc/non_termination3.c [deleted file]
examples/smpi/mc/non_termination4.c [deleted file]
examples/smpi/mc/only_send_deterministic.tesh
examples/smpi/mc/promela_bugged1_liveness [deleted file]
examples/smpi/mc/sendsend.tesh
examples/smpi/replay/replay.cpp
examples/smpi/simple-execute/simple-execute.c
examples/smpi/smpi_s4u_masterworker/masterworker_mailbox_smpi.cpp
examples/smpi/smpi_s4u_masterworker/s4u_smpi.tesh
examples/smpi/trace/trace.tesh
examples/smpi/trace_simple/trace_simple.tesh
examples/sthread/CMakeLists.txt
examples/sthread/pthread-mc-mutex-recursive.tesh [new file with mode: 0644]
examples/sthread/pthread-mc-mutex-simple.tesh
examples/sthread/pthread-mc-mutex-simpledeadlock.tesh
examples/sthread/pthread-mc-producer-consumer.tesh
examples/sthread/pthread-mutex-recursive.c [new file with mode: 0644]
examples/sthread/pthread-mutex-recursive.tesh [new file with mode: 0644]
examples/sthread/pthread-mutex-simple.c
examples/sthread/pthread-mutex-simple.tesh
examples/sthread/pthread-mutex-simpledeadlock.c
examples/sthread/pthread-producer-consumer.c
examples/sthread/pthread-producer-consumer.tesh
examples/sthread/stdobject/stdobject.cpp
examples/sthread/stdobject/stdobject.tesh
examples/sthread/sthread-mutex-simple.tesh
include/simgrid/Exception.hpp
include/simgrid/activity_set.h [new file with mode: 0644]
include/simgrid/comm.h
include/simgrid/engine.h
include/simgrid/exec.h
include/simgrid/forward.h
include/simgrid/host.h
include/simgrid/instr.h
include/simgrid/kernel/ProfileBuilder.hpp
include/simgrid/kernel/Timer.hpp
include/simgrid/kernel/resource/Action.hpp
include/simgrid/kernel/resource/Model.hpp
include/simgrid/kernel/routing/ClusterZone.hpp
include/simgrid/kernel/routing/DijkstraZone.hpp
include/simgrid/kernel/routing/DragonflyZone.hpp
include/simgrid/kernel/routing/EmptyZone.hpp
include/simgrid/kernel/routing/FatTreeZone.hpp
include/simgrid/kernel/routing/FloydZone.hpp
include/simgrid/kernel/routing/FullZone.hpp
include/simgrid/kernel/routing/NetPoint.hpp
include/simgrid/kernel/routing/NetZoneImpl.hpp
include/simgrid/kernel/routing/RoutedZone.hpp
include/simgrid/kernel/routing/StarZone.hpp
include/simgrid/kernel/routing/TorusZone.hpp
include/simgrid/kernel/routing/VivaldiZone.hpp
include/simgrid/kernel/routing/WifiZone.hpp
include/simgrid/modelchecker.h
include/simgrid/plugins/ProducerConsumer.hpp
include/simgrid/plugins/battery.hpp [new file with mode: 0644]
include/simgrid/plugins/chiller.hpp [new file with mode: 0644]
include/simgrid/plugins/jbod.hpp [new file with mode: 0644]
include/simgrid/plugins/ns3.hpp
include/simgrid/plugins/solar_panel.hpp [new file with mode: 0644]
include/simgrid/s4u.hpp
include/simgrid/s4u/Activity.hpp
include/simgrid/s4u/ActivitySet.hpp [new file with mode: 0644]
include/simgrid/s4u/Actor.hpp
include/simgrid/s4u/Barrier.hpp
include/simgrid/s4u/Comm.hpp
include/simgrid/s4u/ConditionVariable.hpp
include/simgrid/s4u/Disk.hpp
include/simgrid/s4u/Engine.hpp
include/simgrid/s4u/Exec.hpp
include/simgrid/s4u/Host.hpp
include/simgrid/s4u/Io.hpp
include/simgrid/s4u/Link.hpp
include/simgrid/s4u/Mailbox.hpp
include/simgrid/s4u/Mess.hpp [new file with mode: 0644]
include/simgrid/s4u/MessageQueue.hpp [new file with mode: 0644]
include/simgrid/s4u/Mutex.hpp
include/simgrid/s4u/NetZone.hpp
include/simgrid/s4u/Semaphore.hpp
include/simgrid/s4u/Task.hpp [new file with mode: 0644]
include/simgrid/s4u/VirtualMachine.hpp
include/simgrid/simix.h [deleted file]
include/simgrid/simix.hpp
include/smpi/forward.hpp
include/smpi/mpi.h
include/smpi/smpi.h
include/smpi/smpi_extended_traces.h
include/smpi/smpi_extended_traces_fortran.h
include/smpi/smpi_helpers.h
include/xbt/Extendable.hpp
include/xbt/PropertyHolder.hpp
include/xbt/automaton.h [deleted file]
include/xbt/automaton.hpp [deleted file]
include/xbt/backtrace.hpp
include/xbt/base.h
include/xbt/config.hpp
include/xbt/file.hpp
include/xbt/function_types.h
include/xbt/functional.hpp
include/xbt/log.hpp
include/xbt/misc.h
include/xbt/module.h
include/xbt/promise.hpp
include/xbt/random.hpp
include/xbt/range.hpp
include/xbt/replay.hpp
include/xbt/signal.hpp
include/xbt/string.hpp
include/xbt/sysdep.h
include/xbt/system_error.hpp
include/xbt/utility.hpp
include/xbt/virtu.h
setup.py
sonar-project.properties
src/3rd-party/xxhash.hpp [deleted file]
src/bindings/python/simgrid_python.cpp
src/dag/loaders.cpp
src/deprecated.cpp [deleted file]
src/instr/instr_interface.cpp
src/instr/instr_platform.cpp
src/instr/instr_smpi.hpp
src/internal_config.h.in
src/kernel/EngineImpl.cpp
src/kernel/EngineImpl.hpp
src/kernel/activity/ActivityImpl.cpp
src/kernel/activity/CommImpl.cpp
src/kernel/activity/CommImpl.hpp
src/kernel/activity/ConditionVariableImpl.cpp
src/kernel/activity/ConditionVariableImpl.hpp
src/kernel/activity/MailboxImpl.cpp
src/kernel/activity/MailboxImpl.hpp
src/kernel/activity/MessImpl.cpp [new file with mode: 0644]
src/kernel/activity/MessImpl.hpp [new file with mode: 0644]
src/kernel/activity/MessageQueueImpl.cpp [new file with mode: 0644]
src/kernel/activity/MessageQueueImpl.hpp [new file with mode: 0644]
src/kernel/activity/MutexImpl.cpp
src/kernel/activity/MutexImpl.hpp
src/kernel/activity/SemaphoreImpl.cpp
src/kernel/activity/SemaphoreImpl.hpp
src/kernel/actor/ActorImpl.cpp
src/kernel/actor/CommObserver.cpp
src/kernel/actor/CommObserver.hpp
src/kernel/actor/Simcall.cpp
src/kernel/actor/SimcallObserver.cpp
src/kernel/actor/SimcallObserver.hpp
src/kernel/actor/SynchroObserver.cpp
src/kernel/actor/SynchroObserver.hpp
src/kernel/context/Context.cpp
src/kernel/context/Context.hpp
src/kernel/context/ContextRaw.cpp
src/kernel/context/ContextSwapped.cpp
src/kernel/context/ContextUnix.cpp
src/kernel/lmm/System.cpp
src/kernel/lmm/System.hpp
src/kernel/lmm/bmf.cpp
src/kernel/resource/CpuImpl.cpp
src/kernel/resource/CpuImpl.hpp
src/kernel/resource/DiskImpl.cpp
src/kernel/resource/DiskImpl.hpp
src/kernel/resource/HostImpl.cpp
src/kernel/resource/HostImpl.hpp
src/kernel/resource/LinkImpl.hpp
src/kernel/resource/Resource.hpp
src/kernel/resource/StandardLinkImpl.cpp
src/kernel/resource/StandardLinkImpl.hpp
src/kernel/resource/VirtualMachineImpl.cpp
src/kernel/resource/VirtualMachineImpl.hpp
src/kernel/resource/WifiLinkImpl.cpp
src/kernel/resource/WifiLinkImpl.hpp
src/kernel/resource/models/cpu_cas01.cpp
src/kernel/resource/models/cpu_ti.cpp
src/kernel/resource/models/host_clm03.cpp
src/kernel/resource/models/host_clm03.hpp
src/kernel/resource/models/network_cm02.cpp
src/kernel/resource/models/network_ib.cpp
src/kernel/resource/models/network_ib.hpp
src/kernel/resource/models/network_ns3.cpp
src/kernel/resource/models/network_ns3.hpp
src/kernel/resource/models/ns3/ns3_simulator.cpp
src/kernel/resource/models/ns3/ns3_simulator.hpp
src/kernel/resource/models/ptask_L07.cpp
src/kernel/resource/models/ptask_L07.hpp
src/kernel/resource/profile/FutureEvtSet.cpp
src/kernel/resource/profile/Profile_test.cpp
src/kernel/routing/ClusterZone.cpp
src/kernel/routing/DijkstraZone_test.cpp
src/kernel/routing/FloydZone_test.cpp
src/kernel/routing/FullZone_test.cpp
src/kernel/routing/NetZoneImpl.cpp
src/kernel/routing/NetZone_test.hpp
src/kernel/routing/StarZone_test.cpp
src/kernel/routing/TorusZone.cpp
src/kernel/xml/platf.hpp
src/kernel/xml/platf_private.hpp
src/kernel/xml/platf_sax_cb.cpp
src/kernel/xml/sg_platf.cpp
src/mc/AddressSpace.hpp [deleted file]
src/mc/VisitedState.cpp [deleted file]
src/mc/VisitedState.hpp [deleted file]
src/mc/api/ActorState.hpp
src/mc/api/ClockVector.cpp [new file with mode: 0644]
src/mc/api/ClockVector.hpp [new file with mode: 0644]
src/mc/api/RemoteApp.cpp
src/mc/api/RemoteApp.hpp
src/mc/api/State.cpp
src/mc/api/State.hpp
src/mc/api/guide/BasicGuide.hpp [deleted file]
src/mc/api/guide/GuidedState.hpp [deleted file]
src/mc/api/strategy/BasicStrategy.hpp [new file with mode: 0644]
src/mc/api/strategy/MaxMatchComm.hpp [new file with mode: 0644]
src/mc/api/strategy/MinMatchComm.hpp [new file with mode: 0644]
src/mc/api/strategy/Strategy.hpp [new file with mode: 0644]
src/mc/api/strategy/UniformStrategy.hpp [new file with mode: 0644]
src/mc/compare.cpp [deleted file]
src/mc/explo/CommunicationDeterminismChecker.cpp
src/mc/explo/DFSExplorer.cpp
src/mc/explo/DFSExplorer.hpp
src/mc/explo/Exploration.cpp
src/mc/explo/Exploration.hpp
src/mc/explo/LivenessChecker.cpp [deleted file]
src/mc/explo/LivenessChecker.hpp [deleted file]
src/mc/explo/UdporChecker.cpp
src/mc/explo/UdporChecker.hpp
src/mc/explo/odpor/ClockVector_test.cpp [new file with mode: 0644]
src/mc/explo/odpor/Execution.cpp [new file with mode: 0644]
src/mc/explo/odpor/Execution.hpp [new file with mode: 0644]
src/mc/explo/odpor/Execution_test.cpp [new file with mode: 0644]
src/mc/explo/odpor/WakeupTree.cpp [new file with mode: 0644]
src/mc/explo/odpor/WakeupTree.hpp [new file with mode: 0644]
src/mc/explo/odpor/WakeupTreeIterator.cpp [new file with mode: 0644]
src/mc/explo/odpor/WakeupTreeIterator.hpp [new file with mode: 0644]
src/mc/explo/odpor/WakeupTree_test.cpp [new file with mode: 0644]
src/mc/explo/odpor/odpor_forward.hpp [new file with mode: 0644]
src/mc/explo/odpor/odpor_tests_private.hpp [new file with mode: 0644]
src/mc/explo/simgrid_mc.cpp
src/mc/explo/udpor/Configuration.cpp
src/mc/explo/udpor/Configuration.hpp
src/mc/explo/udpor/Configuration_test.cpp
src/mc/explo/udpor/EventSet.cpp
src/mc/explo/udpor/EventSet.hpp
src/mc/explo/udpor/EventSet_test.cpp
src/mc/explo/udpor/ExtensionSetCalculator.cpp [new file with mode: 0644]
src/mc/explo/udpor/ExtensionSetCalculator.hpp [new file with mode: 0644]
src/mc/explo/udpor/ExtensionSet_test.cpp [new file with mode: 0644]
src/mc/explo/udpor/History.hpp
src/mc/explo/udpor/Unfolding.cpp
src/mc/explo/udpor/Unfolding.hpp
src/mc/explo/udpor/UnfoldingEvent.cpp
src/mc/explo/udpor/UnfoldingEvent.hpp
src/mc/explo/udpor/UnfoldingEvent_test.cpp
src/mc/explo/udpor/Unfolding_test.cpp
src/mc/explo/udpor/maximal_subsets_iterator.cpp
src/mc/explo/udpor/maximal_subsets_iterator.hpp
src/mc/explo/udpor/udpor_forward.hpp
src/mc/explo/udpor/udpor_tests_private.hpp
src/mc/inspect/DwarfExpression.cpp [deleted file]
src/mc/inspect/DwarfExpression.hpp [deleted file]
src/mc/inspect/Frame.cpp [deleted file]
src/mc/inspect/Frame.hpp [deleted file]
src/mc/inspect/LocationList.cpp [deleted file]
src/mc/inspect/LocationList.hpp [deleted file]
src/mc/inspect/ObjectInformation.cpp [deleted file]
src/mc/inspect/ObjectInformation.hpp [deleted file]
src/mc/inspect/Type.hpp [deleted file]
src/mc/inspect/Variable.hpp [deleted file]
src/mc/inspect/mc_dwarf.cpp [deleted file]
src/mc/inspect/mc_dwarf.hpp [deleted file]
src/mc/inspect/mc_dwarf_attrnames.cpp [deleted file]
src/mc/inspect/mc_dwarf_tagnames.cpp [deleted file]
src/mc/inspect/mc_member.cpp [deleted file]
src/mc/inspect/mc_unw.cpp [deleted file]
src/mc/inspect/mc_unw.hpp [deleted file]
src/mc/inspect/mc_unw_vmread.cpp [deleted file]
src/mc/mc_base.cpp
src/mc/mc_client_api.cpp
src/mc/mc_config.cpp
src/mc/mc_config.hpp
src/mc/mc_environ.h [new file with mode: 0644]
src/mc/mc_exit.hpp
src/mc/mc_global.cpp
src/mc/mc_private.hpp
src/mc/mc_record.cpp
src/mc/mc_record.hpp
src/mc/remote/AppSide.cpp
src/mc/remote/AppSide.hpp
src/mc/remote/Channel.cpp
src/mc/remote/Channel.hpp
src/mc/remote/CheckerSide.cpp
src/mc/remote/CheckerSide.hpp
src/mc/remote/RemotePtr.hpp
src/mc/remote/mc_protocol.h
src/mc/sosp/ChunkedData.cpp [deleted file]
src/mc/sosp/ChunkedData.hpp [deleted file]
src/mc/sosp/PageStore.cpp [deleted file]
src/mc/sosp/PageStore.hpp [deleted file]
src/mc/sosp/PageStore_test.cpp [deleted file]
src/mc/sosp/Region.cpp [deleted file]
src/mc/sosp/Region.hpp [deleted file]
src/mc/sosp/RemoteProcessMemory.cpp [deleted file]
src/mc/sosp/RemoteProcessMemory.hpp [deleted file]
src/mc/sosp/Snapshot.cpp [deleted file]
src/mc/sosp/Snapshot.hpp [deleted file]
src/mc/sosp/Snapshot_test.cpp [deleted file]
src/mc/transition/Transition.cpp
src/mc/transition/Transition.hpp
src/mc/transition/TransitionActor.cpp [new file with mode: 0644]
src/mc/transition/TransitionActor.hpp [moved from src/mc/transition/TransitionActorJoin.hpp with 64% similarity]
src/mc/transition/TransitionActorJoin.cpp [deleted file]
src/mc/transition/TransitionAny.cpp
src/mc/transition/TransitionAny.hpp
src/mc/transition/TransitionComm.cpp
src/mc/transition/TransitionComm.hpp
src/mc/transition/TransitionObjectAccess.cpp
src/mc/transition/TransitionObjectAccess.hpp
src/mc/transition/TransitionRandom.cpp
src/mc/transition/TransitionRandom.hpp
src/mc/transition/TransitionSynchro.cpp
src/mc/transition/TransitionSynchro.hpp
src/plugins/battery.cpp [new file with mode: 0644]
src/plugins/chaos_monkey.cpp
src/plugins/chiller.cpp [new file with mode: 0644]
src/plugins/file_system/s4u_FileSystem.cpp
src/plugins/host_dvfs.cpp
src/plugins/host_energy.cpp
src/plugins/host_load.cpp
src/plugins/jbod.cpp [new file with mode: 0644]
src/plugins/link_energy.cpp
src/plugins/link_energy_wifi.cpp
src/plugins/link_load.cpp
src/plugins/solar_panel.cpp [new file with mode: 0644]
src/plugins/vm/dirty_page_tracking.cpp
src/s4u/s4u_Activity.cpp
src/s4u/s4u_ActivitySet.cpp [new file with mode: 0644]
src/s4u/s4u_Actor.cpp
src/s4u/s4u_Comm.cpp
src/s4u/s4u_ConditionVariable.cpp
src/s4u/s4u_Disk.cpp
src/s4u/s4u_Engine.cpp
src/s4u/s4u_Exec.cpp
src/s4u/s4u_Host.cpp
src/s4u/s4u_Io.cpp
src/s4u/s4u_Link.cpp
src/s4u/s4u_Mailbox.cpp
src/s4u/s4u_Mess.cpp [new file with mode: 0644]
src/s4u/s4u_MessageQueue.cpp [new file with mode: 0644]
src/s4u/s4u_Mutex.cpp
src/s4u/s4u_Netzone.cpp
src/s4u/s4u_Task.cpp [new file with mode: 0644]
src/s4u/s4u_VirtualMachine.cpp
src/simgrid/Exception.cpp
src/simgrid/module.cpp
src/simgrid/sg_config.cpp
src/simgrid/sg_config.hpp
src/simgrid/sg_version.cpp
src/smpi/bindings/smpi_mpi.cpp
src/smpi/bindings/smpi_pmpi.cpp
src/smpi/bindings/smpi_pmpi_comm.cpp
src/smpi/bindings/smpi_pmpi_request.cpp
src/smpi/colls/smpi_coll.cpp
src/smpi/colls/smpi_default_selector.cpp
src/smpi/include/private.hpp
src/smpi/include/smpi_actor.hpp
src/smpi/include/smpi_coll.hpp
src/smpi/include/smpi_replay.hpp
src/smpi/include/smpi_request.hpp
src/smpi/include/smpi_topo.hpp
src/smpi/internals/instr_smpi.cpp
src/smpi/internals/smpi_actor.cpp
src/smpi/internals/smpi_bench.cpp
src/smpi/internals/smpi_config.cpp
src/smpi/internals/smpi_deployment.cpp
src/smpi/internals/smpi_global.cpp
src/smpi/internals/smpi_memory.cpp
src/smpi/internals/smpi_replay.cpp
src/smpi/internals/smpi_shared.cpp
src/smpi/mpi/smpi_datatype.cpp
src/smpi/mpi/smpi_f2c.cpp
src/smpi/mpi/smpi_request.cpp
src/smpi/mpi/smpi_win.cpp
src/smpi/smpi_replay_main.cpp
src/smpi/smpirun.in
src/sthread/ObjectAccess.cpp
src/sthread/sthread.c
src/sthread/sthread.h
src/sthread/sthread_impl.cpp
src/xbt/automaton/automaton.c [deleted file]
src/xbt/automaton/automaton_lexer.yy.c [deleted file]
src/xbt/automaton/automatonparse_promela.c [deleted file]
src/xbt/automaton/parserPromela.lex [deleted file]
src/xbt/automaton/parserPromela.tab.cacc [deleted file]
src/xbt/automaton/parserPromela.tab.hacc [deleted file]
src/xbt/automaton/parserPromela.yacc [deleted file]
src/xbt/backtrace.cpp
src/xbt/config_test.cpp
src/xbt/exception.cpp
src/xbt/mallocator.c
src/xbt/mmalloc/mfree.c [deleted file]
src/xbt/mmalloc/mm.c [deleted file]
src/xbt/mmalloc/mm_interface.c [deleted file]
src/xbt/mmalloc/mm_legacy.c [deleted file]
src/xbt/mmalloc/mm_module.c [deleted file]
src/xbt/mmalloc/mmalloc.c [deleted file]
src/xbt/mmalloc/mmalloc.h [deleted file]
src/xbt/mmalloc/mmalloc.info [deleted file]
src/xbt/mmalloc/mmalloc.texi [deleted file]
src/xbt/mmalloc/mmorecore.c [deleted file]
src/xbt/mmalloc/mmprivate.h [deleted file]
src/xbt/mmalloc/mrealloc.c [deleted file]
src/xbt/mmalloc/swag.c [deleted file]
src/xbt/mmalloc/swag.h [deleted file]
src/xbt/parmap.hpp
src/xbt/utils/iter/iterator_wrapping.hpp
src/xbt/utils/iter/powerset.hpp
src/xbt/utils/iter/subsets.hpp
src/xbt/utils/iter/subsets_tests.cpp
src/xbt/utils/iter/variable_for_loop.hpp
src/xbt/xbt_os_time.c
teshsuite/mc/CMakeLists.txt
teshsuite/mc/dwarf-expression/dwarf-expression.cpp [deleted file]
teshsuite/mc/dwarf-expression/dwarf-expression.tesh [deleted file]
teshsuite/mc/dwarf/dwarf.cpp [deleted file]
teshsuite/mc/dwarf/dwarf.tesh [deleted file]
teshsuite/mc/mcmini/barber_shop_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/barber_shop_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/barber_shop_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/barber_shop_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/philosophers_mutex_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/philosophers_mutex_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/philosophers_mutex_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/philosophers_mutex_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/philosophers_semaphores_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/philosophers_semaphores_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/philosophers_semaphores_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/philosophers_semaphores_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/producer_consumer_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/producer_consumer_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/producer_consumer_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/producer_consumer_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_mutex_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_mutex_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_mutex_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_mutex_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_mutex_with_threads_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_mutex_with_threads_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphore_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphore_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphores_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphores_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphores_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphores_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphores_with_threads_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphores_with_threads_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphores_with_threads_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_semaphores_with_threads_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_threads_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_threads_ok.tesh [new file with mode: 0644]
teshsuite/mc/mutex-handling/mutex-handling.cpp
teshsuite/mc/mutex-handling/mutex-handling.tesh
teshsuite/mc/mutex-handling/without-mutex-handling.tesh
teshsuite/mc/random-bug/random-bug.cpp
teshsuite/mc/random-bug/random-bug.tesh
teshsuite/models/cm02-set-lat-bw/cm02-set-lat-bw.cpp
teshsuite/models/cm02-tcpgamma/cm02-tcpgamma.cpp
teshsuite/models/issue105/issue105.cpp
teshsuite/models/ptask-subflows/ptask-subflows.cpp
teshsuite/platforms/flatifier.tesh
teshsuite/python/platform-mix/platform-mix.py
teshsuite/s4u/CMakeLists.txt
teshsuite/s4u/activity-lifecycle/testing_comm.cpp
teshsuite/s4u/activity-lifecycle/testing_comm_direct.cpp
teshsuite/s4u/activity-lifecycle/testing_test-wait.cpp
teshsuite/s4u/actor-suspend/actor-suspend.cpp
teshsuite/s4u/basic-parsing-test/basic-parsing-test.tesh
teshsuite/s4u/comm-fault-scenarios/comm-fault-scenarios.cpp
teshsuite/s4u/dag-incomplete-simulation/dag-incomplete-simulation.cpp
teshsuite/s4u/dependencies/dependencies.cpp
teshsuite/s4u/host-on-off-actors/host-on-off-actors.cpp
teshsuite/s4u/io-stream/io-stream.cpp
teshsuite/s4u/issue71/issue71.cpp
teshsuite/s4u/monkey-masterworkers/monkey-masterworkers.cpp
teshsuite/s4u/monkey-masterworkers/monkey-masterworkers.py
teshsuite/s4u/monkey-semaphore/monkey-semaphore.cpp
teshsuite/s4u/ns3-from-src-to-itself/ns3-from-src-to-itself.tesh
teshsuite/s4u/seal-platform/seal-platform.cpp
teshsuite/s4u/seal-platform/seal-platform.tesh
teshsuite/s4u/storage_client_server/storage_client_server.cpp
teshsuite/s4u/vm-suicide/vm-suicide.cpp
teshsuite/s4u/wait-all-for/wait-all-for.cpp [deleted file]
teshsuite/s4u/wait-all-for/wait-all-for.tesh [deleted file]
teshsuite/s4u/wait-any-for/wait-any-for.cpp [deleted file]
teshsuite/s4u/wait-any-for/wait-any-for.tesh [deleted file]
teshsuite/smpi/CMakeLists.txt
teshsuite/smpi/MBI/CMakeLists.txt
teshsuite/smpi/MBI/InputHazardGenerator.py
teshsuite/smpi/MBI/MBI.py
teshsuite/smpi/MBI/MBIutils.py
teshsuite/smpi/MBI/P2PBufferingGenerator.py
teshsuite/smpi/MBI/P2PSendrecvArgGenerator.py
teshsuite/smpi/MBI/generator_utils.py
teshsuite/smpi/MBI/simgrid.py
teshsuite/smpi/coll-allreduce-with-leaks/mc-coll-allreduce-with-leaks.tesh
teshsuite/smpi/coll-allreduce/coll-allreduce-papi.tesh
teshsuite/smpi/mpich3-test/CMakeLists.txt
teshsuite/smpi/mpich3-test/attr/CMakeLists.txt
teshsuite/smpi/mpich3-test/attr/attrdelete.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/attr/testlist
teshsuite/smpi/mpich3-test/coll/CMakeLists.txt
teshsuite/smpi/mpich3-test/coll/allred_derived.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/coll/allred_float.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/coll/gatherv.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/coll/testlist
teshsuite/smpi/mpich3-test/comm/CMakeLists.txt
teshsuite/smpi/mpich3-test/comm/cmfree2.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/comm/comm_info2.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/comm/testlist
teshsuite/smpi/mpich3-test/datatype/CMakeLists.txt
teshsuite/smpi/mpich3-test/errhan/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/attr/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/coll/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/comm/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/datatype/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/ext/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/info/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/init/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/pt2pt/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/rma/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/topo/CMakeLists.txt
teshsuite/smpi/mpich3-test/f77/util/CMakeLists.txt
teshsuite/smpi/mpich3-test/f90/coll/CMakeLists.txt
teshsuite/smpi/mpich3-test/f90/datatype/CMakeLists.txt
teshsuite/smpi/mpich3-test/f90/info/CMakeLists.txt
teshsuite/smpi/mpich3-test/f90/init/CMakeLists.txt
teshsuite/smpi/mpich3-test/f90/pt2pt/CMakeLists.txt
teshsuite/smpi/mpich3-test/f90/rma/CMakeLists.txt
teshsuite/smpi/mpich3-test/f90/util/CMakeLists.txt
teshsuite/smpi/mpich3-test/group/CMakeLists.txt
teshsuite/smpi/mpich3-test/info/CMakeLists.txt
teshsuite/smpi/mpich3-test/init/CMakeLists.txt
teshsuite/smpi/mpich3-test/io/CMakeLists.txt
teshsuite/smpi/mpich3-test/perf/CMakeLists.txt
teshsuite/smpi/mpich3-test/pt2pt/CMakeLists.txt
teshsuite/smpi/mpich3-test/pt2pt/huge_dupcomm.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/pt2pt/huge_ssend.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/pt2pt/inactivereq.c
teshsuite/smpi/mpich3-test/pt2pt/isendrecv.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/pt2pt/isendrecv_replace.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/pt2pt/large_tag.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/pt2pt/multi_psend_derived.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/pt2pt/pssend.c [new file with mode: 0644]
teshsuite/smpi/mpich3-test/pt2pt/testlist
teshsuite/smpi/mpich3-test/rma/CMakeLists.txt
teshsuite/smpi/mpich3-test/topo/CMakeLists.txt
teshsuite/xbt/CMakeLists.txt
teshsuite/xbt/cmdline/cmdline.c
teshsuite/xbt/mmalloc/mmalloc_32.tesh [deleted file]
teshsuite/xbt/mmalloc/mmalloc_64.tesh [deleted file]
teshsuite/xbt/mmalloc/mmalloc_test.cpp [deleted file]
teshsuite/xbt/signals/signals.cpp
tools/CMakeLists.txt
tools/address_sanitizer.supp
tools/cmake/CTestConfig.cmake
tools/cmake/DefinePackages.cmake
tools/cmake/Distrib.cmake
tools/cmake/Flags.cmake
tools/cmake/MaintainerMode.cmake
tools/cmake/MakeLib.cmake
tools/cmake/Modules/FindGraphviz.cmake
tools/cmake/Modules/FindLibdw.cmake [deleted file]
tools/cmake/Modules/FindLibelf.cmake [deleted file]
tools/cmake/Modules/FindLibunwind.cmake [deleted file]
tools/cmake/Modules/FindNS3.cmake
tools/cmake/Modules/FindPAPI.cmake
tools/cmake/Option.cmake
tools/cmake/Tests.cmake
tools/cmake/scripts/my_valgrind.pl
tools/cmake/test_prog/prog_ns3.cpp [new file with mode: 0644]
tools/docker/Dockerfile.build-deps
tools/docker/Dockerfile.stable
tools/docker/Dockerfile.tuto-mc
tools/docker/Dockerfile.unstable
tools/generate-dwarf-functions [deleted file]
tools/graphicator/graphicator.cpp
tools/jenkins/Coverage.sh
tools/jenkins/DynamicAnalysis.sh
tools/jenkins/Flags.sh
tools/jenkins/Sanitizers.sh
tools/jenkins/build.sh
tools/jenkins/ci-bigdft.sh
tools/jenkins/ci-starpu.sh
tools/jenkins/gfortran-simgrid.rc
tools/jenkins/project_description.sh
tools/simgrid-monkey
tools/simgrid.supp
tools/simgrid_convert_TI_traces.py
tools/simgrid_update_xml.pl
tools/smpi/generate_smpi_defines.pl
tools/tesh/IO-orders.tesh
tools/tesh/catch-signal.tesh
tools/tesh/catch-timeout-output.tesh
tools/tesh/set-output-sort.tesh
tools/tesh/tesh.py

index 2839cb3..b505615 100644 (file)
@@ -19,5 +19,5 @@ jobs:
           name: Configure, build and test da stuff
           command: |
             mkdir _build && cd _build
-            cmake -Denable_documentation=OFF -Denable_coverage=ON -Denable_model-checking=OFF -Denable_compile_optimizations=OFF -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=OFF -Denable_compile_warnings=ON ..
+            cmake -Denable_documentation=OFF -Denable_coverage=OFF -Denable_model-checking=OFF -Denable_compile_optimizations=OFF -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=OFF -Denable_compile_warnings=ON ..
             make -j4 tests && ctest -j4 --output-on-failure
index 78ac347..f519b1e 100644 (file)
@@ -12,7 +12,7 @@ jobs:
     container: simgrid/unstable
 
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - name: Build and test BatSim
         run: |
           set -e
index 581e733..bb44643 100644 (file)
@@ -14,7 +14,7 @@ jobs:
       options: --user 0
 
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - name: Build and test BigDFT
         run: |
           set -e
index 6b63238..fbca937 100644 (file)
@@ -12,7 +12,7 @@ jobs:
     container: simgrid/unstable
 
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - name: Build and test StarPU
         run: |
           set -e
index 224b03e..1a580b4 100644 (file)
@@ -12,7 +12,7 @@ jobs:
     container: simgrid/unstable
 
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - name: Build and test WRENCH
         run: |
           set -e
index 68a4ec3..c0a0ea8 100644 (file)
@@ -24,7 +24,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       # Login against a Docker registry except on PR
       # https://github.com/docker/login-action
@@ -65,7 +65,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       # Login against a Docker registry except on PR
       # https://github.com/docker/login-action
@@ -104,7 +104,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       # Login against a Docker registry except on PR
       # https://github.com/docker/login-action
index 17f6084..5471cea 100644 (file)
@@ -20,7 +20,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       # Login against a Docker registry except on PR
       # https://github.com/docker/login-action
@@ -59,7 +59,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       # Login against a Docker registry except on PR
       # https://github.com/docker/login-action
index 3bb8225..eb6bc03 100644 (file)
@@ -22,7 +22,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Init options
         run: |
           echo "CC=${{ matrix.config.cc }}"   >> $GITHUB_ENV
@@ -39,8 +39,8 @@ jobs:
           mkdir build ; cd build
           cmake -GNinja -Denable_debug=ON -Denable_documentation=OFF -Denable_coverage=OFF \
                 -Denable_compile_optimizations=ON -Denable_compile_warnings=ON \
-                -Denable_model-checking=OFF -Denable_smpi_MBI_testsuite=OFF \
-                -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=ON \
+                -Denable_model-checking=OFF -Denable_testsuite_smpi_MBI=OFF \
+                -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=ON \
                 -DCMAKE_DISABLE_SOURCE_CHANGES=ON  -DLTO_EXTRA_FLAG="auto" ..
           ninja tests
           ctest --output-on-failure -j$(nproc)
@@ -51,7 +51,7 @@ jobs:
       - name: Create the success Message
         if: ${{ success() }}
         run: |
-          ver=$(grep set.SIMGRID_VERSION_MINOR CMakeLists.txt|sed 's/[^"]*"//'|sed 's/".*$//') echo "{\"attachments\": [{\"color\": \"#00FF00\", \"text\":\"Simgrid built successfully on ${{ matrix.config.name }}! ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} \"}]}" > mattermost.json
+          ver=$(grep set.SIMGRID_VERSION_MINOR CMakeLists.txt|sed 's/[^"]*"//'|sed 's/".*$//') echo "{\"attachments\": [{\"color\": \"#00FF00\", \"text\":\"SimGrid built successfully on ${{ matrix.config.name }}! ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} \"}]}" > mattermost.json
       - uses: komarnitskyi/action-mattermost-notification@v0.1.2-beta
         if: ${{ always() }}
         env:
@@ -68,17 +68,16 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: build
         run: |
-          sudo apt-get update && sudo apt-get install ninja-build libboost-dev libboost-context-dev pybind11-dev
-          sudo apt-get install libunwind-dev libdw-dev libelf-dev libevent-dev
+          sudo apt-get update && sudo apt-get install ninja-build libboost-dev libboost-context-dev pybind11-dev libevent-dev
           mkdir build ; cd build
           cmake -GNinja -Denable_debug=ON -Denable_documentation=OFF -Denable_coverage=OFF \
                 -Denable_compile_optimizations=ON -Denable_compile_warnings=ON \
-                -Denable_model-checking=ON -Denable_smpi_MBI_testsuite=OFF \
-                -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=OFF \
+                -Denable_model-checking=ON -Denable_testsuite_smpi_MBI=OFF \
+                -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=OFF \
                 -Denable_ns3=OFF \
                 -DCMAKE_DISABLE_SOURCE_CHANGES=ON  -DLTO_EXTRA_FLAG="auto" ..
           ninja tests
index c4b7ab7..97d5571 100644 (file)
@@ -104,6 +104,10 @@ tags
 callgrind.out.*
 ### Examples and traces
 *.exe
+examples/c/activityset-testany/c-activityset-testany
+examples/c/activityset-waitall/c-activityset-waitall
+examples/c/activityset-waitallfor/c-activityset-waitallfor
+examples/c/activityset-waitany/c-activityset-waitany
 examples/c/actor-create/c-actor-create
 examples/c/actor-daemon/c-actor-daemon
 examples/c/actor-exiting/c-actor-exiting
@@ -143,6 +147,10 @@ examples/c/platform-failures/c-platform-failures
 examples/c/platform-properties/c-platform-properties
 examples/c/plugin-host-load/c-plugin-host-load
 examples/c/synchro-semaphore/c-synchro-semaphore
+examples/cpp/activityset-testany/s4u-activityset-testany
+examples/cpp/activityset-waitall/s4u-activityset-waitall
+examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor
+examples/cpp/activityset-waitany/s4u-activityset-waitany
 examples/cpp/actor-create/s4u-actor-create
 examples/cpp/actor-daemon/s4u-actor-daemon
 examples/cpp/actor-exiting/s4u-actor-exiting
@@ -175,8 +183,11 @@ examples/cpp/comm-waitall/s4u-comm-waitall
 examples/cpp/comm-waitany/s4u-comm-waitany
 examples/cpp/comm-waituntil/s4u-comm-waituntil
 examples/cpp/dag-comm/s4u-dag-comm
+examples/cpp/dag-tuto/s4u-dag-tuto
 examples/cpp/dag-failure/s4u-dag-failure
 examples/cpp/dag-from-dax/s4u-dag-from-dax
+examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple
+examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple
 examples/cpp/dag-from-dot/s4u-dag-from-dot
 examples/cpp/dag-io/s4u-dag-io
 examples/cpp/dag-scheduling/s4u-dag-scheduling
@@ -239,6 +250,13 @@ examples/cpp/synchro-condition-variable/s4u-synchro-condition-variable
 examples/cpp/synchro-condition-variable-waituntil/s4u-synchro-condition-variable-waituntil
 examples/cpp/synchro-mutex/s4u-synchro-mutex
 examples/cpp/synchro-semaphore/s4u-synchro-semaphore
+examples/cpp/task-dispatch/s4u-task-dispatch
+examples/cpp/task-io/s4u-task-io
+examples/cpp/task-microservice/s4u-task-microservice
+examples/cpp/task-parallelism/s4u-task-parallelism
+examples/cpp/task-simple/s4u-task-simple
+examples/cpp/task-storm/s4u-task-storm
+examples/cpp/task-switch-host/s4u-task-switch-host
 examples/cpp/torus-multicpu/
 examples/cpp/trace-categories/s4u-trace-categories
 examples/cpp/trace-host-user-variables/s4u-trace-host-user-variables
index 53a6261..bbf969b 100644 (file)
@@ -11,7 +11,7 @@ ctest-debug:
   script:
   - apt-get --allow-releaseinfo-change update
   - apt install -y binutils xsltproc
-  - cmake -Denable_model-checking=OFF -Denable_documentation=OFF -Denable_coverage=OFF -Denable_compile_optimizations=ON -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=ON -Denable_compile_warnings=ON -DLTO_EXTRA_FLAG="auto" .
+  - cmake -Denable_model-checking=OFF -Denable_documentation=OFF -Denable_coverage=OFF -Denable_compile_optimizations=ON -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=ON -Denable_testsuite_McMini=ON -Denable_compile_warnings=ON -DLTO_EXTRA_FLAG="auto" .
   - make -j$(nproc) VERBOSE=1 all tests
   - ctest -T Test -j$(nproc) --output-on-failure
   - xsltproc ./tools/jenkins/ctest2junit.xsl Testing/"$( head -n 1 < Testing/TAG )"/Test.xml > CTestResults.xml
@@ -30,8 +30,8 @@ ctest-modelchecking:
   - stable
   script:
   - apt-get --allow-releaseinfo-change update
-  - apt install -y binutils xsltproc
-  - cmake -Denable_model-checking=ON -Denable_documentation=OFF -Denable_coverage=OFF -Denable_compile_optimizations=ON -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=OFF -Denable_compile_warnings=ON -DLTO_EXTRA_FLAG="auto" .
+  - apt install -y binutils xsltproc clang
+  - cmake -Denable_model-checking=ON -Denable_documentation=OFF -Denable_coverage=OFF -Denable_compile_optimizations=ON -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=OFF -Denable_testsuite_McMini=OFF -Denable_compile_warnings=ON -DLTO_EXTRA_FLAG="auto" -DCMAKE_C_COMPILER=/usr/bin/clang  -DCMAKE_CXX_COMPILER=/usr/bin/clang++ .
   - make -j$(nproc) VERBOSE=1 all tests
   - ctest -T Test -j$(nproc) --output-on-failure
   - xsltproc ./tools/jenkins/ctest2junit.xsl Testing/"$( head -n 1 < Testing/TAG )"/Test.xml > CTestResults.xml
@@ -44,6 +44,15 @@ ctest-modelchecking:
     expire_in: 1 week
     when: always
 
+ctest-distcheck:
+  stage: build
+  only:
+  - merge_requests
+  script:
+  - apt-get --allow-releaseinfo-change update
+  - apt install -y binutils
+  - cmake .
+  - make distcheck-configure
 
 release:
   stage: build
@@ -77,12 +86,13 @@ pip:
 pages:
   stage: deploy
   script:
-  - pip3 install --requirement docs/requirements.txt
+  - apt install -y python3-breathe python3-sphinx python3-sphinx-rtd-theme python3-sphinx-copybutton python3-sphinx-tabs
+ # - pip3 install --requirement docs/requirements.txt # Forbidden in Debian:12
   - cd docs
   - LC_ALL=C.UTF-8 ./Build.sh
   - mv build/html ../public
   # - The CSS contains a reference to a font or something, not something we gonna fix on our side
-#not installed   - linkchecker --ignore-url='.*\.css$' ../public
+# not installed   - linkchecker --ignore-url='.*\.css$' ../public
   # From time to time, we should check external links with the
   # following, but it has a lot of false positive
   # - linkchecker --ignore-url='.*\.css$' --check-extern ../public
index 5efced4..2e99416 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -77,6 +77,7 @@ Arnaud Giersch <arnaud.giersch@univ-fcomte.fr> <arnaud.giersch@iut-bm.univ-fcomt
 Julien Gossa <julien.gossa@unistra.fr> <gossa@unistra.fr>
 Adrien Gougeon <adrien.gougeon@inria.fr>
 Adrien Gougeon <adrien.gougeon@inria.fr> <adrien.gougeon@ens-rennes.fr>
+Alexander Grund <git@grundis.de>
 Loic Guegan <manzerbredes@mailbox.org> <manzerberdes@gmx.com>
 Marion Guthmuller <marion.guthmuller@inria.fr> <marion.guthmuller@loria.fr>
 Ahmed Harbaoui <amad206@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
@@ -153,5 +154,5 @@ Pedro Velho <pedro.velho@gmail.com> <velho@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
 Pedro Velho <pedro.velho@gmail.com> <velho@mohave.(none)>
 Flavien Vernier <vernier@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
 Matthieu Volat <matthieu.volat@univ-lyon1.fr> <mazhe@alkumuna.eu>
-Steven Whatelse <stevenwhatelse@hotmail.fr>
+Steven Quinito Masnada <stevenwhatelse@hotmail.fr>
 Chidambar Zinnoury <illogict@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
diff --git a/AUTHORS b/AUTHORS
index 5e867f9..c8ce721 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,4 +1,4 @@
-Simgrid Core Team
+SimGrid Core Team
 _________________
 
 SimGrid is a joint project. Its main authors are (alphabetic order):
index 773ca48..410d1dd 100755 (executable)
@@ -15,8 +15,9 @@ if [ ! -e Makefile ] && [ ! -e build.ninja ]; then
   fi
 fi
 
-target=tests
+target=examples
 ncores=$(grep -c processor /proc/cpuinfo)
+halfcores=$(expr $ncores / 2 + 1)
 
 install_path=$(sed -n 's/^CMAKE_INSTALL_PREFIX:PATH=//p' CMakeCache.txt)
 if [ -e ${install_path} ] && [ -d ${install_path} ] && [ -x ${install_path} ] && [ -w ${install_path} ] ; then
@@ -32,7 +33,8 @@ fi
 (
   echo "install_path: ${install_path}"
   echo "Target: ${target}"
-  echo "Cores: ${ncores}"
-  (nice ${builder} -j${ncores} ${target} tests || make ${target} tests) && nice ctest -j${ncores} --output-on-failure ; date
+  echo "Cores to build: ${ncores}"
+  echo "Cores to test: ${halfcores}"
+  (nice ${builder} -j${ncores} ${target} tests || ${builder} ${target} tests) && nice ctest -j${halfcores} --output-on-failure ; date
 ) 2>&1 | tee BuildSimGrid.sh.log
 
index 4611a4f..6889a12 100644 (file)
@@ -1,7 +1,7 @@
 # Build the version number
 
 set(SIMGRID_VERSION_MAJOR "3")
-set(SIMGRID_VERSION_MINOR "32")
+set(SIMGRID_VERSION_MINOR "35")
 set(SIMGRID_VERSION_PATCH "1") # odd => git branch; even => stable release or released snapshot
 
 if(${SIMGRID_VERSION_PATCH} EQUAL "0")
@@ -35,12 +35,8 @@ include(GNUInstallDirs)
 #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
 #     Check for the compiler        #
 #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
-##
-## Check the C/C++ standard that we need
-##   See also tools/cmake/Flags.cmake that sets our paranoid warning flags
-INCLUDE(CheckCCompilerFlag)
-CHECK_C_COMPILER_FLAG(-fstack-cleaner HAVE_C_STACK_CLEANER)
 
+INCLUDE(CheckCCompilerFlag)
 ## Request full debugging flags
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3")
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3")
@@ -77,7 +73,7 @@ if ((NOT DEFINED enable_smpi) OR enable_smpi)
   # configuration where it was saved as smpiff
   unset(CMAKE_Fortran_COMPILER)
 
-  SET(SMPI_FORTRAN 0)
+  SET(SMPI_FORTRAN OFF)
   if(enable_fortran)
     enable_language(Fortran OPTIONAL)
   endif()
@@ -106,7 +102,7 @@ if ((NOT DEFINED enable_smpi) OR enable_smpi)
     ## Request debugging flags for Fortran too
     set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g")
 
-    set(SMPI_FORTRAN 1)
+    set(SMPI_FORTRAN ON)
   endif(CMAKE_Fortran_COMPILER)
 
 endif()
@@ -128,7 +124,7 @@ if(NOT PERL_FOUND)
   message(FATAL_ERROR "Please install Perl to compile SimGrid.")
 endif()
 
-# tesh.py needs python 3 (or the module python-subprocess32 on python2.8+)
+# tesh.py needs python 3
 find_package(Python3 COMPONENTS Interpreter)
 if(NOT Python3_Interpreter_FOUND)
   message(FATAL_ERROR "Please install Python (version 3 or higher) to compile SimGrid.")
@@ -195,21 +191,21 @@ include(CheckIncludeFiles)
 include(CheckLibraryExists)
 include(CheckSymbolExists)
 
-set(HAVE_GRAPHVIZ 0)
+set(HAVE_GRAPHVIZ OFF)
 if(minimal-bindings)
   message(STATUS "Don't even look for graphviz, as we build minimal binding libraries.")
 else()
   include(FindGraphviz)
 endif()
 
-set(SIMGRID_HAVE_NS3 0)
+set(SIMGRID_HAVE_NS3 OFF)
 if(enable_ns3)
   include(FindNS3)
   if (SIMGRID_HAVE_NS3)
     if (NOT NS3_VERSION EQUAL "3-dev" AND NS3_VERSION VERSION_LESS "3.28")
       message(FATAL_ERROR "SimGrid needs ns-3 in version 3.28 or higher. Please upgrade or disable that cmake option.")
     endif()
-    set(SIMGRID_HAVE_NS3 1)
+    set(SIMGRID_HAVE_NS3 ON)
     set(SIMGRID_DEP "${SIMGRID_DEP} ${NS3_LIBRARIES}")
   else()
     message(FATAL_ERROR "Cannot find ns-3. Please install it (apt-get install ns3 libns3-dev) or disable that cmake option")
@@ -217,19 +213,24 @@ if(enable_ns3)
 endif()
 
 ### Check for Eigen library
-set(SIMGRID_HAVE_EIGEN3 0)
-find_package (Eigen3 3.3 CONFIG
-              HINTS ${EIGEN3_HINT})
-if (Eigen3_FOUND)
-  set(SIMGRID_HAVE_EIGEN3 1)
-  message(STATUS "Found Eigen3: ${EIGEN3_INCLUDE_DIR}")
-  include_directories(${EIGEN3_INCLUDE_DIR})
-  if ("3.3.4" VERSION_EQUAL EIGEN3_VERSION_STRING AND CMAKE_COMPILER_IS_GNUCC)
-    message(STATUS "Avoid build error of Eigen3 v3.3.4 using -Wno-error=int-in-bool-context")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=int-in-bool-context")
+if ((NOT DEFINED EIGEN3_HINT) OR (NOT EIGEN3_HINT STRLESS_EQUAL "OFF"))
+  set(SIMGRID_HAVE_EIGEN3 OFF)
+  find_package (Eigen3 3.3 CONFIG
+                HINTS ${EIGEN3_HINT})
+  if (Eigen3_FOUND)
+    set(SIMGRID_HAVE_EIGEN3 ON)
+    message(STATUS "Found Eigen3: ${EIGEN3_INCLUDE_DIR}")
+    include_directories(${EIGEN3_INCLUDE_DIR})
+    if ("3.3.4" VERSION_EQUAL EIGEN3_VERSION_STRING AND CMAKE_COMPILER_IS_GNUCC)
+      message(STATUS "Avoid build error of Eigen3 v3.3.4 using -Wno-error=int-in-bool-context")
+      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=int-in-bool-context")
+    endif()
+  else()
+    message(STATUS "Disabling model BMF because Eigen3 was not found. If it's installed, use EIGEN3_HINT to hint cmake about the location of Eigen3Config.cmake")
   endif()
+  mark_as_advanced(Eigen3_DIR)
 else()
-  message(STATUS "Disabling model BMF because Eigen3 was not found. If it's installed, use EIGEN3_HINT to hint cmake about the location of Eigen3Config.cmake")
+  message(STATUS "Disabling Eigen3 as requested by the user (EIGEN3_HINT is set to 'OFF')")
 endif()
 
 # Check for our JSON dependency
@@ -246,14 +247,16 @@ if (nlohmann_json_FOUND)
   endif()
   message(STATUS "Found nlohmann_json: ${NLOHMANN_JSON_INCLUDE_DIR}")
 endif()
+mark_as_advanced(nlohmann_json_DIR)
 
-set(HAVE_PAPI 0)
+set(HAVE_PAPI OFF)
 if(enable_smpi_papi)
   include(FindPAPI)
   if (NOT HAVE_PAPI)
     message(FATAL_ERROR "Cannot find PAPI. Please install it (apt-get install papi-tools libpapi-dev) or disable PAPI bindings.")
   endif()
 endif()
+mark_as_advanced(PAPI_PREFIX)
 
 # But we do need the core of Boost
 # cmake before 3.13.1 does not know about stacktrace components. Fix it.
@@ -291,10 +294,10 @@ set(_Boost_STACKTRACE_ADDR2LINE_HEADERS "boost/stacktrace.hpp")
 
       if(Boost_CONTEXT_FOUND)
         message (STATUS "  context: found. Activating Boost contexts.")
-        set(HAVE_BOOST_CONTEXTS 1)
+        set(HAVE_BOOST_CONTEXTS ON)
       else()
         message (STATUS "  context: MISSING. Install libboost-context-dev for this optional feature.")
-        set(HAVE_BOOST_CONTEXTS 0)
+        set(HAVE_BOOST_CONTEXTS OFF)
       endif()
     endif()
   else()
@@ -310,6 +313,10 @@ set(_Boost_STACKTRACE_ADDR2LINE_HEADERS "boost/stacktrace.hpp")
       endif()
     endif()
   endif()
+mark_as_advanced(Boost_CONTEXT_LIBRARY_RELEASE)
+mark_as_advanced(Boost_INCLUDE_DIR)
+mark_as_advanced(Boost_STACKTRACE_ADDR2LINE_LIB)
+mark_as_advanced(Boost_STACKTRACE_BACKTRACE_LIB)
 
 # Checks for header libraries functions.
 CHECK_LIBRARY_EXISTS(rt      clock_gettime           "" HAVE_POSIX_GETTIME)
@@ -334,7 +341,6 @@ if(NOT HAVE_SYSCONF)
   message(FATAL_ERROR "Cannot build without sysconf.")
 endif()
 CHECK_FUNCTION_EXISTS(process_vm_readv HAVE_PROCESS_VM_READV)
-CHECK_FUNCTION_EXISTS(mmap HAVE_MMAP)
 CHECK_FUNCTION_EXISTS(mremap HAVE_MREMAP)
 
 CHECK_SYMBOL_EXISTS(vasprintf stdio.h HAVE_VASPRINTF)
@@ -347,61 +353,33 @@ else()
   set(SG_HAVE_SENDFILE 0)
 endif()
 
-if(enable_model-checking AND NOT "${CMAKE_SYSTEM}" MATCHES "Linux|FreeBSD")
-  message(FATAL_ERROR "Support for model-checking has not been enabled on ${CMAKE_SYSTEM}. Please use a Linux docker to use the model checker.")
-endif()
-
-if(enable_model-checking AND minimal-bindings)
-  message(FATAL_ERROR "Compile-time option 'minimal-bindings' cannot be enabled with 'model-checking'")
-endif()
-
-if(HAVE_MMAP)
-  SET(HAVE_MMALLOC 1)
-else()
-  SET(HAVE_MMALLOC 0)
-  if(enable_model-checking)
-    message(STATUS "Warning: support for model-checking has been disabled because you are missing either mmap or __thread.")
-  endif()
-  SET(enable_model-checking 0)
-endif()
-
 if(enable_mallocators)
   SET(SIMGRID_HAVE_MALLOCATOR 1)
 else()
   SET(SIMGRID_HAVE_MALLOCATOR 0)
 endif()
 
+SET(SIMGRID_HAVE_MC OFF)
+
 if(enable_model-checking)
-  include(FindLibunwind)
-  if(HAVE_LIBUNWIND)
-    SET(SIMGRID_DEP "${SIMGRID_DEP} ${LIBUNWIND_LIBRARIES}")
+  find_package(Libevent)
+  if(Libevent_FOUND)
+    message(STATUS "Found libevent. The stateless model-checking can be enabled.")
+    include_directories(${LIBEVENT_INCLUDE_DIR})
+    set(SIMGRID_DEP "${SIMGRID_DEP} ${LIBEVENT_LIBRARIES}")
+    SET(SIMGRID_HAVE_MC ON)
   else()
-    message(FATAL_ERROR "Please install libunwind-dev libdw-dev libelf-dev libevent-dev if you want to compile the SimGrid model checker.")
+    message(STATUS "libevent not found. Please install libevent-dev to enable the SimGrid model checker.")
   endif()
-  find_package(Libdw REQUIRED)
-  find_package(Libelf REQUIRED)
-  find_package(Libevent REQUIRED)
-  include_directories(${LIBDW_INCLUDE_DIR} ${LIBELF_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR})
-  set(SIMGRID_DEP "${SIMGRID_DEP} ${LIBEVENT_LIBRARIES} ${LIBELF_LIBRARIES} ${LIBDW_LIBRARIES}")
-  set(SIMGRID_HAVE_MC 1)
-  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)
-endif()
-mark_as_advanced(PATH_LIBDW_H)
-mark_as_advanced(PATH_LIBDW_LIB)
-
-if (enable_model-checking AND enable_ns3)
-  message(WARNING "Activating both model-checking and ns-3 bindings is considered experimental.")
+  mark_as_advanced(LIBEVENT_LIBRARY)
+  mark_as_advanced(LIBEVENT_THREADS_LIBRARY)
 endif()
 
 if(enable_smpi)
-  SET(HAVE_SMPI 1)
-  SET(HAVE_PRIVATIZATION 1)
+  SET(HAVE_SMPI ON)
+  SET(HAVE_PRIVATIZATION ON)
 else()
-  SET(HAVE_SMPI 0)
+  SET(HAVE_SMPI OFF)
 endif()
 
 #--------------------------------------------------------------------------------------------------
@@ -464,7 +442,7 @@ else()
   endif()
 endif()
 # If the test ran well, remove the test binary
-file(REMOVE test_stackgrowth)
+file(REMOVE ${CMAKE_BINARY_DIR}/test_stackgrowth)
 #--------------------------------------------------------------------------------------------------
 
 ###############
@@ -744,6 +722,10 @@ SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
 add_custom_target(tests    COMMENT "Recompiling the tests")
 add_custom_target(tests-mc COMMENT "Recompiling the MC tests and tools.")
 add_dependencies(tests tests-mc)
+add_custom_target(tests-ns3 COMMENT "Recompiling the ns3 tests and tools.")
+add_dependencies(tests tests-ns3)
+add_custom_target(examples COMMENT "Recompiling all examples")
+add_dependencies(examples tests)
 
 ### Build some Maintainer files
 include(${CMAKE_HOME_DIRECTORY}/tools/cmake/MaintainerMode.cmake)
@@ -783,11 +765,6 @@ endif()
 
 option(enable_python "Whether the Python bindings are activated." ${default_enable_python}) # ON by default if dependencies are met
 
-if("${CMAKE_SYSTEM}" MATCHES "FreeBSD" AND enable_model-checking AND enable_python)
-  message(WARNING "FreeBSD + Model-Checking + Python = too much for now. Disabling the Python bindings.")
-  set(enable_python FALSE)
-endif()
-
 if(enable_python)
   if(NOT Python3_Development_FOUND)
     message(FATAL_ERROR "Please install the development components of Python (python3-dev on Debian) to build the Python bindings (or disable that option).")
@@ -918,32 +895,34 @@ endif()
 if(SIMGRID_HAVE_EIGEN3)
   message("        Eigen3 library ..............: ${EIGEN3_VERSION_STRING} in ${EIGEN3_INCLUDE_DIR}")
 else()
-  message("        Eigen3 library ..............: not found (EIGEN3_HINT='${EIGEN3_HINT}').")
+  message("        Eigen3 library ..............: not found (EIGEN3_HINT='${EIGEN3_HINT}')")
 endif()
 if(SIMGRID_HAVE_JSON)
-  message("        JSON library.................: ${nlohmann_json_VERSION} in ${NLOHMANN_JSON_INCLUDE_DIR}")
+  message("        JSON library ................: ${nlohmann_json_VERSION} in ${NLOHMANN_JSON_INCLUDE_DIR}")
 else()
-  message("        JSON library.................: not found (nlohmann_json_HINT='${nlohmann_json_HINT}')")
+  message("        JSON library ................: not found (nlohmann_json_HINT='${nlohmann_json_HINT}')")
 endif()
 message("        Compile Smpi ................: ${HAVE_SMPI}")
 message("          Smpi fortran ..............: ${SMPI_FORTRAN}")
-message("          MPICH3 testsuite ..........: ${enable_smpi_MPICH3_testsuite}")
-message("          MBI testsuite .............: ${enable_smpi_MBI_testsuite}")
+message("          MPICH3 testsuite ..........: ${enable_testsuite_smpi_MPICH3}")
+message("          MBI testsuite .............: ${enable_testsuite_smpi_MBI}")
 message("          Privatization .............: ${HAVE_PRIVATIZATION}")
-message("          PAPI support...............: ${HAVE_PAPI}")
+message("          PAPI support ..............: ${HAVE_PAPI}")
 message("        Compile Boost.Context support: ${HAVE_BOOST_CONTEXTS}")
 message("")
-message("        Maintainer mode .............: ${enable_maintainer_mode}")
-message("        Documentation................: ${enable_documentation}")
 message("        Model checking ..............: ${SIMGRID_HAVE_MC}")
+message("          MBI testsuite .............: ${enable_testsuite_smpi_MBI}")
+message("          McMini testsuite ..........: ${enable_testsuite_McMini}")
+message("")
+message("        Maintainer mode .............: ${enable_maintainer_mode}")
+message("        Documentation ...............: ${enable_documentation}")
 message("        Graphviz mode ...............: ${HAVE_GRAPHVIZ}")
 message("        Mallocators .................: ${enable_mallocators}")
 message("")
-message("        Simgrid dependencies ........: ${SIMGRID_DEP}")
+message("        SimGrid dependencies ........: ${SIMGRID_DEP}")
 message("")
 
 execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/Testing/Notes/)
 file(WRITE ${PROJECT_BINARY_DIR}/Testing/Notes/Build  "GIT version : ${GIT_VERSION}\n")
 file(APPEND ${PROJECT_BINARY_DIR}/Testing/Notes/Build "Release     : simgrid-${release_version}\n")
 
-INCLUDE(Dart)
diff --git a/COPYING b/COPYING
index f4b1b6d..7a85266 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -11,13 +11,6 @@ Copyright: 1999, Mark Martinec <mark.martinec@ijs.si.
 License: Artistic
 Comment: Heavily adapted by the SimGrid team but remains under the original license
 
-Files: src/xbt/mmalloc/*
-Copyright:
-  Copyright (C) 1991, 1992 Free Software Foundation, Inc.
-  Copyright (C) 2003-2023. The SimGrid team.
-License: LGPL-2.1-only
-Comment: these files used to be part of gdb, but were removed there
-
 Files:
  teshsuite/smpi/mpich3-test/*
 Copyright:
@@ -173,16 +166,9 @@ Copyright: 1997, Rolf Rabenseifner. Computing Center University of Stuttgart
 License: other-reduce-rab
  The usage of this software is free, but this header must not be removed.
 
-Files: src/xbt/automaton/parserPromela.tab.cacc
-Copyright:
- Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
- Copyright (C) 2003-2023. The SimGrid team.
-License: GPL-3+ and LGPL-2.1-only
-Comment: Generated with the Bison processor generator (which is GPL-3+) using SimGrid configuration files (that are LGPL-2.1-only)
-
 Files: src/3rd-party/catch.hpp
 Copyright:
 Copyright (c) 2022 Two Blue Cubes Ltd.
+ Copyright (c) 2022 Two Blue Cubes Ltd.
 License: BSL-1.0
 
 Files: teshsuite/smpi/MBI/*
@@ -191,12 +177,6 @@ Copyright:
 Comment: The MBI.py script was written for SimGrid while the other files are kept in sync with the MBI source tree.
 License: GPL-3
 
-Files: src/3rd-party/xxhash.hpp
-Copyright:
-  Copyright (C) 2012-2018, Yann Collet.
-  Copyright (C) 2017-2018, Piotr Pliszka.
-License: BSD 2-Clause
-
 License: BSL-1.0
  Permission is hereby granted, free of charge, to any person or organization
  obtaining a copy of the software and accompanying documentation covered by
index 41bc62f..d41a80e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
-SimGrid (3.32.1) not released yet (target december 22)
+SimGrid (3.35.1) not released (target: Feb 24)
+
+
+----------------------------------------------------------------------------
+
+SimGrid (3.35) November 23. 2023
+
+The "Thanks Giving up stateful model-checking" release. Stateless model checking remains.
+
+S4U:
+ - New class ActivitySet to ease wait_any()/test_any()/wait_all()
+   - Deprecate {Comm,Io,Exec}::{wait_any,wait_all,test_any} and friends
+ - Simplify a bit the declaration of multi-zoned platforms from C++
+   - New function NetZone::add_route(host1, host2, links) when you don't need gateways
+   - Also add a variant with s4u::Link, when you don't want to specify the directions
+     on symmetric routes.
+   - Zone's gateways can now be controlled directly.
+   - Add NetZone::add_route(zone1, zone2, links) specifying the route between zones
+ - Introduce a Mailbox::get_async() with no payload parameter. You can use the new
+   Comm::get_payload() once the communication is over to retrieve the payload.
+ - Implement recursive mutexes. Simply pass true to the constructor to get one.
+ - Simplify the expression of horizontal scaling of Tasks.
+   - Each Task now consists of a dispatcher, a collector and one or more instances.
+   - The parallelism degree of each of these can be set.
+   - Several examples have been added or modified accordingly.
+   - Update s4u::create_DAG_from_json() to support wfformat 1.4.
+ - Introduce a new MessageQueue abstraction and associated Mess simulated object.
+   The behavior of a MessageQueue is similar to that of a Mailbox, but intended for
+   control messages that do not incur any simulated cost. Information is automagically
+   transported over thin air between producer and consumer. See examples/cpp/mess-wait
+ - New function: Mutex::get_owner()
+
+S4U plugins:
+ - New: Add a JBOD (just a bunch of disks) concept. It's a sort of host with many disks.
+ - Revamp the battery plugin: rewrite completely the API, for a better usability.
+   The examples were updated accordingly.
+   The battery can now act as a simple connector (see battery-connector example).
+ - Revamp of the photovoltaic plugin: now called SolarPanel and complete rewrite of the API
+ - Add chiller plugin: enable the management of chillers consuming electrical energy
+   to compensate heat generated by hosts.
+ - Add a battery-chiller-solar example combining several plugins to evaluate the amount
+   of brown energy (from the electrical grid) and green energy (from the solar panel)
+   during a given computation.
+
+SMPI:
+ - New SMPI_app_instance_join(): wait for the completion of a started MPI instance
+ - MPI_UNIVERSE_SIZE now initialized to the total amount of hosts in the platform
+ - Memory usage due to SMPI for non-MPI actors greatly reduced.
+ - New implemented calls: MPI_Isendrecv, MPI_Isendrecv_replace
+
+sthread:
+ - Allow to use on valgrind-observed or gdb-observed processes.
+ - Install sthread on user's disk.
+ - Implement recursive pthreads.
+ - Implement pthread_barrier and pthread_cond (but conditional are not supported by the MC yet).
+ - Add some McMini codes to test sthread further (controlled with enable_testsuite_McMini).
+
+Model checking:
+ - Remove stateful model-checking. This was not used, not really working, and very hard to fix.
+   Liveness properties cannot be verified anymore.
+ - More informative backtraces on assertion failure.
+ - Fix dependency bugs for mutex and other transitions
+ - Fix some reversible_race definitions, and also the rest of ODPOR.
+
+Python:
+ - Make the host_load plugin available from Python. See examples/python/plugin-host-load
+ - Mailbox::get_async() does not return a pair anymore. Use comm.get_payload() instead.
+ - Comm::waitall/waitany/testany() are gone. Please use ActivitySet() instead.
+ - Comm::waitallfor() is gone too. Its semantic was unclear on timeout anyway.
+ - Io::waitany() and waitanyfor() are gone. Please use ActivitySet() instead.
+ - Do not export the values of enums. So you need to write e.g. SharingPolicy.LINEAR
+   while it should have been possible to write LINEAR alone before. This is the advised
+   behavior for modern C++ code.
+
+C API:
+ - Introduce sg_activity_set_t and deprecate wait_all/wait_any/test_any for
+   Exec, Io and Comm.
+
+Kernel:
+ - optimize an internal data structure (replace boost::circular_buffer_space_optimized by
+   std::deque to store pending and unmatched Comms in Mailboxes). It is actually a revert
+   to what was used a few years back. The boost structure had a lower memory footprint than
+   deques, but it appeared that their "space_optimized" character was generating a huge lot
+   of refcount changes on the stored Comms.
+
+General:
+ - Fix errors with ns-3 v3.36+
+ - Many other small bug fixes, in particular in MC and sthread.
+
+----------------------------------------------------------------------------
+
+SimGrid (3.34) June 26. 2023
+
+  Save the planet, skip a release: 3.33 was due 6 months ago, so skip directly to 3.34.
 
 General:
+ - SimGrid now requires a compiler with C++17 support for public headers too.
+   Sibling projects should upgrade their FindSimGrid.cmake
  - Remove the MSG API: its EOL was scheduled for 2020.
  - Remove the Java bindings: they were limited to the MSG interface.
  - On Windows, you now need to install WSL2 as the native builds are now disabled.
    It was not really working anyway.
  - Support for 32bits architecture is not tested anymore on our CI infrastructure.
    It may break in the future, but we think that nobody's using SimGrid on 32 bits.
- - Remove the surf module. It was replaced by the kernel/models module, and that 
+ - Remove the surf module. It was replaced by the kernel/models module, and that
    refactoring took almost 10 years to properly complete.
 
 S4U:
@@ -15,12 +110,32 @@ S4U:
    Comm::set_payload_size() to change the size of the simulated data.
  - New function: Engine::flatify_platform(), to get a fully detailed vision of the
    configured platform.
+ - New Task abstraction: They are designed to represent dataflows, i.e, graphs of repeatable Activities.
+   See the examples under examples/cpp/task-* and the associated documentation.
  - Full simDAG integration: Activity::start() actually starts only when all dependencies
-   are fullfiled. If it cannot be started right away, it will start as soon as it becomes
+   are fulfilled. If it cannot be started right away, it will start as soon as it becomes
    possible.
+ - Allow to set a concurrency limit on disks and hosts, as it was already the case for links.
+ - Rename Link::get_usage() to Link::get_load() for consistency with Host::
+ - Every signal now come with a static version that is invoked for every object of that class,
+   and an instance version that is invoked for this specific object only. For example,
+   s4u::Actor::on_suspend_cb() adds a callback that is invoked for the suspend of any actor while
+   s4u::Actor::on_this_suspend_cb() adds a callback for this specific actor only.
+ - Activity::on_suspended_cb() is renamed to Activity::on_suspend_cb(), and fired right before the suspend.
+ - Activity::on_resumed_cb() is renamed to Activity::on_resume_cb(), and fired right before the resume.
+ - Resource::on_state_change_cb() is renamed to Resource::on_onoff_cb() to distinguish from the
+   Activity::on_state_change_cb() that is related to the activity state machine, not on/off.
+ - Activity signals (veto, suspend, resume, completion) are now specialized by activity class.
+   That is, callbacks registered in Exec::on_suspend_cb will not be fired for Comms nor Ios.
+
+New S4U plugins:
+ - Battery: Enable the management of batteries on hosts.
+   See the examples under examples/cpp/battery-* and the documentation in the Plugins page.
+ - Photovoltaic: Enable the management of photovoltaic panels on hosts.
+   See the examples under examples/cpp/photovoltaic-* and the documentation in the Plugins page.
 
 Kernel:
- - optimize an internal datastructure (use a set instead of a list for ongoing activities),
+ - optimize an internal data structure (use a set instead of a list for ongoing activities),
    leading to a potentially big performance gain, in particular with many detached comms.
 
 MPI:
@@ -30,7 +145,7 @@ MPI:
 
 Models:
  - Write the section of the manual about models, at least.
- - WiFi: the total capacity of a link depends on the amout of flows on that link.
+ - WiFi: the total capacity of a link depends on the amount of flows on that link.
    - Use the nonlinear callback feature of LMM to reflect this.
    - Calibration values can be changed to match different MCS configurations
    - See the example teshsuite/models/wifi_usage_decay/wifi_usage_decay.cpp
@@ -53,8 +168,14 @@ sthread:
    It requires code annotation, as shown in examples/sthread/stdobject/stdobject.cpp
 
 Model checking:
+ - Stateless model-checking is now usable on any system, including Mac OSX and ARM processors.
+ - The stateless aspects of the MC are now enabled by default in all SimGrid builds.
+   Liveness and stateful aspects are still controlled by the enabling_model-checking
+   configuration option.
+ - Introducing ODPOR and SDPOR reduction strategies
+ - Introducing guiding heuristics, trying to find bugs faster than DFS in reduced state space.
  - Synchronize the MBI tests with upstream.
- - Show the full actor bactraces when replaying a MC trace (with model-check/replay)
+ - Show the full actor backtraces when replaying a MC trace (with model-check/replay)
    and the status of all actors on deadlocks in MC mode.
 
 XBT:
@@ -62,6 +183,7 @@ XBT:
    Please use simgrid::s4u::Engine::get_cmdline() instead.
 
 Documentation:
+ - New tutorial on simulating DAGs.
  - New section in the user guide on the provided performance models.
  - New section presenting some technical good practices for (potential) contributors.
  - Add a section on errors and exceptions to the API documentation.
@@ -216,7 +338,7 @@ MSG:
 New plugin: the Chaos Monkey (killing actors at any time)
  - Along with the new simgrid-monkey script, it tests whether your simulation
    resists resource failures at any possible timestamp in your simulation.
- - It is mostly intended to test the simgrid core in extreme conditions,
+ - It is mostly intended to test the SimGrid core in extreme conditions,
    but some users may find it interesting too.
 
 Models:
@@ -654,7 +776,7 @@ The Release release (the French lockdown was eased today).
 
 Important user-visible changes:
  - SimGrid now requires a compiler with C++14 support.
-   Sibling projects should upgrade their FindSimgrid.cmake
+   Sibling projects should upgrade their FindSimGrid.cmake
  - Surf precision default value is now 1e-9, instead of 1e-5. This was changed as
    several users had difficulties to understand issues when using high bandwidth or
    small latency events. The new value was already the default for SMPI and
@@ -980,7 +1102,7 @@ General:
  - Network model 'NS3' was renamed into 'ns-3'.
 
 Python:
- - Simgrid can now hopefully be installed with pip.
+ - SimGrid can now hopefully be installed with pip.
 
 S4U:
  - wait_any can now be used for asynchronous executions too.
@@ -2028,7 +2150,7 @@ SimGrid (3.12) stable; urgency=low
    - InfiniBand network model added: Based on the works of Jerome Vienne
      http://mescal.imag.fr/membres/jean-marc.vincent/index.html/PhD/Vienne.pdf
    - When smpi/display_timing is set, also display global simulation time and application times
-   - Have smpirun, smpicc and friends display the simgrid git hash version on --git-version
+   - Have smpirun, smpicc and friends display the SimGrid git hash version on --git-version
  * Collective communications
    - SMP-aware algorithms are now dynamically handled. An internal communicator is created for each node, and an external one to handle communications between "leaders" of each node
    - MVAPICH2 (1.9) collective algorithms selector: normal and SMP algorithms are handled, and selection logic is based on the one used on TACC's Stampede cluster (https://www.tacc.utexas.edu/stampede/).
@@ -2769,8 +2891,8 @@ SimGrid (3.6.2) stable; urgency=low
 
  Portability
  * Create an installer for windows with nsis (amd64 and win32)
-   - Add an hello world project to illustrate simgrid project creation.
-   - Embed libpcre into the Simgrid installer to avoid
+   - Add an hello world project to illustrate SimGrid project creation.
+   - Embed libpcre into the SimGrid installer to avoid
      its compilation burden
  * The raw execution contexts should work on Apple now
  * Port to Windows 64 bits
@@ -2803,7 +2925,7 @@ SimGrid (3.6.1) stable; urgency=low
 SimGrid-java (3.6) unstable; urgency=low
 
  * Initial release.
- * Split of every thing from simgrid v3.5 into a separate package.
+ * Split of every thing from SimGrid v3.5 into a separate package.
 
  -- 2011-10-05 Da SimGrid team <simgrid-devel@lists.gforge.inria.fr>
 
@@ -3317,7 +3439,7 @@ SimGrid (3.4) stable; urgency=low
   * Greatly improved our cdash/ctest interactions
     Check http://cdash.inria.fr/CDash/index.php?project=Simgrid
   * Added memory checking tests with valgrind; lot of memleak fixing.
-    This may be the first release of simgrid with so few memory issues
+    This may be the first release of SimGrid with so few memory issues
   * Added code coverage tests.
     Our coverage is still improvable, but at least we see it on cdash.
 
@@ -3623,7 +3745,7 @@ SimGrid (3.3.2) stable; urgency=low
 
  Timing report of this version:
   This version seem to be more than 5% faster than 3.3.1 (on linux
-    64bits with contextes). The gain is less than expected, we are
+    64bits with contexts). The gain is less than expected, we are
     investigating this for next release.
 
  -- Da SimGrid team <simgrid-devel@lists.gforge.inria.fr> Wed, 19 Aug 2009 17:07:12 +0200
@@ -3716,7 +3838,7 @@ SimGrid (3.3.1) stable; urgency=low
     - Linux(debian)/amd64/context
     - Linux(debian)/amd64/pthreads
     These targets fail about 1/10 of times on gras/pmm, but we believe
-      that this is because of the test, not because of simgrid.
+      that this is because of the test, not because of SimGrid.
     amok/saturate_sg fails even more rarely, and the test may not be
       the problem.
 
@@ -3773,7 +3895,7 @@ SimGrid (3.3) stable; urgency=high
     is really less memory-demanding, which should allow you to use
     larger files in SimGrid [AL].
 
-  * Inform valgrind about our contextes, so that it becomes usable
+  * Inform valgrind about our contexts, so that it becomes usable
     with the default (and more effecient) version of SimGrid
     [contributed by Sékou Diakite, many thanks]
 
index 209d709..eec2f92 100644 (file)
 #      (code to use with SimGrid v3.19+)
 #    #endif
 #
-#  Since SimGrid header files require C++14, so we set CMAKE_CXX_STANDARD to 14.
+#  Since SimGrid header files require C++17, so we set CMAKE_CXX_STANDARD to 17.
 #    Change this variable in your own file if you need a later standard.
 
+# DEVELOPPERS OF MPI PROGRAMS USING SIMGRID
+#   You should use smpi_c_target() on the targets that are intended to run in SMPI.
+#   ${SMPIRUN} is correctly set if it's installed.
+#
+#   Example:
+#     add_executable(roundtrip roundtrip.c)
+#     smpi_c_target(roundtrip)
+#
+#     enable_testing()
+#     add_test(NAME Roundtrip
+#              COMMAND ${SMPIRUN} -platform ${CMAKE_SOURCE_DIR}/../cluster_backbone.xml -np 2 ./roundtrip)
+
 #
 # IMPROVING THIS FILE
 # -------------------
@@ -48,9 +60,9 @@
 #    https://cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file
 #    https://github.com/boostcon/cppnow_presentations_2017/blob/master/05-19-2017_friday/effective_cmake__daniel_pfeifer__cppnow_05-19-2017.pdf
 
-cmake_minimum_required(VERSION 2.8.12)
+cmake_minimum_required(VERSION 3.5)
 
-set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 find_path(SimGrid_INCLUDE_DIR
@@ -103,32 +115,40 @@ find_package_handle_standard_args(SimGrid
 )
 
 if (SimGrid_FOUND)
+
+  find_program(SMPIRUN smpirun
+               HINTS ${SimGrid_PATH}/bin /opt/simgrid/bin)
+
+  MACRO(smpi_c_target NAME)
+    target_compile_options(${NAME} PUBLIC "-include;smpi/smpi_helpers.h;-fPIC;-shared;-Wl,-z,defs")
+    target_link_options(${NAME} PUBLIC "-fPIC;-shared;-Wl,-z,defs;-lm")
+    target_link_libraries(${NAME} PUBLIC ${SimGrid_LIBRARY})
+    target_include_directories(${NAME} PUBLIC "${SimGrid_INCLUDE_DIR};${SimGrid_INCLUDE_DIR}/smpi")
+  ENDMACRO()
+
   add_library(SimGrid::SimGrid SHARED IMPORTED)
   set_target_properties(SimGrid::SimGrid PROPERTIES
     INTERFACE_SYSTEM_INCLUDE_DIRECTORIES ${SimGrid_INCLUDE_DIR}
     INTERFACE_COMPILE_FEATURES cxx_alias_templates
     IMPORTED_LOCATION ${SimGrid_LIBRARY}
   )
-  # We need C++14, so check for it just in case the user removed it since compiling SimGrid
+  # We need C++17, so check for it just in case the user removed it since compiling SimGrid
   if (NOT CMAKE_VERSION VERSION_LESS 3.8)
-    # 3.8+ allows us to simply require C++14 (or higher)
-    set_property(TARGET SimGrid::SimGrid PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_14)
-  elseif (NOT CMAKE_VERSION VERSION_LESS 3.1)
-    # 3.1+ is similar but for certain features. We pick just one
-    set_property(TARGET SimGrid::SimGrid PROPERTY INTERFACE_COMPILE_FEATURES cxx_attribute_deprecated)
+    # 3.8+ allows us to simply require C++17 (or higher)
+    set_property(TARGET SimGrid::SimGrid PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
   else ()
-    # Old CMake can't do much. Just check the CXX_FLAGS and inform the user when a C++14 feature does not work
+    # Old CMake can't do much. Just check the CXX_FLAGS and inform the user when a C++17 feature does not work
     include(CheckCXXSourceCompiles)
     set(CMAKE_REQUIRED_FLAGS "${CMAKE_CXX_FLAGS}")
     check_cxx_source_compiles("
-#if __cplusplus < 201402L
+#if __cplusplus < 201703L
 #error
 #else
 int main(){}
 #endif
-" _SIMGRID_CXX14_ENABLED)
-    if (NOT _SIMGRID_CXX14_ENABLED)
-        message(WARNING "C++14 is required to use SimGrid. Enable it with e.g. -std=c++14")
+" _SIMGRID_CXX17_ENABLED)
+    if (NOT _SIMGRID_CXX17_ENABLED)
+        message(WARNING "C++17 is required to use SimGrid. Enable it with e.g. -std=c++17")
     endif ()
     unset(_SIMGRID_CXX14_ENABLED CACHE)
   endif ()
index 9ae7ec1..a7c5668 100644 (file)
@@ -1,6 +1,14 @@
 # This file lists the content of the python source package
 # Prepared in tools/cmake/Distrib.cmake
 
+include examples/c/activityset-testany/activityset-testany.c
+include examples/c/activityset-testany/activityset-testany.tesh
+include examples/c/activityset-waitall/activityset-waitall.c
+include examples/c/activityset-waitall/activityset-waitall.tesh
+include examples/c/activityset-waitallfor/activityset-waitallfor.c
+include examples/c/activityset-waitallfor/activityset-waitallfor.tesh
+include examples/c/activityset-waitany/activityset-waitany.c
+include examples/c/activityset-waitany/activityset-waitany.tesh
 include examples/c/actor-create/actor-create.c
 include examples/c/actor-create/actor-create.tesh
 include examples/c/actor-create/actor-create_d.xml
@@ -65,12 +73,6 @@ include examples/c/comm-wait/comm-wait2_d.xml
 include examples/c/comm-wait/comm-wait3_d.xml
 include examples/c/comm-wait/comm-wait4_d.xml
 include examples/c/comm-wait/comm-wait_d.xml
-include examples/c/comm-waitall/comm-waitall.c
-include examples/c/comm-waitall/comm-waitall.tesh
-include examples/c/comm-waitall/comm-waitall_d.xml
-include examples/c/comm-waitany/comm-waitany.c
-include examples/c/comm-waitany/comm-waitany.tesh
-include examples/c/comm-waitany/comm-waitany_d.xml
 include examples/c/dht-kademlia/answer.c
 include examples/c/dht-kademlia/answer.h
 include examples/c/dht-kademlia/common.h
@@ -102,8 +104,6 @@ include examples/c/exec-dvfs/exec-dvfs.c
 include examples/c/exec-dvfs/exec-dvfs.tesh
 include examples/c/exec-remote/exec-remote.c
 include examples/c/exec-remote/exec-remote.tesh
-include examples/c/exec-waitany/exec-waitany.c
-include examples/c/exec-waitany/exec-waitany.tesh
 include examples/c/io-disk-raw/io-disk-raw.c
 include examples/c/io-disk-raw/io-disk-raw.tesh
 include examples/c/io-file-remote/io-file-remote.c
@@ -120,10 +120,14 @@ include examples/c/plugin-host-load/plugin-host-load.c
 include examples/c/plugin-host-load/plugin-host-load.tesh
 include examples/c/synchro-semaphore/synchro-semaphore.c
 include examples/c/synchro-semaphore/synchro-semaphore.tesh
-include examples/cpp/activity-testany/s4u-activity-testany.cpp
-include examples/cpp/activity-testany/s4u-activity-testany.tesh
-include examples/cpp/activity-waitany/s4u-activity-waitany.cpp
-include examples/cpp/activity-waitany/s4u-activity-waitany.tesh
+include examples/cpp/activityset-testany/s4u-activityset-testany.cpp
+include examples/cpp/activityset-testany/s4u-activityset-testany.tesh
+include examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp
+include examples/cpp/activityset-waitall/s4u-activityset-waitall.tesh
+include examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp
+include examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.tesh
+include examples/cpp/activityset-waitany/s4u-activityset-waitany.cpp
+include examples/cpp/activityset-waitany/s4u-activityset-waitany.tesh
 include examples/cpp/actor-create/s4u-actor-create.cpp
 include examples/cpp/actor-create/s4u-actor-create.tesh
 include examples/cpp/actor-create/s4u-actor-create_d.xml
@@ -162,6 +166,19 @@ include examples/cpp/app-masterworkers/s4u-app-masterworkers.tesh
 include examples/cpp/app-masterworkers/s4u-app-masterworkers_d.xml
 include examples/cpp/app-token-ring/s4u-app-token-ring.cpp
 include examples/cpp/app-token-ring/s4u-app-token-ring.tesh
+include examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp
+include examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh
+include examples/cpp/battery-connector/s4u-battery-connector.cpp
+include examples/cpp/battery-connector/s4u-battery-connector.tesh
+include examples/cpp/battery-degradation/plot_battery_degradation.py
+include examples/cpp/battery-degradation/s4u-battery-degradation.cpp
+include examples/cpp/battery-degradation/s4u-battery-degradation.tesh
+include examples/cpp/battery-energy/s4u-battery-energy.cpp
+include examples/cpp/battery-energy/s4u-battery-energy.tesh
+include examples/cpp/battery-simple/s4u-battery-simple.cpp
+include examples/cpp/battery-simple/s4u-battery-simple.tesh
+include examples/cpp/chiller-simple/s4u-chiller-simple.cpp
+include examples/cpp/chiller-simple/s4u-chiller-simple.tesh
 include examples/cpp/cloud-capping/s4u-cloud-capping.cpp
 include examples/cpp/cloud-capping/s4u-cloud-capping.tesh
 include examples/cpp/cloud-migration/s4u-cloud-migration.cpp
@@ -183,30 +200,33 @@ include examples/cpp/comm-ready/s4u-comm-ready.cpp
 include examples/cpp/comm-ready/s4u-comm-ready.tesh
 include examples/cpp/comm-suspend/s4u-comm-suspend.cpp
 include examples/cpp/comm-suspend/s4u-comm-suspend.tesh
-include examples/cpp/comm-testany/s4u-comm-testany.cpp
-include examples/cpp/comm-testany/s4u-comm-testany.tesh
 include examples/cpp/comm-throttling/s4u-comm-throttling.cpp
 include examples/cpp/comm-throttling/s4u-comm-throttling.tesh
 include examples/cpp/comm-wait/s4u-comm-wait.cpp
 include examples/cpp/comm-wait/s4u-comm-wait.tesh
-include examples/cpp/comm-waitall/s4u-comm-waitall.cpp
-include examples/cpp/comm-waitall/s4u-comm-waitall.tesh
-include examples/cpp/comm-waitany/s4u-comm-waitany.cpp
-include examples/cpp/comm-waitany/s4u-comm-waitany.tesh
 include examples/cpp/comm-waituntil/s4u-comm-waituntil.cpp
 include examples/cpp/comm-waituntil/s4u-comm-waituntil.tesh
 include examples/cpp/dag-comm/s4u-dag-comm.cpp
 include examples/cpp/dag-comm/s4u-dag-comm.tesh
 include examples/cpp/dag-failure/s4u-dag-failure.cpp
 include examples/cpp/dag-failure/s4u-dag-failure.tesh
+include examples/cpp/dag-from-dax-simple/dag.xml
+include examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.cpp
+include examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.tesh
 include examples/cpp/dag-from-dax/s4u-dag-from-dax.cpp
 include examples/cpp/dag-from-dax/s4u-dag-from-dax.tesh
 include examples/cpp/dag-from-dax/simple_dax_with_cycle.xml
 include examples/cpp/dag-from-dax/smalldax.xml
+include examples/cpp/dag-from-dot-simple/dag.dot
+include examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.cpp
+include examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.tesh
 include examples/cpp/dag-from-dot/dag.dot
 include examples/cpp/dag-from-dot/dag_with_cycle.dot
 include examples/cpp/dag-from-dot/s4u-dag-from-dot.cpp
 include examples/cpp/dag-from-dot/s4u-dag-from-dot.tesh
+include examples/cpp/dag-from-json-simple/dag.json
+include examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.cpp
+include examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.tesh
 include examples/cpp/dag-io/s4u-dag-io.cpp
 include examples/cpp/dag-io/s4u-dag-io.tesh
 include examples/cpp/dag-scheduling/Montage_25.xml
@@ -214,6 +234,8 @@ include examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
 include examples/cpp/dag-scheduling/s4u-dag-scheduling.tesh
 include examples/cpp/dag-simple/s4u-dag-simple.cpp
 include examples/cpp/dag-simple/s4u-dag-simple.tesh
+include examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+include examples/cpp/dag-tuto/s4u-dag-tuto.tesh
 include examples/cpp/dht-chord/s4u-dht-chord-node.cpp
 include examples/cpp/dht-chord/s4u-dht-chord.cpp
 include examples/cpp/dht-chord/s4u-dht-chord.hpp
@@ -273,8 +295,6 @@ include examples/cpp/exec-threads/s4u-exec-threads.cpp
 include examples/cpp/exec-threads/s4u-exec-threads.tesh
 include examples/cpp/exec-unassigned/s4u-exec-unassigned.cpp
 include examples/cpp/exec-unassigned/s4u-exec-unassigned.tesh
-include examples/cpp/exec-waitany/s4u-exec-waitany.cpp
-include examples/cpp/exec-waitany/s4u-exec-waitany.tesh
 include examples/cpp/exec-waitfor/s4u-exec-waitfor.cpp
 include examples/cpp/exec-waitfor/s4u-exec-waitfor.tesh
 include examples/cpp/io-async/s4u-io-async.cpp
@@ -294,16 +314,8 @@ include examples/cpp/io-priority/s4u-io-priority.cpp
 include examples/cpp/io-priority/s4u-io-priority.tesh
 include examples/cpp/maestro-set/s4u-maestro-set.cpp
 include examples/cpp/maestro-set/s4u-maestro-set.tesh
-include examples/cpp/mc-bugged1-liveness/promela_bugged1_liveness
-include examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner
-include examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh
-include examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp
-include examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh
 include examples/cpp/mc-bugged1/s4u-mc-bugged1.cpp
 include examples/cpp/mc-bugged1/s4u-mc-bugged1.tesh
-include examples/cpp/mc-bugged2-liveness/promela_bugged2_liveness
-include examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.cpp
-include examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.tesh
 include examples/cpp/mc-bugged2/s4u-mc-bugged2.cpp
 include examples/cpp/mc-bugged2/s4u-mc-bugged2.tesh
 include examples/cpp/mc-centralized-mutex/s4u-mc-centralized-mutex.cpp
@@ -311,9 +323,10 @@ include examples/cpp/mc-centralized-mutex/s4u-mc-centralized-mutex.tesh
 include examples/cpp/mc-electric-fence/s4u-mc-electric-fence.cpp
 include examples/cpp/mc-electric-fence/s4u-mc-electric-fence.tesh
 include examples/cpp/mc-failing-assert/s4u-mc-failing-assert-nodpor.tesh
-include examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh
 include examples/cpp/mc-failing-assert/s4u-mc-failing-assert.cpp
 include examples/cpp/mc-failing-assert/s4u-mc-failing-assert.tesh
+include examples/cpp/mess-wait/s4u-mess-wait.cpp
+include examples/cpp/mess-wait/s4u-mess-wait.tesh
 include examples/cpp/network-factors/s4u-network-factors.cpp
 include examples/cpp/network-factors/s4u-network-factors.tesh
 include examples/cpp/network-nonlinear/s4u-network-nonlinear.cpp
@@ -327,8 +340,9 @@ include examples/cpp/network-ns3/crosstraffic_d.xml
 include examples/cpp/network-ns3/dogbone_d.xml
 include examples/cpp/network-ns3/one_cluster_d.xml
 include examples/cpp/network-ns3/onelink_d.xml
+include examples/cpp/network-ns3/s4u-network-ns3-notime.tesh
+include examples/cpp/network-ns3/s4u-network-ns3-timed.tesh
 include examples/cpp/network-ns3/s4u-network-ns3.cpp
-include examples/cpp/network-ns3/s4u-network-ns3.tesh
 include examples/cpp/network-wifi/s4u-network-wifi.cpp
 include examples/cpp/network-wifi/s4u-network-wifi.tesh
 include examples/cpp/platform-comm-serialize/s4u-platform-comm-serialize.cpp
@@ -342,6 +356,8 @@ include examples/cpp/platform-properties/s4u-platform-properties.cpp
 include examples/cpp/platform-properties/s4u-platform-properties.tesh
 include examples/cpp/plugin-host-load/s4u-plugin-host-load.cpp
 include examples/cpp/plugin-host-load/s4u-plugin-host-load.tesh
+include examples/cpp/plugin-jbod/s4u-plugin-jbod.cpp
+include examples/cpp/plugin-jbod/s4u-plugin-jbod.tesh
 include examples/cpp/plugin-link-load/s4u-plugin-link-load.cpp
 include examples/cpp/plugin-link-load/s4u-plugin-link-load.tesh
 include examples/cpp/plugin-prodcons/s4u-plugin-prodcons.cpp
@@ -359,6 +375,8 @@ include examples/cpp/replay-io/s4u-replay-io.txt
 include examples/cpp/replay-io/s4u-replay-io_d.xml
 include examples/cpp/routing-get-clusters/s4u-routing-get-clusters.cpp
 include examples/cpp/routing-get-clusters/s4u-routing-get-clusters.tesh
+include examples/cpp/solar-panel-simple/s4u-solar-panel-simple.cpp
+include examples/cpp/solar-panel-simple/s4u-solar-panel-simple.tesh
 include examples/cpp/synchro-barrier/s4u-mc-synchro-barrier.tesh
 include examples/cpp/synchro-barrier/s4u-synchro-barrier.cpp
 include examples/cpp/synchro-barrier/s4u-synchro-barrier.tesh
@@ -372,6 +390,22 @@ include examples/cpp/synchro-mutex/s4u-synchro-mutex.tesh
 include examples/cpp/synchro-semaphore/s4u-mc-synchro-semaphore.tesh
 include examples/cpp/synchro-semaphore/s4u-synchro-semaphore.cpp
 include examples/cpp/synchro-semaphore/s4u-synchro-semaphore.tesh
+include examples/cpp/task-dispatch/s4u-task-dispatch.cpp
+include examples/cpp/task-dispatch/s4u-task-dispatch.tesh
+include examples/cpp/task-io/s4u-task-io.cpp
+include examples/cpp/task-io/s4u-task-io.tesh
+include examples/cpp/task-microservice/s4u-task-microservice.cpp
+include examples/cpp/task-microservice/s4u-task-microservice.tesh
+include examples/cpp/task-parallelism/s4u-task-parallelism.cpp
+include examples/cpp/task-parallelism/s4u-task-parallelism.tesh
+include examples/cpp/task-simple/s4u-task-simple.cpp
+include examples/cpp/task-simple/s4u-task-simple.tesh
+include examples/cpp/task-storm/s4u-task-storm.cpp
+include examples/cpp/task-storm/s4u-task-storm.tesh
+include examples/cpp/task-switch-host/s4u-task-switch-host.cpp
+include examples/cpp/task-switch-host/s4u-task-switch-host.tesh
+include examples/cpp/task-variable-load/s4u-task-variable-load.cpp
+include examples/cpp/task-variable-load/s4u-task-variable-load.tesh
 include examples/cpp/trace-categories/s4u-trace-categories.cpp
 include examples/cpp/trace-categories/s4u-trace-categories.tesh
 include examples/cpp/trace-host-user-variables/s4u-trace-host-user-variables.cpp
@@ -386,6 +420,14 @@ include examples/cpp/trace-process-migration/s4u-trace-process-migration.cpp
 include examples/cpp/trace-process-migration/s4u-trace-process-migration.tesh
 include examples/cpp/trace-route-user-variables/s4u-trace-route-user-variables.cpp
 include examples/cpp/trace-route-user-variables/s4u-trace-route-user-variables.tesh
+include examples/python/activityset-testany/activityset-testany.py
+include examples/python/activityset-testany/activityset-testany.tesh
+include examples/python/activityset-waitall/activityset-waitall.py
+include examples/python/activityset-waitall/activityset-waitall.tesh
+include examples/python/activityset-waitallfor/activityset-waitallfor.py
+include examples/python/activityset-waitallfor/activityset-waitallfor.tesh
+include examples/python/activityset-waitany/activityset-waitany.py
+include examples/python/activityset-waitany/activityset-waitany.tesh
 include examples/python/actor-create/actor-create.py
 include examples/python/actor-create/actor-create.tesh
 include examples/python/actor-daemon/actor-daemon.py
@@ -416,18 +458,10 @@ include examples/python/comm-ready/comm-ready.py
 include examples/python/comm-ready/comm-ready.tesh
 include examples/python/comm-suspend/comm-suspend.py
 include examples/python/comm-suspend/comm-suspend.tesh
-include examples/python/comm-testany/comm-testany.py
-include examples/python/comm-testany/comm-testany.tesh
 include examples/python/comm-throttling/comm-throttling.py
 include examples/python/comm-throttling/comm-throttling.tesh
 include examples/python/comm-wait/comm-wait.py
 include examples/python/comm-wait/comm-wait.tesh
-include examples/python/comm-waitall/comm-waitall.py
-include examples/python/comm-waitall/comm-waitall.tesh
-include examples/python/comm-waitallfor/comm-waitallfor.py
-include examples/python/comm-waitallfor/comm-waitallfor.tesh
-include examples/python/comm-waitany/comm-waitany.py
-include examples/python/comm-waitany/comm-waitany.tesh
 include examples/python/comm-waituntil/comm-waituntil.py
 include examples/python/comm-waituntil/comm-waituntil.tesh
 include examples/python/exec-async/exec-async.py
@@ -452,12 +486,22 @@ include examples/python/platform-failures/platform-failures.py
 include examples/python/platform-failures/platform-failures.tesh
 include examples/python/platform-profile/platform-profile.py
 include examples/python/platform-profile/platform-profile.tesh
+include examples/python/plugin-host-load/plugin-host-load.py
+include examples/python/plugin-host-load/plugin-host-load.tesh
 include examples/python/synchro-barrier/synchro-barrier.py
 include examples/python/synchro-barrier/synchro-barrier.tesh
 include examples/python/synchro-mutex/synchro-mutex.py
 include examples/python/synchro-mutex/synchro-mutex.tesh
 include examples/python/synchro-semaphore/synchro-semaphore.py
 include examples/python/synchro-semaphore/synchro-semaphore.tesh
+include examples/python/task-io/task-io.py
+include examples/python/task-io/task-io.tesh
+include examples/python/task-simple/task-simple.py
+include examples/python/task-simple/task-simple.tesh
+include examples/python/task-switch-host/task-switch-host.py
+include examples/python/task-switch-host/task-switch-host.tesh
+include examples/python/task-variable-load/task-variable-load.py
+include examples/python/task-variable-load/task-variable-load.tesh
 include examples/smpi/NAS/DGraph.c
 include examples/smpi/NAS/DGraph.h
 include examples/smpi/NAS/README.install
@@ -478,22 +522,14 @@ include examples/smpi/gemm/gemm.c
 include examples/smpi/gemm/gemm.tesh
 include examples/smpi/hostfile
 include examples/smpi/mc/bugged1.c
-include examples/smpi/mc/bugged1_liveness.c
 include examples/smpi/mc/bugged2.c
 include examples/smpi/mc/hostfile_bugged1
-include examples/smpi/mc/hostfile_bugged1_liveness
 include examples/smpi/mc/hostfile_bugged2
 include examples/smpi/mc/hostfile_mutual_exclusion
-include examples/smpi/mc/hostfile_non_termination
 include examples/smpi/mc/hostfile_only_send_deterministic
 include examples/smpi/mc/mutual_exclusion.c
-include examples/smpi/mc/non_termination1.c
-include examples/smpi/mc/non_termination2.c
-include examples/smpi/mc/non_termination3.c
-include examples/smpi/mc/non_termination4.c
 include examples/smpi/mc/only_send_deterministic.c
 include examples/smpi/mc/only_send_deterministic.tesh
-include examples/smpi/mc/promela_bugged1_liveness
 include examples/smpi/mc/sendsend.c
 include examples/smpi/mc/sendsend.tesh
 include examples/smpi/replay/actions0.txt
@@ -595,9 +631,12 @@ include examples/smpi/trace_call_location/trace_call_location.c
 include examples/smpi/trace_call_location/trace_call_location.tesh
 include examples/smpi/trace_simple/trace_simple.c
 include examples/smpi/trace_simple/trace_simple.tesh
+include examples/sthread/pthread-mc-mutex-recursive.tesh
 include examples/sthread/pthread-mc-mutex-simple.tesh
 include examples/sthread/pthread-mc-mutex-simpledeadlock.tesh
 include examples/sthread/pthread-mc-producer-consumer.tesh
+include examples/sthread/pthread-mutex-recursive.c
+include examples/sthread/pthread-mutex-recursive.tesh
 include examples/sthread/pthread-mutex-simple.c
 include examples/sthread/pthread-mutex-simple.tesh
 include examples/sthread/pthread-mutex-simpledeadlock.c
@@ -615,10 +654,50 @@ include teshsuite/kernel/context-defaults/factory_thread.tesh
 include teshsuite/kernel/context-defaults/factory_ucontext.tesh
 include teshsuite/kernel/stack-overflow/stack-overflow.cpp
 include teshsuite/kernel/stack-overflow/stack-overflow.tesh
-include teshsuite/mc/dwarf-expression/dwarf-expression.cpp
-include teshsuite/mc/dwarf-expression/dwarf-expression.tesh
-include teshsuite/mc/dwarf/dwarf.cpp
-include teshsuite/mc/dwarf/dwarf.tesh
+include teshsuite/mc/mcmini/barber_shop_deadlock.c
+include teshsuite/mc/mcmini/barber_shop_deadlock.tesh
+include teshsuite/mc/mcmini/barber_shop_ok.c
+include teshsuite/mc/mcmini/barber_shop_ok.tesh
+include teshsuite/mc/mcmini/philosophers_mutex_deadlock.c
+include teshsuite/mc/mcmini/philosophers_mutex_deadlock.tesh
+include teshsuite/mc/mcmini/philosophers_mutex_ok.c
+include teshsuite/mc/mcmini/philosophers_mutex_ok.tesh
+include teshsuite/mc/mcmini/philosophers_semaphores_deadlock.c
+include teshsuite/mc/mcmini/philosophers_semaphores_deadlock.tesh
+include teshsuite/mc/mcmini/philosophers_semaphores_ok.c
+include teshsuite/mc/mcmini/philosophers_semaphores_ok.tesh
+include teshsuite/mc/mcmini/producer_consumer_deadlock.c
+include teshsuite/mc/mcmini/producer_consumer_deadlock.tesh
+include teshsuite/mc/mcmini/producer_consumer_ok.c
+include teshsuite/mc/mcmini/producer_consumer_ok.tesh
+include teshsuite/mc/mcmini/simple_barrier_deadlock.c
+include teshsuite/mc/mcmini/simple_barrier_deadlock.tesh
+include teshsuite/mc/mcmini/simple_barrier_ok.c
+include teshsuite/mc/mcmini/simple_barrier_ok.tesh
+include teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c
+include teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh
+include teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c
+include teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh
+include teshsuite/mc/mcmini/simple_mutex_deadlock.c
+include teshsuite/mc/mcmini/simple_mutex_deadlock.tesh
+include teshsuite/mc/mcmini/simple_mutex_ok.c
+include teshsuite/mc/mcmini/simple_mutex_ok.tesh
+include teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.c
+include teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.tesh
+include teshsuite/mc/mcmini/simple_mutex_with_threads_ok.c
+include teshsuite/mc/mcmini/simple_mutex_with_threads_ok.tesh
+include teshsuite/mc/mcmini/simple_semaphore_deadlock.c
+include teshsuite/mc/mcmini/simple_semaphore_deadlock.tesh
+include teshsuite/mc/mcmini/simple_semaphores_deadlock.c
+include teshsuite/mc/mcmini/simple_semaphores_deadlock.tesh
+include teshsuite/mc/mcmini/simple_semaphores_ok.c
+include teshsuite/mc/mcmini/simple_semaphores_ok.tesh
+include teshsuite/mc/mcmini/simple_semaphores_with_threads_deadlock.c
+include teshsuite/mc/mcmini/simple_semaphores_with_threads_deadlock.tesh
+include teshsuite/mc/mcmini/simple_semaphores_with_threads_ok.c
+include teshsuite/mc/mcmini/simple_semaphores_with_threads_ok.tesh
+include teshsuite/mc/mcmini/simple_threads_ok.c
+include teshsuite/mc/mcmini/simple_threads_ok.tesh
 include teshsuite/mc/mutex-handling/mutex-handling.cpp
 include teshsuite/mc/mutex-handling/mutex-handling.tesh
 include teshsuite/mc/mutex-handling/without-mutex-handling.tesh
@@ -786,10 +865,6 @@ include teshsuite/s4u/vm-live-migration/vm-live-migration.cpp
 include teshsuite/s4u/vm-live-migration/vm-live-migration.tesh
 include teshsuite/s4u/vm-suicide/vm-suicide.cpp
 include teshsuite/s4u/vm-suicide/vm-suicide.tesh
-include teshsuite/s4u/wait-all-for/wait-all-for.cpp
-include teshsuite/s4u/wait-all-for/wait-all-for.tesh
-include teshsuite/s4u/wait-any-for/wait-any-for.cpp
-include teshsuite/s4u/wait-any-for/wait-any-for.tesh
 include teshsuite/smpi/MBI/CollArgGenerator.py
 include teshsuite/smpi/MBI/CollComGenerator.py
 include teshsuite/smpi/MBI/CollLocalConcurrencyGenerator.py
@@ -890,6 +965,7 @@ include teshsuite/smpi/macro-shared/macro-shared.c
 include teshsuite/smpi/macro-shared/macro-shared.tesh
 include teshsuite/smpi/mpich3-test/README
 include teshsuite/smpi/mpich3-test/attr/attr2type.c
+include teshsuite/smpi/mpich3-test/attr/attrdelete.c
 include teshsuite/smpi/mpich3-test/attr/attrdeleteget.c
 include teshsuite/smpi/mpich3-test/attr/attrend.c
 include teshsuite/smpi/mpich3-test/attr/attrend2.c
@@ -924,6 +1000,8 @@ include teshsuite/smpi/mpich3-test/coll/allred3.c
 include teshsuite/smpi/mpich3-test/coll/allred4.c
 include teshsuite/smpi/mpich3-test/coll/allred5.c
 include teshsuite/smpi/mpich3-test/coll/allred6.c
+include teshsuite/smpi/mpich3-test/coll/allred_derived.c
+include teshsuite/smpi/mpich3-test/coll/allred_float.c
 include teshsuite/smpi/mpich3-test/coll/allredmany.c
 include teshsuite/smpi/mpich3-test/coll/alltoall1.c
 include teshsuite/smpi/mpich3-test/coll/alltoallv.c
@@ -951,6 +1029,7 @@ include teshsuite/smpi/mpich3-test/coll/exscan2.c
 include teshsuite/smpi/mpich3-test/coll/gather.c
 include teshsuite/smpi/mpich3-test/coll/gather2.c
 include teshsuite/smpi/mpich3-test/coll/gather_big.c
+include teshsuite/smpi/mpich3-test/coll/gatherv.c
 include teshsuite/smpi/mpich3-test/coll/iallred.c
 include teshsuite/smpi/mpich3-test/coll/ibarrier.c
 include teshsuite/smpi/mpich3-test/coll/icallgather.c
@@ -1003,6 +1082,7 @@ include teshsuite/smpi/mpich3-test/coll/scatterv.c
 include teshsuite/smpi/mpich3-test/coll/testlist
 include teshsuite/smpi/mpich3-test/coll/uoplong.c
 include teshsuite/smpi/mpich3-test/comm/cmfree.c
+include teshsuite/smpi/mpich3-test/comm/cmfree2.c
 include teshsuite/smpi/mpich3-test/comm/cmsplit.c
 include teshsuite/smpi/mpich3-test/comm/cmsplit2.c
 include teshsuite/smpi/mpich3-test/comm/cmsplit_type.c
@@ -1019,6 +1099,7 @@ include teshsuite/smpi/mpich3-test/comm/comm_idup_mul.c
 include teshsuite/smpi/mpich3-test/comm/comm_idup_nb.c
 include teshsuite/smpi/mpich3-test/comm/comm_idup_overlap.c
 include teshsuite/smpi/mpich3-test/comm/comm_info.c
+include teshsuite/smpi/mpich3-test/comm/comm_info2.c
 include teshsuite/smpi/mpich3-test/comm/commcreate1.c
 include teshsuite/smpi/mpich3-test/comm/commname.c
 include teshsuite/smpi/mpich3-test/comm/ctxalloc.c
@@ -1350,21 +1431,28 @@ include teshsuite/smpi/mpich3-test/pt2pt/dtype_send.c
 include teshsuite/smpi/mpich3-test/pt2pt/eagerdt.c
 include teshsuite/smpi/mpich3-test/pt2pt/greq1.c
 include teshsuite/smpi/mpich3-test/pt2pt/huge_anysrc.c
+include teshsuite/smpi/mpich3-test/pt2pt/huge_dupcomm.c
+include teshsuite/smpi/mpich3-test/pt2pt/huge_ssend.c
 include teshsuite/smpi/mpich3-test/pt2pt/huge_underflow.c
 include teshsuite/smpi/mpich3-test/pt2pt/icsend.c
 include teshsuite/smpi/mpich3-test/pt2pt/inactivereq.c
 include teshsuite/smpi/mpich3-test/pt2pt/isendirecv.c
+include teshsuite/smpi/mpich3-test/pt2pt/isendrecv.c
+include teshsuite/smpi/mpich3-test/pt2pt/isendrecv_replace.c
 include teshsuite/smpi/mpich3-test/pt2pt/isendself.c
 include teshsuite/smpi/mpich3-test/pt2pt/isendselfprobe.c
 include teshsuite/smpi/mpich3-test/pt2pt/issendselfcancel.c
 include teshsuite/smpi/mpich3-test/pt2pt/large_message.c
+include teshsuite/smpi/mpich3-test/pt2pt/large_tag.c
 include teshsuite/smpi/mpich3-test/pt2pt/many_isend.c
 include teshsuite/smpi/mpich3-test/pt2pt/manylmt.c
 include teshsuite/smpi/mpich3-test/pt2pt/mprobe.c
+include teshsuite/smpi/mpich3-test/pt2pt/multi_psend_derived.c
 include teshsuite/smpi/mpich3-test/pt2pt/pingping.c
 include teshsuite/smpi/mpich3-test/pt2pt/probe-unexp.c
 include teshsuite/smpi/mpich3-test/pt2pt/probenull.c
 include teshsuite/smpi/mpich3-test/pt2pt/pscancel.c
+include teshsuite/smpi/mpich3-test/pt2pt/pssend.c
 include teshsuite/smpi/mpich3-test/pt2pt/rcancel.c
 include teshsuite/smpi/mpich3-test/pt2pt/recv_any.c
 include teshsuite/smpi/mpich3-test/pt2pt/rqfreeb.c
@@ -1566,9 +1654,6 @@ include teshsuite/xbt/log_large/log_large.tesh
 include teshsuite/xbt/log_usage/log_usage.c
 include teshsuite/xbt/log_usage/log_usage.tesh
 include teshsuite/xbt/log_usage/log_usage_ndebug.tesh
-include teshsuite/xbt/mmalloc/mmalloc_32.tesh
-include teshsuite/xbt/mmalloc/mmalloc_64.tesh
-include teshsuite/xbt/mmalloc/mmalloc_test.cpp
 include teshsuite/xbt/parallel_log_crashtest/parallel_log_crashtest.cpp
 include teshsuite/xbt/parallel_log_crashtest/parallel_log_crashtest.tesh
 include teshsuite/xbt/parmap_bench/parmap_bench.cpp
@@ -1579,7 +1664,6 @@ include teshsuite/xbt/signals/signals.cpp
 include teshsuite/xbt/signals/signals.tesh
 include tools/address_sanitizer.supp
 include tools/fix-paje-trace.sh
-include tools/generate-dwarf-functions
 include tools/graphicator/graphicator.cpp
 include tools/graphicator/graphicator.tesh
 include tools/normalize-pointers.py
@@ -1678,6 +1762,10 @@ include docs/source/app_smpi.rst
 include docs/source/application.rst
 include docs/source/community.rst
 include docs/source/conf.py
+include docs/source/img/battery_degradation.svg
+include docs/source/img/dag.svg
+include docs/source/img/dag1.svg
+include docs/source/img/dag2.svg
 include docs/source/img/design-scheduling-parallel.svg
 include docs/source/img/design-scheduling-simulatedtime.svg
 include docs/source/img/design-scheduling-wallclock.svg
@@ -1699,17 +1787,6 @@ include docs/source/img/zoom_comm.drawio
 include docs/source/img/zoom_comm.svg
 include docs/source/index.rst
 include docs/source/intl.rst
-include docs/source/tuto_dag/dag_lab1.cpp
-include docs/source/tuto_dag/dag_lab2-1.cpp
-include docs/source/tuto_dag/dag_lab2-2.cpp
-include docs/source/tuto_dag/dag_lab2-3.cpp
-include docs/source/tuto_dag/img/dag.svg
-include docs/source/tuto_dag/img/dag1.svg
-include docs/source/tuto_dag/img/dag2.svg
-include docs/source/tuto_dag/simple_dax.xml
-include docs/source/tuto_dag/simple_dot.dot
-include docs/source/tuto_dag/simple_json.json
-include docs/source/tuto_dag/small_platform.xml
 include docs/source/tuto_disk/CMakeLists.txt
 include docs/source/tuto_disk/Dockerfile
 include docs/source/tuto_disk/analysis.irst
@@ -1869,6 +1946,7 @@ include examples/smpi/replay_multiple_manual_deploy/CMakeLists.txt
 include examples/smpi/smpi_s4u_masterworker/CMakeLists.txt
 include examples/sthread/CMakeLists.txt
 include include/simgrid/Exception.hpp
+include include/simgrid/activity_set.h
 include include/simgrid/actor.h
 include include/simgrid/barrier.h
 include include/simgrid/chrono.hpp
@@ -1904,14 +1982,19 @@ include include/simgrid/mailbox.h
 include include/simgrid/modelchecker.h
 include include/simgrid/mutex.h
 include include/simgrid/plugins/ProducerConsumer.hpp
+include include/simgrid/plugins/battery.hpp
+include include/simgrid/plugins/chiller.hpp
 include include/simgrid/plugins/dvfs.h
 include include/simgrid/plugins/energy.h
 include include/simgrid/plugins/file_system.h
+include include/simgrid/plugins/jbod.hpp
 include include/simgrid/plugins/live_migration.h
 include include/simgrid/plugins/load.h
 include include/simgrid/plugins/ns3.hpp
+include include/simgrid/plugins/solar_panel.hpp
 include include/simgrid/s4u.hpp
 include include/simgrid/s4u/Activity.hpp
+include include/simgrid/s4u/ActivitySet.hpp
 include include/simgrid/s4u/Actor.hpp
 include include/simgrid/s4u/Barrier.hpp
 include include/simgrid/s4u/Comm.hpp
@@ -1923,12 +2006,14 @@ include include/simgrid/s4u/Host.hpp
 include include/simgrid/s4u/Io.hpp
 include include/simgrid/s4u/Link.hpp
 include include/simgrid/s4u/Mailbox.hpp
+include include/simgrid/s4u/Mess.hpp
+include include/simgrid/s4u/MessageQueue.hpp
 include include/simgrid/s4u/Mutex.hpp
 include include/simgrid/s4u/NetZone.hpp
 include include/simgrid/s4u/Semaphore.hpp
+include include/simgrid/s4u/Task.hpp
 include include/simgrid/s4u/VirtualMachine.hpp
 include include/simgrid/semaphore.h
-include include/simgrid/simix.h
 include include/simgrid/simix.hpp
 include include/simgrid/version.h.in
 include include/simgrid/vm.h
@@ -1947,8 +2032,6 @@ include include/xbt/Extendable.hpp
 include include/xbt/PropertyHolder.hpp
 include include/xbt/asserts.h
 include include/xbt/asserts.hpp
-include include/xbt/automaton.h
-include include/xbt/automaton.hpp
 include include/xbt/backtrace.hpp
 include include/xbt/base.h
 include include/xbt/config.h
@@ -1981,13 +2064,11 @@ include include/xbt/virtu.h
 include include/xbt/xbt_os_time.h
 include setup.py
 include src/3rd-party/catch.hpp
-include src/3rd-party/xxhash.hpp
 include src/bindings/python/simgrid_python.cpp
 include src/dag/dax.dtd
 include src/dag/dax_dtd.c
 include src/dag/dax_dtd.h
 include src/dag/loaders.cpp
-include src/deprecated.cpp
 include src/instr/instr_config.cpp
 include src/instr/instr_interface.cpp
 include src/instr/instr_paje_containers.cpp
@@ -2020,6 +2101,10 @@ include src/kernel/activity/IoImpl.cpp
 include src/kernel/activity/IoImpl.hpp
 include src/kernel/activity/MailboxImpl.cpp
 include src/kernel/activity/MailboxImpl.hpp
+include src/kernel/activity/MessImpl.cpp
+include src/kernel/activity/MessImpl.hpp
+include src/kernel/activity/MessageQueueImpl.cpp
+include src/kernel/activity/MessageQueueImpl.hpp
 include src/kernel/activity/MutexImpl.cpp
 include src/kernel/activity/MutexImpl.hpp
 include src/kernel/activity/SemaphoreImpl.cpp
@@ -2145,27 +2230,37 @@ include src/kernel/xml/sg_platf.cpp
 include src/kernel/xml/simgrid.dtd
 include src/kernel/xml/simgrid_dtd.c
 include src/kernel/xml/simgrid_dtd.h
-include src/mc/AddressSpace.hpp
-include src/mc/VisitedState.cpp
-include src/mc/VisitedState.hpp
 include src/mc/api/ActorState.hpp
+include src/mc/api/ClockVector.cpp
+include src/mc/api/ClockVector.hpp
 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/api/guide/BasicGuide.hpp
-include src/mc/api/guide/GuidedState.hpp
-include src/mc/compare.cpp
+include src/mc/api/strategy/BasicStrategy.hpp
+include src/mc/api/strategy/MaxMatchComm.hpp
+include src/mc/api/strategy/MinMatchComm.hpp
+include src/mc/api/strategy/Strategy.hpp
+include src/mc/api/strategy/UniformStrategy.hpp
 include src/mc/datatypes.h
 include src/mc/explo/CommunicationDeterminismChecker.cpp
 include src/mc/explo/DFSExplorer.cpp
 include src/mc/explo/DFSExplorer.hpp
 include src/mc/explo/Exploration.cpp
 include src/mc/explo/Exploration.hpp
-include src/mc/explo/LivenessChecker.cpp
-include src/mc/explo/LivenessChecker.hpp
 include src/mc/explo/UdporChecker.cpp
 include src/mc/explo/UdporChecker.hpp
+include src/mc/explo/odpor/ClockVector_test.cpp
+include src/mc/explo/odpor/Execution.cpp
+include src/mc/explo/odpor/Execution.hpp
+include src/mc/explo/odpor/Execution_test.cpp
+include src/mc/explo/odpor/WakeupTree.cpp
+include src/mc/explo/odpor/WakeupTree.hpp
+include src/mc/explo/odpor/WakeupTreeIterator.cpp
+include src/mc/explo/odpor/WakeupTreeIterator.hpp
+include src/mc/explo/odpor/WakeupTree_test.cpp
+include src/mc/explo/odpor/odpor_forward.hpp
+include src/mc/explo/odpor/odpor_tests_private.hpp
 include src/mc/explo/simgrid_mc.cpp
 include src/mc/explo/udpor/Comb.hpp
 include src/mc/explo/udpor/Configuration.cpp
@@ -2174,6 +2269,9 @@ include src/mc/explo/udpor/Configuration_test.cpp
 include src/mc/explo/udpor/EventSet.cpp
 include src/mc/explo/udpor/EventSet.hpp
 include src/mc/explo/udpor/EventSet_test.cpp
+include src/mc/explo/udpor/ExtensionSetCalculator.cpp
+include src/mc/explo/udpor/ExtensionSetCalculator.hpp
+include src/mc/explo/udpor/ExtensionSet_test.cpp
 include src/mc/explo/udpor/History.cpp
 include src/mc/explo/udpor/History.hpp
 include src/mc/explo/udpor/History_test.cpp
@@ -2187,30 +2285,13 @@ include src/mc/explo/udpor/maximal_subsets_iterator.cpp
 include src/mc/explo/udpor/maximal_subsets_iterator.hpp
 include src/mc/explo/udpor/udpor_forward.hpp
 include src/mc/explo/udpor/udpor_tests_private.hpp
-include src/mc/inspect/DwarfExpression.cpp
-include src/mc/inspect/DwarfExpression.hpp
-include src/mc/inspect/Frame.cpp
-include src/mc/inspect/Frame.hpp
-include src/mc/inspect/LocationList.cpp
-include src/mc/inspect/LocationList.hpp
-include src/mc/inspect/ObjectInformation.cpp
-include src/mc/inspect/ObjectInformation.hpp
-include src/mc/inspect/Type.hpp
-include src/mc/inspect/Variable.hpp
-include src/mc/inspect/mc_dwarf.cpp
-include src/mc/inspect/mc_dwarf.hpp
-include src/mc/inspect/mc_dwarf_attrnames.cpp
-include src/mc/inspect/mc_dwarf_tagnames.cpp
-include src/mc/inspect/mc_member.cpp
-include src/mc/inspect/mc_unw.cpp
-include src/mc/inspect/mc_unw.hpp
-include src/mc/inspect/mc_unw_vmread.cpp
 include src/mc/mc.h
 include src/mc/mc_base.cpp
 include src/mc/mc_base.hpp
 include src/mc/mc_client_api.cpp
 include src/mc/mc_config.cpp
 include src/mc/mc_config.hpp
+include src/mc/mc_environ.h
 include src/mc/mc_exit.hpp
 include src/mc/mc_forward.hpp
 include src/mc/mc_global.cpp
@@ -2227,22 +2308,10 @@ include src/mc/remote/CheckerSide.cpp
 include src/mc/remote/CheckerSide.hpp
 include src/mc/remote/RemotePtr.hpp
 include src/mc/remote/mc_protocol.h
-include src/mc/sosp/ChunkedData.cpp
-include src/mc/sosp/ChunkedData.hpp
-include src/mc/sosp/PageStore.cpp
-include src/mc/sosp/PageStore.hpp
-include src/mc/sosp/PageStore_test.cpp
-include src/mc/sosp/Region.cpp
-include src/mc/sosp/Region.hpp
-include src/mc/sosp/RemoteProcessMemory.cpp
-include src/mc/sosp/RemoteProcessMemory.hpp
-include src/mc/sosp/Snapshot.cpp
-include src/mc/sosp/Snapshot.hpp
-include src/mc/sosp/Snapshot_test.cpp
 include src/mc/transition/Transition.cpp
 include src/mc/transition/Transition.hpp
-include src/mc/transition/TransitionActorJoin.cpp
-include src/mc/transition/TransitionActorJoin.hpp
+include src/mc/transition/TransitionActor.cpp
+include src/mc/transition/TransitionActor.hpp
 include src/mc/transition/TransitionAny.cpp
 include src/mc/transition/TransitionAny.hpp
 include src/mc/transition/TransitionComm.cpp
@@ -2254,18 +2323,23 @@ include src/mc/transition/TransitionRandom.hpp
 include src/mc/transition/TransitionSynchro.cpp
 include src/mc/transition/TransitionSynchro.hpp
 include src/plugins/ProducerConsumer.cpp
+include src/plugins/battery.cpp
 include src/plugins/chaos_monkey.cpp
+include src/plugins/chiller.cpp
 include src/plugins/file_system/s4u_FileSystem.cpp
 include src/plugins/host_dvfs.cpp
 include src/plugins/host_energy.cpp
 include src/plugins/host_load.cpp
+include src/plugins/jbod.cpp
 include src/plugins/link_energy.cpp
 include src/plugins/link_energy_wifi.cpp
 include src/plugins/link_load.cpp
+include src/plugins/solar_panel.cpp
 include src/plugins/vm/VmLiveMigration.cpp
 include src/plugins/vm/VmLiveMigration.hpp
 include src/plugins/vm/dirty_page_tracking.cpp
 include src/s4u/s4u_Activity.cpp
+include src/s4u/s4u_ActivitySet.cpp
 include src/s4u/s4u_Actor.cpp
 include src/s4u/s4u_Barrier.cpp
 include src/s4u/s4u_Comm.cpp
@@ -2277,9 +2351,12 @@ include src/s4u/s4u_Host.cpp
 include src/s4u/s4u_Io.cpp
 include src/s4u/s4u_Link.cpp
 include src/s4u/s4u_Mailbox.cpp
+include src/s4u/s4u_Mess.cpp
+include src/s4u/s4u_MessageQueue.cpp
 include src/s4u/s4u_Mutex.cpp
 include src/s4u/s4u_Netzone.cpp
 include src/s4u/s4u_Semaphore.cpp
+include src/s4u/s4u_Task.cpp
 include src/s4u/s4u_VirtualMachine.cpp
 include src/simgrid/Exception.cpp
 include src/simgrid/math_utils.h
@@ -2481,13 +2558,6 @@ include src/sthread/sthread.h
 include src/sthread/sthread_impl.cpp
 include src/xbt/OsSemaphore.hpp
 include src/xbt/PropertyHolder.cpp
-include src/xbt/automaton/automaton.c
-include src/xbt/automaton/automaton_lexer.yy.c
-include src/xbt/automaton/automatonparse_promela.c
-include src/xbt/automaton/parserPromela.lex
-include src/xbt/automaton/parserPromela.tab.cacc
-include src/xbt/automaton/parserPromela.tab.hacc
-include src/xbt/automaton/parserPromela.yacc
 include src/xbt/backtrace.cpp
 include src/xbt/config.cpp
 include src/xbt/config_test.cpp
@@ -2507,20 +2577,6 @@ include src/xbt/mallocator.c
 include src/xbt/mallocator_private.h
 include src/xbt/memory_map.cpp
 include src/xbt/memory_map.hpp
-include src/xbt/mmalloc/mfree.c
-include src/xbt/mmalloc/mm.c
-include src/xbt/mmalloc/mm_interface.c
-include src/xbt/mmalloc/mm_legacy.c
-include src/xbt/mmalloc/mm_module.c
-include src/xbt/mmalloc/mmalloc.c
-include src/xbt/mmalloc/mmalloc.h
-include src/xbt/mmalloc/mmalloc.info
-include src/xbt/mmalloc/mmalloc.texi
-include src/xbt/mmalloc/mmorecore.c
-include src/xbt/mmalloc/mmprivate.h
-include src/xbt/mmalloc/mrealloc.c
-include src/xbt/mmalloc/swag.c
-include src/xbt/mmalloc/swag.h
 include src/xbt/parmap.cpp
 include src/xbt/parmap.hpp
 include src/xbt/random.cpp
@@ -2596,10 +2652,7 @@ include tools/cmake/Flags.cmake
 include tools/cmake/MaintainerMode.cmake
 include tools/cmake/MakeLib.cmake
 include tools/cmake/Modules/FindGraphviz.cmake
-include tools/cmake/Modules/FindLibdw.cmake
-include tools/cmake/Modules/FindLibelf.cmake
 include tools/cmake/Modules/FindLibevent.cmake
-include tools/cmake/Modules/FindLibunwind.cmake
 include tools/cmake/Modules/FindNS3.cmake
 include tools/cmake/Modules/FindPAPI.cmake
 include tools/cmake/Modules/FindValgrind.cmake
@@ -2612,6 +2665,7 @@ include tools/cmake/scripts/my_valgrind.pl
 include tools/cmake/scripts/update_tesh.pl
 include tools/cmake/test_prog/prog_asan.cpp
 include tools/cmake/test_prog/prog_makecontext.c
+include tools/cmake/test_prog/prog_ns3.cpp
 include tools/cmake/test_prog/prog_stackgrowth.c
 include tools/cmake/test_prog/prog_stacksetup.c
 include tools/cmake/test_prog/prog_tsan.cpp
diff --git a/NEWS b/NEWS
index fe01ae8..bbe6e5f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,14 +1,48 @@
-                    _               _____  __________
-__   _____ _ __ ___(_) ___  _ __   |___ / |___ /___ /
-\ \ / / _ \ '__/ __| |/ _ \| '_ \    |_ \   |_ \ |_ \
+
+                    _               _____  _____  __
+__   _____ _ __ ___(_) ___  _ __   |___ / |___ / / /_
+\ \ / / _ \ '__/ __| |/ _ \| '_ \    |_ \   |_ \| '_ \
+ \ V /  __/ |  \__ \ | (_) | | | |  ___) | ___) | (_) |
+  \_/ \___|_|  |___/_|\___/|_| |_| |____(_)____/ \___/
+               (not released yet)
+
+
+                    _               _____  _________
+__   _____ _ __ ___(_) ___  _ __   |___ / |___ / ___|
+\ \ / / _ \ '__/ __| |/ _ \| '_ \    |_ \   |_ \___ \
  \ V /  __/ |  \__ \ | (_) | | | |  ___) | ___) |__) |
   \_/ \___|_|  |___/_|\___/|_| |_| |____(_)____/____/
-               (not released yet)
+               November 23. 2023
+
+The "Thanks Giving up stateful model-checking" release. Stateless model checking remains.
+
+ * Maint: liveness checking is gone. It was fragile and buggy.
+ * API: ActivitySet make it easier to manage sets of activities.
+ * Plugins chiller, photovoltaic and battery revamped and improved.
+ * Performance improvements, both in time and memory.
+ * (+ internal refactoring, usability improvements and bug fixes)
+                    _               _____  _____ _  _
+__   _____ _ __ ___(_) ___  _ __   |___ / |___ /| || |
+\ \ / / _ \ '__/ __| |/ _ \| '_ \    |_ \   |_ \| || |_
+ \ V /  __/ |  \__ \ | (_) | | | |  ___) | ___) |__   _|
+  \_/ \___|_|  |___/_|\___/|_| |_| |____(_)____/   |_|
+               June 26. 2023
+
+Save the planet, skip a release: 3.33 was due 6 months ago, so skip directly to 3.34.
+
+ * Maint: MSG and Java are gone (EOL was scheduled for 2020), move to C++17,
+          and drop 32bits support.
+ * Model: Introduce a fluid I/O model, mixing I/O and network, to represent
+          streaming from disk
+ * API: DAG/workflow loader; Introducing Tasks which are activities that can
+        be fired several times.
+ * Doc: Several new documentation sections, and a new tutorial on DAGs.
+ * MC: Safety properties now portable to every OS, activated by default
+       in all builds.
+ * MC: Introduction ODPOR/SDPOR reductions and guiding strategies (better
+       state space traversal).
+ * (+ internal refactoring, bug fixes and documentation improvement)
 
-  * MSG and Java are gone (EOL was scheduled for 2020)
-  * Introduce a fluid I/O model, mixing I/O and network, to represent streaming from disk
-  * Fix the DPOR reduction, toward sound verifications.
-  * (+ MANY internal refactoring, bug fixes and MANY documentation improvement)
                     _               _____  _________
 __   _____ _ __ ___(_) ___  _ __   |___ / |___ /___ \
 \ \ / / _ \ '__/ __| |/ _ \| '_ \    |_ \   |_ \ __) |
index 65f20c0..d7e84f0 100644 (file)
@@ -14,7 +14,6 @@ Please apply the following checklist before releasing.
 - ChangeLog file
   - All changes are documented
   - The release date is indicated below the changes
-  - The release is marked as stable above the changes (remove the UNRELEASED marker)
   - The release dub name matches the one given in NEWS file
 - NEWS
   - The most notable changes of the version are documented
@@ -35,6 +34,7 @@ Please apply the following checklist before releasing.
 @subsection inside_release_c_releasing Actually releasing SimGrid
 
 - Update the version number in:
+  - ChangeLog header
   - CMakeLists.txt (in macros SIMGRID_VERSION_*)
   - sonar-project.properties
   - docs/source/conf.py
@@ -52,7 +52,7 @@ Please apply the following checklist before releasing.
 - Document the tag on framagit and ghub
   - Upload the files simgrid-3.XX.tar.gz and simgrid-doc-3_XX.zip
   - Add a link to the version of the ChangeLog that comes with this tag.
-    https://framagit.org/simgrid/simgrid/-/blob/v3.29/ChangeLog
+    https://framagit.org/simgrid/simgrid/-/blob/v3.35/ChangeLog
 - Update the website
   - emacs org/org-templates/level-0.org to change the release version and the tgz link.
   - jed .gitlab-ci.yml
@@ -67,7 +67,7 @@ Please apply the following checklist before releasing.
     rm -rf /tmp/pysimgrid && mkdir /tmp/pysimgrid && cp dist/simgrid-*.tar.gz /tmp/pysimgrid
     (cd /tmp/pysimgrid && tar xfz simgrid*.tar.gz && cd simgrid-*/ && python3 setup.py build)
   - Upload it to pypi (WARNING: you cannot modify uploaded files, ever)
-    twine upload dist/simgrid-*.tar.gz
+    twine upload dist/simgrid-*.tar.gz # User and password should be located in ~/.pypirc
 
 @subsection inside_release_c_publishing Publishing the release if it's a stable one (3.XX not 3.XX.Y)
 
@@ -79,18 +79,17 @@ Please apply the following checklist before releasing.
     - Link to the ChangeLog on framagit (the version of that tag)
  - Also mail some other lists (G5K users)
 - Release the debian package
-  - rm -f ../simgrid_3.*+dfsg.orig.tar.xz
+  - rm -f ../simgrid_3.*.orig.tar.xz
   - uscan # download the new version
-  - gbp import-orig ../simgrid_3.*+dfsg.orig.tar.xz
+  - gbp import-orig ../simgrid_3.*.orig.tar.xz
   - dch -i "New upstream release" # + copy the NEWS into debian/changelog
   - git mv debian/libsimgrid3.XX.install debian/libsimgrid3.XY.install
   - edit debian/control: s/simgrid3.XX/simgrid3.XY/
 - Update the simgrid/package.py for spack: https://gitlab.inria.fr/solverstack/spack-repo
 - Push the stable branch to github to rebuild and push the stable Docker images
-  - It downloads the latest tag on framagit
-  - If it was done automatically at some point, make sure that it's really the latest stable, 
-    as things get sometimes out of synch to the point that the github action re-build the previous release. 
-    If this happens, just rerun the docker-stable action. Nothing should have been broken.
+  - It downloads the latest tag on framagit, but sometimes gets out of synch.
+    Make sure that it's really the latest stable, as it sometimes rebuilds the previous release.
+    If this happens, just rerun the docker-stable action. Nothing should get hurt by the rebuild.
   - Doing the same manually: cd tools/docker && make stable && make tuto-s4u tuto-smpi
     (tuto-mc is not based on simgrid/stable but rebuilds from the git)
   - Once the new images are built, trigger a rebuild of the simgrid-template-{s4u,smpi} repositories on framagit
index c8899ea..b4fb66f 100644 (file)
@@ -354,7 +354,7 @@ you should use to analyze your simulator.
 @li I want to trace the resource utilization of all hosts
 and links of the platform, and my simulator <b>does not</b> use
 the tracing API. For that, you can run a uncategorized trace
-with the following parameters (it will work with <b>any</b> Simgrid
+with the following parameters (it will work with <b>any</b> SimGrid
 simulator):
 @verbatim
 ./your_simulator @
index dc40367..98d55a9 100644 (file)
@@ -411,7 +411,7 @@ type and properly handles exceptions:
 
 @code{cpp}
 template<class F>
-typename std::result_of<F()>::type kernelImmediate(F&& code)
+typename std::result_of_t<F()> kernelImmediate(F&& code)
 {
   // If we are in the simulation kernel, we take the fast path and
   // execute the code directly without simcall
@@ -421,7 +421,7 @@ typename std::result_of<F()>::type kernelImmediate(F&& code)
 
   // If we are in the application, pass the code to the simulation
   // kernel which executes it for us and reports the result:
-  typedef typename std::result_of<F()>::type R;
+  typedef typename std::result_of_t<F()> R;
   simgrid::xbt::Result<R> result;
   simcall_run_kernel([&]{
     xbt_assert(SIMIX_is_maestro(), "Not in maestro");
index e55855c..8aa516b 100755 (executable)
@@ -65,3 +65,5 @@ else
   echo "Install linkchecker to have it executed when you build the doc."
 fi
 
+echo "Undocumented symbols:"
+./find-missing.py 2>&1
index 1f26318..bd2d730 100644 (file)
@@ -20,6 +20,7 @@ It is only used by find-missing, that will not report any definition linked here
 
 # These are used to make the C++ objects visible from the C world
 .. doxygentypedef:: s4u_Actor
+.. doxygentypedef:: s4u_ActivitySet
 .. doxygentypedef:: s4u_Barrier
 .. doxygentypedef:: s4u_Comm
 .. doxygentypedef:: s4u_ConditionVariable
@@ -33,3 +34,6 @@ It is only used by find-missing, that will not report any definition linked here
 .. doxygentypedef:: s4u_NetZone
 .. doxygentypedef:: s4u_Semaphore
 .. doxygentypedef:: s4u_VM
+.. doxygentypedef:: s4u_Activity
+.. doxygentypedef:: s4u_ActivitySet
+.. doxygentypedef:: s4u_MessageQueue
\ No newline at end of file
index 7d370d5..ac61890 100755 (executable)
@@ -94,6 +94,9 @@ def handle_python_module(fullname, englobing, elm):
     elif isinstance(elm, (int, str)): # We do have such a data, directly in the SimGrid top module
         found_decl("data", fullname)
 #        print('.. autodata:: {}'.format(fullname))
+    elif inspect.isclass(type(elm)): # Enum classes are of that kind
+        found_decl("data", fullname)
+        #print('.. autodata:: {}'.format(fullname))
     elif inspect.ismodule(elm) or inspect.isclass(elm):
         for name, data in inspect.getmembers(elm):
             if name.startswith('__'):
@@ -101,7 +104,7 @@ def handle_python_module(fullname, englobing, elm):
 #            print("Recurse on {}.{}".format(fullname, name))
             handle_python_module("{}.{}".format(fullname, name), elm, data)
     else:
-        print('UNHANDLED TYPE {} : {!r} Type: {}'.format(fullname, elm, type(elm)))
+        print('UNHANDLED TYPE {} : {!r} Type: {} Englobing: {} str: {} Members: \n{}\n'.format(fullname, elm, type(elm), englobing, str(elm), inspect.getmembers(elm)))
 
 # Start the recursion on the provided Python modules
 for name in python_modules:
index a98401b..d6238d6 100644 (file)
@@ -1,5 +1,5 @@
 breathe>=4.26
-sphinx>=3.4.3,<4.0
+sphinx
 sphinx_rtd_theme>=0.5.2
 # sphinx_tabs v1.2.1 is required for Sphinx 2
 sphinx_tabs>=1.2.1
index 3df5bdd..d06882f 100644 (file)
@@ -108,18 +108,14 @@ Existing Configuration Items
 - **maxmin/concurrency-limit:** :ref:`cfg=maxmin/concurrency-limit`
 
 - **model-check:** :ref:`options_modelchecking`
-- **model-check/checkpoint:** :ref:`cfg=model-check/checkpoint`
 - **model-check/communications-determinism:** :ref:`cfg=model-check/communications-determinism`
 - **model-check/dot-output:** :ref:`cfg=model-check/dot-output`
 - **model-check/max-depth:** :ref:`cfg=model-check/max-depth`
-- **model-check/property:** :ref:`cfg=model-check/property`
 - **model-check/reduction:** :ref:`cfg=model-check/reduction`
 - **model-check/replay:** :ref:`cfg=model-check/replay`
 - **model-check/send-determinism:** :ref:`cfg=model-check/send-determinism`
 - **model-check/setenv:** :ref:`cfg=model-check/setenv`
-- **model-check/termination:** :ref:`cfg=model-check/termination`
 - **model-check/timeout:** :ref:`cfg=model-check/timeout`
-- **model-check/visited:** :ref:`cfg=model-check/visited`
 
 - **network/bandwidth-factor:** :ref:`cfg=network/bandwidth-factor`
 - **network/crosstraffic:** :ref:`cfg=network/crosstraffic`
@@ -527,8 +523,6 @@ Note that with the default host model this option is activated by default.
 Simulating Asynchronous Send
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-(this configuration item is experimental and may change or disappear)
-
 It is possible to specify that messages below a certain size (in bytes) will be
 sent as soon as the call to MPI_Send is issued, without waiting for
 the correspondent receive. This threshold can be configured through
@@ -547,13 +541,12 @@ are meant to be detached as well.
 Configuring ns-3
 ^^^^^^^^^^^^^^^^
 
-**Option** ``ns3/TcpModel`` **Default:** "default" (ns-3 default)
+**Option** ``ns3/NetworkModel`` **Default:** "default" (ns-3 default TCP)
 
-When using ns-3, there is an extra item ``ns3/TcpModel``, corresponding
-to the ``ns3::TcpL4Protocol::SocketType`` configuration item in
-ns-3. The only valid values (enforced on the SimGrid side) are
-'default' (no change to the ns-3 configuration), 'NewReno' or 'Reno' or
-'Tahoe'.
+When using ns-3, the item ``ns3/NetworkModel`` can be used to switch between TCP or UDP, and switch the used TCP variante. If
+the item is left unchanged, ns-3 uses the default TCP implementation. With a value of "UDP", ns-3 is set to use UDP instead.
+With the value of either 'NewReno' or 'Cubic', the ``ns3::TcpL4Protocol::SocketType`` configuration item in ns-3 is set to the
+corresponding protocol.
 
 **Option** ``ns3/seed`` **Default:** "" (don't set the seed in ns-3)
 
@@ -648,102 +641,50 @@ The ``smpi/buffering`` (only valid with MC) option gives an easier interface to
 - **zero:** means that buffering should be disabled. All communications are actually blocking.
 - **infty:** means that buffering should be made infinite. All communications are non-blocking.
 
-.. _cfg=model-check/property:
-
-Specifying a liveness property
-..............................
-
-**Option** ``model-check/property`` **Default:** unset
-
-If you want to specify liveness properties, you have to pass them on
-the command line, specifying the name of the file containing the
-property, as formatted by the `ltl2ba <https://github.com/utwente-fmt/ltl2ba>`_ program.
-Note that ltl2ba is not part of SimGrid and must be installed separately.
-
-.. code-block:: console
-
-   $ simgrid-mc ./my_program --cfg=model-check/property:<filename>
-
-.. _cfg=model-check/checkpoint:
-
-Going for Stateful Verification
-...............................
-
-By default, the system is backtracked to its initial state to explore
-another path, instead of backtracking to the exact step before the fork
-that we want to explore (this is called stateless verification). This
-is done this way because saving intermediate states can rapidly
-exhaust the available memory. If you want, you can change the value of
-the ``model-check/checkpoint`` item. For example,
-``--cfg=model-check/checkpoint:1`` asks to take a checkpoint every
-step.  Beware, this will certainly explode your memory. Larger values
-are probably better, make sure to experiment a bit to find the right
-setting for your specific system.
-
 .. _cfg=model-check/reduction:
 
 Specifying the kind of reduction
 ................................
 
+**Option** model-check/reduction **Default:** "dpor"
+
 The main issue when using the model-checking is the state space
 explosion. You can activate some reduction technique with
 ``--cfg=model-check/reduction:<technique>``. For now, this
 configuration variable can take 2 values:
 
- - **none:** Do not apply any kind of reduction (mandatory for
-   liveness properties, as our current DPOR algorithm breaks cycles)
- - **dpor:** Apply Dynamic Partial Ordering Reduction. Only valid if
-   you verify local safety properties (default value for safety
-   checks).
-
-Another way to mitigate the state space explosion is to search for
-cycles in the exploration with the :ref:`cfg=model-check/visited`
-configuration. Note that DPOR and state-equality reduction may not
-play well together. You should choose between them.
+ - **none:** Do not apply any kind of reduction
+ - **dpor:** Apply Dynamic Partial Ordering Reduction. Only valid if you verify local safety properties (default value for
+   safety checks).
+ - **sdpor:** Source-set DPOR, as described in "Source Sets: A Foundation for Optimal Dynamic Partial Order Reduction"
+    by Abdulla et al.
+ - **odpor:** Optimal DPOR, as described in "Source Sets: A Foundation for Optimal Dynamic Partial Order Reduction"
+    by Abdulla et al.
 
 Our current DPOR implementation could be improved in may ways. We are
 currently improving its efficiency (both in term of reduction ability
-and computational speed), and future work could make it compatible
-with liveness properties.
+and computational speed).
 
-.. _cfg=model-check/visited:
+.. _cfg=model-check/strategy:
 
-Size of Cycle Detection Set (state equality reduction)
-......................................................
-
-Mc SimGrid can be asked to search for cycles during the exploration,
-i.e. situations where a new explored state is in fact the same state
-than a previous one.. This can prove useful to mitigate the state
-space explosion with safety properties, and this is the crux when
-searching for counter-examples to the liveness properties.
-
-Note that this feature may break the current implementation of the
-DPOR reduction technique.
-
-The ``model-check/visited`` item is the maximum number of states, which
-are stored in memory. If the maximum number of snapshotted state is
-reached, some states will be removed from the memory and some cycles
-might be missed. Small values can lead to incorrect verifications, but
-large values can exhaust your memory and be CPU intensive as each new
-state must be compared to that amount of older saved states.
-
-The default settings depend on the kind of exploration. With safety
-checking, no state is snapshotted and cycles cannot be detected. With
-liveness checking, all states are snapshotted because missing a cycle
-could hinder the exploration soundness.
-
-.. _cfg=model-check/termination:
-
-Non-Termination Detection
-.........................
+Guiding strategy
+................
 
-The ``model-check/termination`` configuration item can be used to
-report if a non-termination execution path has been found. This is a
-path with a cycle, which means that the program might never terminate.
+**Option** model-check/strategy **Default:** "none"
 
-This only works in safety mode, not in liveness mode.
+Even after the DPOR's reduction, the state space that we have to explore remains huge. SimGrid provides several guiding
+strategies aiming at converging faster toward bugs. By default, none of these strategy is enabled, and SimGrid does a regular
+DFS exploration.
 
-This options is disabled by default.
+ - **max_match_comm**: Try to minimize the number of in-fly communication by appairing matching send and receive. This tend to
+   produce nicer backtraces, in particular when a user-level ``send`` is broken down internally into a ``send_async`` + ``wait``.
+   This strategy will ensure that the ``wait`` occures as soon as possible, easing the understanding of the user who do not
+   expect her ``send`` to be split.
+ - **min_match_comm**: Try to maximize the number of in-fly communication by not appairing matching send and receive. This is
+   the exact opposite strategy, but it is still useful as it tend to explore first the branches where the risk of deadlock is
+   higher.
+ - **uniform**: this is a boring random strategy where choices are based on a uniform sampling of possible choices.
+   Surprisingly, it gives really really good results.
 
 .. _cfg=model-check/dot-output:
 
@@ -752,8 +693,7 @@ Dot Output
 
 If set, the ``model-check/dot-output`` configuration item is the name
 of a file in which to write a dot file of the path leading to the
-property violation discovered (safety or liveness violation), as well
-as the cycle for liveness properties. This dot file can then be fed to the
+property violation discovered (safety violation). This dot file can then be fed to the
 graphviz dot tool to generate a corresponding graphical representation.
 
 .. _cfg=model-check/max-depth:
@@ -818,17 +758,14 @@ memory (see :ref:`contexts/guard-size <cfg=contexts/guard-size>`).
 Replaying buggy execution paths from the model checker
 ......................................................
 
-Debugging the problems reported by the model checker is challenging:
-First, the application under verification cannot be debugged with gdb
-because the model checker already traces it. Then, the model checker may
-explore several execution paths before encountering the issue, making it
-very difficult to understand the output. Fortunately, SimGrid provides
+Debugging the problems reported by the model checker is challenging because
+the model checker may explore several execution paths before encountering the issue,
+the output very difficult to understand. Fortunately, SimGrid provides
 the execution path leading to any reported issue so that you can replay
-this path reported by the model checker, enabling the usage of classical
-debugging tools.
+this path reported by the model checker, restoring a classical experience of debugging.
 
 When the model checker finds an interesting path in the application
-execution graph (where a safety or liveness property is violated), it
+execution graph (where a safety property is violated), it
 generates an identifier for this path. Here is an example of the output:
 
 .. code-block:: console
@@ -849,10 +786,84 @@ The interesting line is ``Path = 1/3;1/4``, which means that you should use
 ``--cfg=model-check/replay:1/3;1/4`` to replay your application on the buggy
 execution path. All options (but the model checker related ones) must
 remain the same. In particular, if you ran your application with
-``smpirun -wrapper simgrid-mc``, then do it again. Remove all
+``smpirun -wrapper simgrid-mc``, then remove the ``-wrapper simgrid-mc`` part 
+(you may want to use valgrind or gdb as wrappers instead). Also remove all
 MC-related options, keep non-MC-related ones and add
 ``--cfg=model-check/replay:???``.
 
+Things are very similar if you are using sthread. Simply drop ``simgrid-mc`` from your command line, as follows:
+
+.. code-block:: console
+
+   $ LD_PRELOAD=../../lib/libsthread.so ./pthread-mutex-simpledeadlock --cfg=model-check/replay:'2;2;3;2;3;3'
+   sthread is intercepting the execution of ./pthread-mutex-simpledeadlock
+   [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/replay' to '2;2;3;2;3;3'
+   [0.000000] [mc_record/INFO] path=2;2;3;2;3;3
+   All threads are started.
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   [0.000000] [mc_record/INFO] * Path chunk #1 '2/0' Actor thread 1(pid:2): MUTEX_ASYNC_LOCK(mutex_id:0 owner:none)
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   Backtrace (displayed in actor thread 1):
+     ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:26
+     ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+     ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+     ->  #3 thread_fun1 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:21
+   
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   [0.000000] [mc_record/INFO] * Path chunk #2 '2/0' Actor thread 1(pid:2): MUTEX_WAIT(mutex_id:0 owner:2)
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   Backtrace (displayed in actor thread 1):
+     ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:29
+     ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+     ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+     ->  #3 thread_fun1 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:21
+   
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   [0.000000] [mc_record/INFO] * Path chunk #3 '3/0' Actor thread 2(pid:3): MUTEX_ASYNC_LOCK(mutex_id:1 owner:none)
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   Backtrace (displayed in actor thread 2):
+     ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:26
+     ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+     ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+     ->  #3 thread_fun2 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:31
+   
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   [0.000000] [mc_record/INFO] * Path chunk #4 '2/0' Actor thread 1(pid:2): MUTEX_ASYNC_LOCK(mutex_id:1 owner:3)
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   Backtrace (displayed in actor thread 1):
+     ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:26
+     ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+     ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+     ->  #3 thread_fun1 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:22
+   
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   [0.000000] [mc_record/INFO] * Path chunk #5 '3/0' Actor thread 2(pid:3): MUTEX_WAIT(mutex_id:1 owner:3)
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   Backtrace (displayed in actor thread 2):
+     ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:29
+     ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+     ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+     ->  #3 thread_fun2 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:31
+   
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   [0.000000] [mc_record/INFO] * Path chunk #6 '3/0' Actor thread 2(pid:3): MUTEX_ASYNC_LOCK(mutex_id:0 owner:2)
+   [0.000000] [mc_record/INFO] ***********************************************************************************
+   Backtrace (displayed in actor thread 2):
+     ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:26
+     ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+     ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+     ->  #3 thread_fun2 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:32
+   
+   [0.000000] [mc_record/INFO] The replay of the trace is complete. DEADLOCK detected.
+   [0.000000] [ker_engine/INFO] 3 actors are still running, waiting for something.
+   [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+   [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:2)
+   [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall MUTEX_WAIT(mutex_id:1 owner:3)
+   [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+   [0.000000] [sthread/INFO] All threads exited. Terminating the simulation.
+   [0.000000] ../../src/kernel/EngineImpl.cpp:265: [ker_engine/WARNING] Process called exit when leaving - Skipping cleanups
+   [0.000000] ../../src/kernel/EngineImpl.cpp:265: [ker_engine/WARNING] Process called exit when leaving - Skipping cleanups
+
 Currently, if the path is of the form ``X;Y;Z``, each number denotes
 the actor's pid that is selected at each indecision point. If it's of
 the form ``X/a;Y/b``, the X and Y are the selected pids while the a
@@ -1330,12 +1341,10 @@ existing MPI libraries. The ``smpi/coll-selector`` item can be used to
 select the decision logic either of the OpenMPI or the MPICH libraries. (By
 default SMPI uses naive version of collective operations.)
 
-Each collective operation can be manually selected with a
-``smpi/collective_name:algo_name``. Available algorithms are listed in
-:ref:`SMPI_use_colls`.
-
-.. TODO:: All available collective algorithms will be made available
-          via the ``smpirun --help-coll`` command.
+Each collective operation can be manually selected with a ``smpi/collective_name:algo_name``. For example, if you want to use
+the Bruck algorithm for the Alltoall algorithm, you should use ``--cfg=smpi/alltoall:bruck`` on the command-line of smpirun. The
+reference of all available algorithms are listed in :ref:`SMPI_use_colls`, and you can get the full list implemented in your
+version using ``smpirun --help-coll``.
 
 .. _cfg=smpi/barrier-collectives:
 
index 1595fcb..0e1decc 100644 (file)
@@ -3,6 +3,7 @@ INPUT                  = ../../include/simgrid/forward.h
 INPUT                 += ../../include/simgrid/plugins/
 INPUT                 += ../../include/simgrid/s4u/
 INPUT                 += ../../include/simgrid/actor.h
+INPUT                 += ../../include/simgrid/activity_set.h
 INPUT                 += ../../src/s4u/s4u_Actor.cpp
 INPUT                 += ../../include/simgrid/barrier.h
 INPUT                 += ../../include/simgrid/comm.h
@@ -19,6 +20,8 @@ INPUT                 += ../../include/simgrid/mutex.h
 INPUT                 += ../../include/simgrid/semaphore.h
 INPUT                 += ../../include/simgrid/vm.h
 INPUT                 += ../../include/simgrid/zone.h
+INPUT                 += ../../include/smpi/smpi.h
+INPUT                 += ../../include/xbt/function_types.h
 INPUT                 += ../../include/xbt/dynar.h
 INPUT                 += ../../src/xbt/dynar.cpp
 INPUT                 += ../../include/xbt/signal.hpp
@@ -65,7 +68,6 @@ PREDEFINED             += \
     XBT_ATTRIB_NORETURN= \
     XBT_ATTRIB_UNUSED= \
     XBT_LOG_NEW_DEFAULT_SUBCATEGORY(cname,parent,desc)= \
-    XBT_ATTRIB_DEPRECATED_v334(mesg)= \
-    XBT_ATTRIB_DEPRECATED_v335(mesg)= \
-    XBT_ATTRIB_DEPRECATED_v336(mesg)= \
-    XBT_ATTRIB_DEPRECATED_v337(mesg)=
+    XBT_ATTRIB_DEPRECATED_v338(mesg)= \
+    XBT_ATTRIB_DEPRECATED_v339(mesg)= \
+    XBT_ATTRIB_DEPRECATED_v340(mesg)=
index 5cb50fb..39cc872 100644 (file)
@@ -43,6 +43,17 @@ email.
 .. _simgrid AUR package: https://aur.archlinux.org/packages/simgrid/
 .. _AUR official documentation: https://wiki.archlinux.org/title/Arch_User_Repository
 
+Binaries from macOS
+^^^^^^^^^^^^^^^^^^^
+
+SimGrid can be found in the Homebrew package manager. Troubleshooting:
+
+warning: dylib (libsimgrid.dylib) was built for newer macOS version (14.0) than being linked (13.3)
+  This was reported with the SimGrid version from Homebrew on a Mac book air M1 (ARM).
+  The solution is simply to export this variable before the compilation of your binaries:
+
+  ``export MACOSX_DEPLOYMENT_TARGET=14.0``
+
 .. _deprecation_policy:
 
 Version numbering and deprecation
@@ -100,13 +111,13 @@ boost recommended components (optional).
   - On Debian / Ubuntu: ``apt install libboost-context-dev libboost-stacktrace-dev``
 python bindings (optional):
   - On Debian / Ubuntu: ``apt install pybind11-dev python3-dev``
-Model-checking dependencies (optional)
-  - On Debian / Ubuntu: ``apt install libunwind-dev libdw-dev libelf-dev libevent-dev``
+Model-checking mandatory dependencies
+  - On Debian / Ubuntu: ``apt install libevent-dev``
 Eigen3 (optional)
   - On Debian / Ubuntu: ``apt install libeigen3-dev``
   - On CentOS / Fedora: ``dnf install eigen3-devel``
   - On macOS with homebrew: ``brew install eigen``
-  - Use EIGEN3_HINT to specify where it's installed if cmake doesn't find it automatically.
+  - Use EIGEN3_HINT to specify where it's installed if cmake doesn't find it automatically. Set EIGEN3_HINT=OFF to disable detection even if it could be found.
 JSON (optional, for the DAG wfcommons loader)
   - On Debian / Ubuntu: ``apt install nlohmann-json3-dev``
   - Use nlohmann_json_HINT to specify where it's installed if cmake doesn't find it automatically.
@@ -195,7 +206,7 @@ Note that the dot at the end is mandatory (see :ref:`install_cmake_outsrc`).
 
 .. code-block:: console
 
-   $ cmake -DCC=clang -DCXX=clang++ .
+   $ cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .
 
 SimGrid compilation options
 """""""""""""""""""""""""""
@@ -241,10 +252,9 @@ enable_mallocators (ON/off)
   Activates our internal memory caching mechanism. This produces faster
   code, but it may fool the debuggers.
 
-enable_model-checking (on/OFF)
-  Activates the formal verification mode. This will hinder simulation speed even when the model checker is not activated at run
-  time, because some optimizations such as LTO must be disabled at compile time. You need to have the :ref:`required
-  build-dependencies <install_src_deps>` to activate this option.
+enable_model-checking (ON/off)
+  Activates the verification mode. This should not impact the performance of your simulations if you build it but don't use it,
+  but you can still disable it to save some compilation time.
 
 enable_ns3 (on/OFF)
   Activates the ns-3 bindings. See section :ref:`models_ns3`.
@@ -252,10 +262,13 @@ enable_ns3 (on/OFF)
 enable_smpi (ON/off)
   Allows one to run MPI code on top of SimGrid.
 
-enable_smpi_MBI_testsuite (on/OFF)
-  Adds many extra tests for the model checker module.
+enable_testsuite_McMini (on/OFF)
+  Adds several extra tests for the model checker module (targeting threaded applications).
+
+enable_testsuite_smpi_MBI (on/OFF)
+  Adds many extra tests for the model checker module (targeting MPI applications).
 
-enable_smpi_MPICH3_testsuite (on/OFF)
+enable_testsuite_smpi_MPICH3 (on/OFF)
   Adds many extra tests for the MPI module.
 
 minimal-bindings (on/OFF)
@@ -267,6 +280,7 @@ NS3_HINT (empty by default)
 
 EIGEN3_HINT (empty by default)
   Alternative path into which Eigen3 should be searched for.
+  Providing the value OFF as an hint will disable the detection alltogether.
 
 SIMGRID_PYTHON_LIBDIR (auto-detected)
   Where to install the Python module library. By default, it is set to the cmake Python3_SITEARCH variable if installing to /usr,
@@ -323,7 +337,7 @@ existing targets are not really for public consumption so don't worry
 if some do not work for you.
 
 - **make**: Build the core of SimGrid that gets installed, but not any example.
-- **make tests**: Build the tests and examples.
+- **make examples**: Build the examples, which are needed by the tests.
 - **make simgrid**: Build only the SimGrid library. Not any example nor the helper tools.
 - **make s4u-comm-pingpong**: Build only this example (works for any example)
 - **make python-bindings**: Build the Python bindings
@@ -399,7 +413,7 @@ Windows-specific instructions
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 The best solution to get SimGrid working on windows is to install the
-Ubuntu subsystem of Windows 10. All of SimGrid (but the model checker)
+Ubuntu subsystem of Windows 10. All of SimGrid 
 works in this setting. Native builds never really worked, and they are
 disabled starting with SimGrid v3.33.
 
@@ -422,3 +436,17 @@ simgrid without downloading the source with pip:
 .. code-block:: console
 
   $ pip install simgrid
+
+If you installed SimGrid to a non-standard directory (such as ``/opt/simgrid`` as advised earlier), you should tell python where
+to find the libraries as follows (notice the elements suffixed to the configured prefix).
+
+.. code-block:: console
+
+  $ PYTHONPATH="/opt/simgrid/lib/python3/dist-packages" LD_LIBRARY_PATH="/opt/simgrid/lib" python your_script.py
+
+You can add those variables to your bash profile to not specify it each time by adding these lines to your ``~/.profile``:
+
+.. code-block:: console
+
+  export PYTHONPATH="$PYTHONPATH:/opt/simgrid/lib/python3/dist-packages"
+  export LD_LIBRARY_PATH="$PYTHONPATH:/opt/simgrid/lib"
index 72c7c4b..32975c9 100644 (file)
@@ -34,8 +34,8 @@ Here are some objectives for which SimGrid is particularly relevant and has been
    quantify an application's performance behavior, but that instead explores all causally possible outcomes of the application so as to evaluate application correctness. This exhaustive
    search is ideal for finding bugs that are difficult to trigger experimentally. But because it is exhaustive, there is a limit to the scale of the applications for which it can be used. 
 
- Anatomy of a project that uses SimGrid
----------------------------------------
+Anatomy of a project that uses SimGrid
+--------------------------------------
 
 Any project that uses SimGrid as its simulation framework comprises the following components:
 
@@ -46,10 +46,8 @@ Any project that uses SimGrid as its simulation framework comprises the followin
    disks, clusters, etc). SimGrid makes it straightforward to augment the simulated platform with dynamic behaviors where, for example, the
    links are slowed down (because of external usage) or the machines fail :ref:`(more info) <platform>`.
 
- - An application's **deployment description**. To simulate the execution
- of the application on the platform, they way in which the application is
- deployed on the platform must be described.  This is done by specifying
- which process is mapped onto which machine :ref:`(more
+ - An application's **deployment description**. To simulate the execution of the application on the platform, they way in which the application is
+   deployed on the platform must be described.  This is done by specifying which process is mapped onto which machine :ref:`(more
    info) <scenario>`.
 
  - **Platform models**. SimGrid implements models that describe how the simulated platform reacts to the simulated activities performed my
index 9b54d2d..e8ee901 100644 (file)
@@ -125,7 +125,7 @@ small delay that corresponds to the end-to-end latency. During that time, the co
 communications are not slowed down, because there is no contention yet).
 
 As an alternative to the above LMM-based models, it is possible to use the :ref:`ns-3 simulator as a network model <models_ns3>`. ns-3 performs
-a mushc more detailed, packet-level simulation 
+a much more detailed, packet-level simulation 
 than the above models. As a result is is much slower but will produce more accurate results. 
 Both simulators have time complexity that is linear in the size of their input, but ns-3 has a much larger input in case of large communications
 because it considers individual network packets. 
@@ -182,15 +182,16 @@ latency-factor is 13.01, bandwidth-factor is 0.97 while weight-S is 20537. Lets
      <link_ctn id="link1" />
    </route>
 
-If host `A` sends ``100kB`` (a hundred kilobytes) to host `B`, one can expect that this communication would take `0.81`
-seconds to complete according to a simple latency-plus-size-divided-by-bandwidth model (0.01 + 8e5/1e6 = 0.81) since the
-latency is small enough to ensure that the physical bandwidth is used (see the discussion on CM02 above). However, the
-LV08 model is more complex to account for three phenomena that directly impact the simulation time:
+If host `A` sends ``100kB`` (a hundred kilobytes, that is, 8e5 bits) to host `B`, one can expect that this communication would
+take `0.81` seconds to complete according to a simple latency-plus-size-divided-by-bandwidth model (0.01 + 8e5/1e6 = 0.81 -- the
+size was converted from bytes to bits) since the latency is small enough to ensure that the physical bandwidth is used (see the
+discussion on CM02 above). However, the LV08 model is more complex to account for three phenomena that directly impact the
+simulation time:
 
   - The size of a message at the application level (i.e., 100kB in this example) is not the size that is actually
     transferred over the network. To mimic the fact that TCP and IP headers are added to each packet of the original
     payload, the TCP model of SimGrid empirically considers that `only 97% of the nominal bandwidth` are available. In
-    other words, the size of your message is increased by a few percents, whatever this size be.
+    other words, the size of your message is increased by a few percents, whichever this size.
 
   - In the real world, the TCP protocol is not able to fully exploit the bandwidth of a link from the emission of the
     first packet. To reflect this `slow start` phenomenon, the latency declared in the platform file is multiplied by
@@ -332,21 +333,26 @@ distributed algorithms such as leader election or causal broadcast.
 ns-3 as a SimGrid model
 ***********************
 
-The **ns-3 based model** is the most accurate network model in SimGrid. It relies on the well-known
-`ns-3 packet-level network simulator <http://www.nsnam.org>`_ to compute full timing information related to network
-transfers. This
-model is much slower than the LMM-based models. This is because ns-3 simulates the movement of every network packet involved in
-every communication, while the LMM-based models only recompute the respective instantaneous speeds of the currently ongoing
-communications when a communication starts or stops.
+The **ns-3 based model** is the most accurate network model in SimGrid. It relies on the well-known `ns-3 packet-level network
+simulator <http://www.nsnam.org>`_ to compute full timing information related to network transfers. This model is much slower
+than the LMM-based models. This is because ns-3 simulates the movement of every network packet involved in every communication,
+while the LMM-based models only recompute the respective instantaneous speeds of the currently ongoing communications when a
+communication starts or stops. In other terms, both SimGrid and ns-3 are fast and highly optimized, but while SimGrid only
+depends on application-level events (starting and stoping of communications), ns-3 depends on network-level events (sending a
+packet).
 
 You need to install ns-3 and recompile SimGrid accordingly to use this model.
 
-The SimGrid/ns-3 binding only contains features that are common to both systems. Not all ns-3 models are available from
-SimGrid (only the TCP and WiFi ones are), while not all SimGrid platform files can be used in conjunction with ns-3
-(routes must be of length 1). Note also that the platform built in ns-3 from the SimGrid
-description is very basic. Finally, communicating from a host to
-itself is forbidden in ns-3, so every such communication is simulated to take zero time.
+The SimGrid/ns-3 binding only contains features that are common to both systems. Not all ns-3 models are available from SimGrid
+(only the TCP and WiFi ones are), while not all SimGrid platform files can be used in conjunction with ns-3 (routes must be of
+length 1). Note also that the platform built in ns-3 from the SimGrid description is very basic. Finally, communicating from a
+host to itself is forbidden in ns-3, so every such communication is simulated to take zero time.
 
+By default, the ns-3 model in SimGrid is not idempotent, unless you patch your version of ns-3 with [this
+patch](https://gitlab.com/nsnam/ns-3-dev/-/merge_requests/1338). It is perfectly OK to have a non-idempotent model in SimGrid as
+long as you only have only one such model, and as long as you don't use utterly advanced things in SimGrid. If you do want to
+have an idempotent ns-3, apply the previously mentioned patch, and recompile SimGrid. It should detect the patch and react
+accordingly.
 
 Compiling the ns-3/SimGrid binding
 ==================================
index 6cc6d75..fe5a7c4 100644 (file)
@@ -110,11 +110,12 @@ Vivaldi
 =======
 
 This routing model is particularly well adapted to Peer-to-Peer and Clouds platforms: each component is connected to the
-cloud through a private link of which the upload and download rate may be asymmetric.
+cloud through a private link whose upload and download rates may be asymmetric.
 
-The network core (between the private links) is assumed to be over-sized so only the latency is taken into account.
-Instead of a matrix of latencies that would become too large when the amount of peers grows, Vivaldi netzones give a
-coordinate to each peer and compute the latency between host A=(xA,yA,zA) and host B=(xB,yB,zB) as follows:
+The network core (between the private links) is assumed to be  over-provisioned so that only the latency has to be
+taken into account. Instead of a matrix of latencies that would become too large when the amount of peers grows,
+Vivaldi netzones give a coordinate to each peer and compute the latency between host A=(xA,yA,zA) and host B=(xB,yB,zB)
+as follows:
 
   latency = sqrt( (xA-xB)² + (yA-yB)² ) + zA + zB
 
index 0594693..aab0fe0 100644 (file)
@@ -23,6 +23,9 @@ documents some of the plugins distributed with SimGrid:
   - :ref:`Host Energy <plugin_host_energy>`: models the energy dissipation of the compute units.
   - :ref:`Link Energy <plugin_link_energy>`: models the energy dissipation of the network.
   - :ref:`WiFi Energy <plugin_link_energy_wifi>`: models the energy dissipation of wifi links.
+  - :ref:`Battery <plugin_battery>`: models batteries that get discharged by the energy consumption of a given host.
+  - :ref:`Solar Panel <plugin_solar_panel>`: models solar panels which energy production depends on the solar irradiance.
+  - :ref:`Chiller <plugin_chiller>`: models chillers which dissipate heat by consuming energy.
 
 You can activate these plugins with the :ref:`--cfg=plugin <cfg=plugin>` command
 line option, for example with ``--cfg=plugin:host_energy``. You can get the full
@@ -67,50 +70,106 @@ kind of objects, please let us now.
 
   Fire that signal, invoking all callbacks.
 
-Partial list of existing signals in s4u:
+.. _s4u_API_signals:
 
-- :cpp:func:`Actor::on_creation <simgrid::s4u::Actor::on_creation_cb>`
+Existing signals
+================
+
+- In actors:
+  :cpp:func:`Actor::on_creation <simgrid::s4u::Actor::on_creation_cb>`
   :cpp:func:`Actor::on_suspend <simgrid::s4u::Actor::on_suspend_cb>`
+  :cpp:func:`Actor::on_this_suspend <simgrid::s4u::Actor::on_this_suspend_cb>`
   :cpp:func:`Actor::on_resume <simgrid::s4u::Actor::on_resume_cb>`
+  :cpp:func:`Actor::on_this_resume <simgrid::s4u::Actor::on_this_resume_cb>`
   :cpp:func:`Actor::on_sleep <simgrid::s4u::Actor::on_sleep_cb>`
+  :cpp:func:`Actor::on_this_sleep <simgrid::s4u::Actor::on_this_sleep_cb>`
   :cpp:func:`Actor::on_wake_up <simgrid::s4u::Actor::on_wake_up_cb>`
+  :cpp:func:`Actor::on_this_wake_up <simgrid::s4u::Actor::on_this_wake_up_cb>`
   :cpp:func:`Actor::on_host_change <simgrid::s4u::Actor::on_host_change_cb>`
+  :cpp:func:`Actor::on_this_host_change <simgrid::s4u::Actor::on_this_host_change_cb>`
   :cpp:func:`Actor::on_termination <simgrid::s4u::Actor::on_termination_cb>`
+  :cpp:func:`Actor::on_this_termination <simgrid::s4u::Actor::on_this_termination_cb>`
   :cpp:func:`Actor::on_destruction <simgrid::s4u::Actor::on_destruction_cb>`
-- :cpp:func:`Comm::on_send <simgrid::s4u::Comm::on_send_cb>`
-  :cpp:func:`Comm::on_recv <simgrid::s4u::Comm::on_recv_cb>`
-  :cpp:func:`Comm::on_completion <simgrid::s4u::Comm::on_completion_cb>`
-- :cpp:func:`CommImpl::on_start <simgrid::s4u::Comm::on_start_cb>`
-  :cpp:func:`CommImpl::on_completion <simgrid::s4u::Comm::on_completion_cb>`
-- :cpp:func:`Disk::on_creation <simgrid::s4u::Disk::on_creation_cb>`
-  :cpp:func:`Disk::on_destruction <simgrid::s4u::Disk::on_destruction_cb>`
-  :cpp:func:`Disk::on_state_change <simgrid::s4u::Disk::on_state_change_cb>`
-- :cpp:func:`Engine::on_platform_creation <simgrid::s4u::Engine::on_platform_creation_cb>`
+- In the engine:
+  :cpp:func:`Engine::on_platform_creation <simgrid::s4u::Engine::on_platform_creation_cb>`
   :cpp:func:`Engine::on_platform_created <simgrid::s4u::Engine::on_platform_created_cb>`
   :cpp:func:`Engine::on_time_advance <simgrid::s4u::Engine::on_time_advance_cb>`
   :cpp:func:`Engine::on_simulation_end <simgrid::s4u::Engine::on_simulation_end_cb>`
   :cpp:func:`Engine::on_deadlock <simgrid::s4u::Engine::on_deadlock_cb>`
-- :cpp:func:`Exec::on_start <simgrid::s4u::Exec::on_start_cb>`
-  :cpp:func:`Exec::on_completion <simgrid::s4u::Exec::on_completion_cb>`
-- :cpp:func:`Host::on_creation <simgrid::s4u::Host::on_creation_cb>`
-  :cpp:func:`Host::on_destruction <simgrid::s4u::Host::on_destruction_cb>`
-  :cpp:func:`Host::on_state_change <simgrid::s4u::Host::on_state_change_cb>`
-  :cpp:func:`Host::on_speed_change <simgrid::s4u::Host::on_speed_change_cb>`
-- :cpp:func:`Io::on_start <simgrid::s4u::Io::on_start_cb>`
-  :cpp:func:`Io::on_completion <simgrid::s4u::Io::on_completion_cb>`
-- :cpp:func:`Link::on_creation <simgrid::s4u::Link::on_creation_cb>`
-  :cpp:func:`Link::on_destruction <simgrid::s4u::Link::on_destruction_cb>`
-  :cpp:func:`Link::on_state_change <simgrid::s4u::Link::on_state_change_cb>`
-  :cpp:func:`Link::on_speed_change <simgrid::s4u::Link::on_bandwidth_change_cb>`
-  :cpp:func:`Link::on_communication_state_change <simgrid::s4u::Link::on_communication_state_change_cb>`
-- :cpp:func:`NetZone::on_creation <simgrid::s4u::NetZone::on_creation_cb>`
-  :cpp:func:`NetZone::on_seal <simgrid::s4u::NetZone::on_seal_cb>`
-- :cpp:func:`VirtualMachine::on_start <simgrid::s4u::VirtualMachine::on_start_cb>`
-  :cpp:func:`VirtualMachine::on_started <simgrid::s4u::VirtualMachine::on_started_cb>`
-  :cpp:func:`VirtualMachine::on_suspend <simgrid::s4u::VirtualMachine::on_suspend_cb>`
-  :cpp:func:`VirtualMachine::on_resume <simgrid::s4u::VirtualMachine::on_resume_cb>`
-  :cpp:func:`VirtualMachine::on_migration_start <simgrid::s4u::VirtualMachine::on_migration_start_cb>`
-  :cpp:func:`VirtualMachine::on_migration_end <simgrid::s4u::VirtualMachine::on_migration_end_cb>`
+
+- In resources:
+
+  - :cpp:func:`Disk::on_creation <simgrid::s4u::Disk::on_creation_cb>`
+    :cpp:func:`Disk::on_destruction <simgrid::s4u::Disk::on_destruction_cb>`
+    :cpp:func:`Disk::on_this_destruction <simgrid::s4u::Disk::on_this_destruction_cb>`
+    :cpp:func:`Disk::on_onoff <simgrid::s4u::Disk::on_onoff_cb>`
+    :cpp:func:`Disk::on_this_onoff <simgrid::s4u::Disk::on_this_onoff_cb>`
+  - :cpp:func:`Host::on_creation <simgrid::s4u::Host::on_creation_cb>`
+    :cpp:func:`Host::on_destruction <simgrid::s4u::Host::on_destruction_cb>`
+    :cpp:func:`Host::on_this_destruction <simgrid::s4u::Host::on_this_destruction_cb>`
+    :cpp:func:`Host::on_onoff <simgrid::s4u::Host::on_onoff_cb>`
+    :cpp:func:`Host::on_this_onoff <simgrid::s4u::Host::on_this_onoff_cb>`
+    :cpp:func:`Host::on_speed_change <simgrid::s4u::Host::on_speed_change_cb>`
+    :cpp:func:`Host::on_this_speed_change <simgrid::s4u::Host::on_this_speed_change_cb>`
+    :cpp:func:`Host::on_exec_state_change <simgrid::s4u::Host::on_exec_state_change_cb>`
+  - :cpp:func:`Link::on_creation <simgrid::s4u::Link::on_creation_cb>`
+    :cpp:func:`Link::on_destruction <simgrid::s4u::Link::on_destruction_cb>`
+    :cpp:func:`Link::on_this_destruction <simgrid::s4u::Link::on_this_destruction_cb>`
+    :cpp:func:`Link::on_onoff <simgrid::s4u::Link::on_onoff_cb>`
+    :cpp:func:`Link::on_this_onoff <simgrid::s4u::Link::on_this_onoff_cb>`
+    :cpp:func:`Link::on_bandwidth_change <simgrid::s4u::Link::on_bandwidth_change_cb>`
+    :cpp:func:`Link::on_this_bandwidth_change <simgrid::s4u::Link::on_this_bandwidth_change_cb>`
+    :cpp:func:`Link::on_communication_state_change <simgrid::s4u::Link::on_communication_state_change_cb>`
+
+  - :cpp:func:`NetZone::on_creation <simgrid::s4u::NetZone::on_creation_cb>`
+    :cpp:func:`NetZone::on_seal <simgrid::s4u::NetZone::on_seal_cb>`
+  - :cpp:func:`VirtualMachine::on_start <simgrid::s4u::VirtualMachine::on_start_cb>`
+    :cpp:func:`VirtualMachine::on_this_start <simgrid::s4u::VirtualMachine::on_this_start_cb>`
+    :cpp:func:`VirtualMachine::on_started <simgrid::s4u::VirtualMachine::on_started_cb>`
+    :cpp:func:`VirtualMachine::on_this_started <simgrid::s4u::VirtualMachine::on_this_started_cb>`
+    :cpp:func:`VirtualMachine::on_suspend <simgrid::s4u::VirtualMachine::on_suspend_cb>`
+    :cpp:func:`VirtualMachine::on_this_suspend <simgrid::s4u::VirtualMachine::on_this_suspend_cb>`
+    :cpp:func:`VirtualMachine::on_resume <simgrid::s4u::VirtualMachine::on_resume_cb>`
+    :cpp:func:`VirtualMachine::on_this_resume <simgrid::s4u::VirtualMachine::on_this_resume_cb>`
+    :cpp:func:`VirtualMachine::on_migration_start <simgrid::s4u::VirtualMachine::on_migration_start_cb>`
+    :cpp:func:`VirtualMachine::on_this_migration_start <simgrid::s4u::VirtualMachine::on_this_migration_start_cb>`
+    :cpp:func:`VirtualMachine::on_migration_end <simgrid::s4u::VirtualMachine::on_migration_end_cb>`
+    :cpp:func:`VirtualMachine::on_this_migration_end <simgrid::s4u::VirtualMachine::on_this_migration_end_cb>`
+
+- In activities:
+
+  - :cpp:func:`Comm::on_send <simgrid::s4u::Comm::on_send_cb>`
+    :cpp:func:`Comm::on_recv <simgrid::s4u::Comm::on_recv_cb>`
+  - :cpp:func:`Comm::on_start <simgrid::s4u::Comm::on_start_cb>`
+    :cpp:func:`Comm::on_this_start <simgrid::s4u::Comm::on_this_start_cb>`
+    :cpp:func:`Comm::on_completion <simgrid::s4u::Comm::on_completion_cb>`
+    :cpp:func:`Comm::on_this_completion <simgrid::s4u::Comm::on_this_completion_cb>`
+    :cpp:func:`Comm::on_suspended <simgrid::s4u::Comm::on_suspended_cb>`
+    :cpp:func:`Comm::on_this_suspended <simgrid::s4u::Comm::on_this_suspended_cb>`
+    :cpp:func:`Comm::on_resume <simgrid::s4u::Comm::on_resume_cb>`
+    :cpp:func:`Comm::on_this_resumed <simgrid::s4u::Comm::on_this_resumed_cb>`
+    :cpp:func:`Comm::on_veto <simgrid::s4u::Comm::on_veto_cb>`
+    :cpp:func:`Comm::on_this_veto <simgrid::s4u::Comm::on_this_veto_cb>`
+  - :cpp:func:`Exec::on_start <simgrid::s4u::Exec::on_start_cb>`
+    :cpp:func:`Exec::on_this_start <simgrid::s4u::Exec::on_this_start_cb>`
+    :cpp:func:`Exec::on_completion <simgrid::s4u::Exec::on_completion_cb>`
+    :cpp:func:`Exec::on_this_completion <simgrid::s4u::Exec::on_this_completion_cb>`
+    :cpp:func:`Exec::on_suspended <simgrid::s4u::Exec::on_suspended_cb>`
+    :cpp:func:`Exec::on_this_suspended <simgrid::s4u::Exec::on_this_suspended_cb>`
+    :cpp:func:`Exec::on_resume <simgrid::s4u::Exec::on_resume_cb>`
+    :cpp:func:`Exec::on_this_resume <simgrid::s4u::Exec::on_this_resume_cb>`
+    :cpp:func:`Exec::on_veto <simgrid::s4u::Exec::on_veto_cb>`
+    :cpp:func:`Exec::on_this_veto <simgrid::s4u::Exec::on_this_veto_cb>`
+  - :cpp:func:`Io::on_start <simgrid::s4u::Io::on_start_cb>`
+    :cpp:func:`Io::on_this_start <simgrid::s4u::Io::on_this_start_cb>`
+    :cpp:func:`Io::on_completion <simgrid::s4u::Io::on_completion_cb>`
+    :cpp:func:`Io::on_this_completion <simgrid::s4u::Io::on_this_completion_cb>`
+    :cpp:func:`Io::on_suspended <simgrid::s4u::Io::on_suspended_cb>`
+    :cpp:func:`Io::on_this_suspended <simgrid::s4u::Io::on_this_suspended_cb>`
+    :cpp:func:`Io::on_resume <simgrid::s4u::Io::on_resume_cb>`
+    :cpp:func:`Io::on_this_resumed <simgrid::s4u::Io::on_this_resumed_cb>`
+    :cpp:func:`Io::on_veto <simgrid::s4u::Io::on_veto_cb>`
+    :cpp:func:`Io::on_this_veto <simgrid::s4u::Io::on_this_veto_cb>`
 
 Existing Plugins
 ****************
@@ -150,8 +209,6 @@ Host Load
 
 .. doxygengroup:: plugin_host_load
 
-
-
 .. _plugin_filesystem:
 
 File System
@@ -159,5 +216,25 @@ File System
 
 .. doxygengroup:: plugin_filesystem
 
+.. _plugin_battery:
+
+Battery
+=======
+
+.. doxygengroup:: plugin_battery
+
+.. _plugin_solar_panel:
+
+Solar Panel
+===========
+
+.. doxygengroup:: plugin_solar_panel
+
+.. _plugin_chiller:
+
+Chiller
+=======
+
+.. doxygengroup:: plugin_chiller
 
 ..  LocalWords:  SimGrid
index 495ad65..8e06554 100644 (file)
@@ -568,15 +568,20 @@ Hopefully in the next release.
 Finally, this release mostly entails maintenance work **on the model front**: a bug was fixed when using ptasks on multicore hosts, and the legacy
 stochastic generator of external load has been reintroduced.
 
-Version 3.33 (not released yet)
--------------------------------
+Version 3.33 (never released)
+-----------------------------
+
+This version was overdue for more than 6 months, so it was skipped to not hinder our process of deprecating old code.
+
+Version 3.34 (June 26. 2023)
+----------------------------
 
-**On the maintainance front,** we removed the ancient MSG interface which end-of-life was scheduled for 2020, the Java bindings
+**On the maintenance front,** we removed the ancient MSG interface which end-of-life was scheduled for 2020, the Java bindings
 that was MSG-only, support for native builds on Windows (WSL is now required) and support for 32 bits platforms. Keeping SimGrid
 alive while adding new features require to remove old, unused stuff. The very rare users impacted by these removals are urged to
 move to the new API and systems.
 
-We also conducted many internal refactorings to remove any occurence of "surf" and "simix". SimGrid v3.12 used a layered design
+We also conducted many internal refactorings to remove any occurrence of "surf" and "simix". SimGrid v3.12 used a layered design
 where simix was providing synchronizations to actors, on top of surf which was computing the models. These features are now
 provided in modules, not layers. Surf became the kernel::{lmm, resource, routing, timer, xml} modules while simix became
 the kernel::{activity, actor, context} modules.
@@ -589,13 +594,16 @@ the other models do. The *fair bottleneck* solver is convenient, but with less s
 development of its replacement (the *bmf solver*) is still ongoing. However, this combination of I/Os and
 communications seemed easier as these activities share the same unit (bytes).
 
-After a few tentatives, we opted for a simple, slightly unperfect, yet convenient way to implement such I/O streams
-at the kernel level. It doesn't require a new model, just that the default HostModels implements a new function which
-creates a classical NetworkAction, but add some I/O-related constraints to it. A couple little hacks here and there,
-and done! A single activity mixing I/Os and communications can be created whose progress is limited by the resource
-(Disk or Link) of least bandwidth value.
+After a few tentatives, we opted for a simple, slightly imperfect, yet convenient way to implement such I/O streams at the
+kernel level. It doesn't require a new model, just that the default HostModels implements a new function which creates a
+classical NetworkAction, but add some I/O-related constraints to it. A couple little hacks here and there, and done! A single
+activity mixing I/Os and communications can be created whose progress is limited by the resource (Disk or Link) of least
+bandwidth value. As a result, a new :cpp:func:`Io::streamto()` function has been added to send data between arbitrary disks or
+hosts. The user can specify a ``src_disk`` on a ``src_host`` and a ``dst_disk`` on a ``dst_host`` to stream data of a
+given ``size``. Note that disks are optional, allowing users to simulate some kind of "disk-to-memory" or "memory-to-disk" I/O
+streams. It's highly inspired by the existing :cpp:func:`Comm::sendto` that can be used to send data between arbitrary hosts.
 
-We also modified the Wi-Fi model so that the total capacity of a link depends on the amout of flows on that link, accordingly to
+We also modified the Wi-Fi model so that the total capacity of a link depends on the amount of flows on that link, accordingly to
 the result of some ns-3 experiments. This model can be more accurate for congestioned Wi-Fi links, but its calibration is more
 demanding, as shown in the `example
 <https://framagit.org/simgrid/simgrid/tree/master/teshsuite/models/wifi_usage_decay/wifi_usage_decay.cpp>`_ and in the `research
@@ -603,29 +611,145 @@ paper <https://hal.archives-ouvertes.fr/hal-03777726>`_.
 
 We also worked on the usability of our models, by actually writing the long overdue documentation of our TCP models and by renaming
 some options for clarity (old names are still accepted as aliases). A new function ``s4u::Engine::flatify_platform()`` dumps an
-XML representation that is inefficient (all zones are flatified) but easier to read (routes are explicitely defined). You should
+XML representation that is inefficient (all zones are flatified) but easier to read (routes are explicitly defined). You should
 not use the output as a regular input file, but it will prove useful to double-check the your platform.
 
-**On the interface front**, the new ``Io::streamto()`` function has been inspired by the existing ``Comm::sendto()``
-function (which also derives from the ptask model). The user can specify a ``src_disk`` on a ``src_host`` and a
-``dst_disk`` on a ``dst_host`` to stream data of a given ``size``. Note that disks are optional, allowing users to
-simulate some kind of "disk-to-memory" or "memory-to-disk" I/O streams.
-
-As usual on that front, some functions were deprecated and will be removed in 4 versions, while some old deprecated functions
-were removed in this version.
-
-**On the model checking front**, we are almost done with the ongoing refactoring to ensure that the model-checker don't read
-directly the memory of the application beside checkpoint/restore and state equality. Instead, the network protocol is used to
-retrieve the information, which makes the code much easier to read and understand. We fixed a bug in the DPOR reduction which
-resulted in some failures to be missed by the exploration, but our quick fix hindered the reduction quality. As a result, some
-scenarios which could be explored completely earlier (with bugs) are now too large for our (correct) exploration algorithm. We
-should improve DPOR in the next release, possibly implementing the ODPOR variant (Optimal DPOR). Also, we started implementing
-the UDPOR (Unfoldings DPOR) reduction algorithm, also for the next release.
+**On the interface front**, some functions were deprecated and will be removed in 4 versions, while some old deprecated functions
+were removed in this version, as usual.
+
+Expressing your application as a DAG or a workflow is even more integrated than before. We added a new tutorial on simulating
+DAGs and a DAG loader for workflows using the `wfcommons formalism <https://wfcommons.org/>`_. Starting an activity is now
+properly delayed until after all its dependencies are fulfilled. We also added a notion of :ref:`Task <API_s4u_Tasks>`, a sort
+of activity that can be fired several time. It's very useful to represent complex workflows. We added a ``on_this`` variant of
+:ref:`every signal <s4u_API_signals>`, to react to the signals emitted by one object instance only. This is sometimes easier than
+reacting to every signals of a class, and then filtering on the object you want. Activity signals (veto, suspend, resume,
+completion) are now specialized by activity class. That is, callbacks registered in Exec::on_suspend_cb will not be fired for
+Comms nor Ios
+
+Three new useful plugins were added: The :ref:`battery plugin<plugin_battery>` can be used to create batteries that get discharged
+by the energy consumption of a given host, the :ref:`solar panel plugin <plugin_solar_panel>` can be used to create
+solar panels which energy production depends on the solar irradiance and the :ref:`chiller plugin <plugin_chiller>` can be used to
+create chillers and compensate the heat generated by hosts. These plugins could probably be better integrated
+in the framework, but our goal is to include in SimGrid the building blocks upon which everybody would agree, while the model
+elements that are more arguable are provided as plugins, in the hope that the users will carefully assess the plugins and adapt
+them to their specific needs before usage. Here for example, there is several models of batteries (the one provided does not
+take the aging into account), and would not be adapted to every studies.
+
+It is now easy to mix S4U actors and SMPI applications, or even to start more than one MPI application in a given simulation
+with the :ref:`SMPI_app_instance_start() <SMPI_mix_s4u>` function.
+
+**On the model checking front**, this release brings a huge load of good improvements. First, we finished the long refactoring
+so that the model-checker only reads the memory of the application for state equality (used for liveness checking) and for
+:ref:`stateful checking <cfg=model-check/checkpoint>`. Instead, the network protocol is used to retrieve the information and the
+application is simply forked to explore new execution branches. The code is now easier to read and to understand. Even better,
+the verification of safety properties is now enabled by default on every platforms since it does not depend on advanced OS
+mechanisms anymore. You can even run the verified application in valgrind in that case. On the other hand, liveness checking
+still needs to be enabled at compile time if you need it. Tbh, this part of the framework is not very well maintained nowadays.
+We should introduce more testing of the liveness verification at some point to fix this situation.
+
+Back on to safety verification, we fixed a bug in the DPOR reduction which resulted in some failures to be missed by the
+exploration, but this somewhat hinders the reduction quality (as we don't miss branches anymore). Some scenarios which could be
+exhaustively explored earlier (with our buggy algorithm) are now too large for our (correct) exploration algorithm. But that's
+not a problem because we implemented several mechanism to improve the performance of the verification. First, we implemented
+source sets in DPOR, to blacklist transitions that are redundant with previously explored ones. Then, we implemented several new
+DPOR variants. SDPOR and ODPOR are very efficient algorithms described in the paper "Source Sets: A Foundation for Optimal
+Dynamic Partial Order Reduction" by Abdulla et al in 2017. We also have an experimental implementation of UPDOR, described in
+the paper "Unfolding-based Partial Order Reduction" by Rodriguez et al in 2015, but it's not completely functional yet. We hope
+to finish it for the next release. And finally, we implemented a guiding mechanism trying to converge faster toward the bugs in
+the reduced state space. We have some naive heuristics, and we hope to provide better ones in the next release.
 
 We also extended the sthread module, which allows to intercept simple code that use pthread mutex and semaphores to simulate and
 verify it. You do not even need to recompile your code, as it uses LD_PRELOAD to intercept on the target functions. This module
-is still rather young, but it could already reveal useful to verify the code written by students in a class on UNIX IPC and
-synchronization. Check `the examples <https://framagit.org/simgrid/simgrid/tree/master/examples/sthread>`_.
+is still rather young, but it could probably be useful already, e.g. to verify the code written by students in a class on UNIX
+IPC and synchronization. Check `the examples <https://framagit.org/simgrid/simgrid/tree/master/examples/sthread>`_. In addition,
+sthread can now also check concurrent accesses to a given collection, loosely inspired from `this paper
+<https://www.microsoft.com/en-us/research/publication/efficient-and-scalable-thread-safety-violation-detection-finding-thousands-of-concurrency-bugs-during-testing>`_.
+This feature is not very usable yet, as you have to manually annotate your code, but we hope to improve it in the future.
+
+Version 3.35 (November 23. 2023)
+--------------------------------
+
+**On the performance front**, we did some profiling and optimisation for this release. We saved some memory in simulation
+mixing MPI applications and S4U actors, and we greatly improved the performance of simulation exchanging many messages. We even
+introduced a new abstraction called MessageQueue and associated Mess simulated object to represent control messages in a very
+efficient way. When using MessageQueue and Mess instead of Mailboxes and Comms, information is automagically transported over
+thin air between producer and consumer in no simulated time. The implementation is much simpler, yielding much better
+performance. Indeed, this abstraction solves a scalability issue observed in the WRENCH framework, which is heavily based on
+control messages.
+
+
+**On the interface front**, we introduced a new abstraction called ActivitySets. It makes it easy to interact with a bag of
+mixed activities, waiting for the next occurring one, or for the completion of the whole set. This feature already existed in
+SimGrid, but was implemented in a crude way with vectors of activities and static functions. It is also much easier than earlier
+to mix several kinds of activities in activity sets.
+
+We introduced a new plugin called JBOD (just a bunch of disks), that proves useful to represent a sort of hosts gathering many
+disks. We also revamped the battery, photovoltaic and chiller plugins introduced in previous release to make it even easier to
+study green computing scenarios. On a similar topic, we eased the expression of vertical scaling with the :ref:`Task
+<API_s4u_Tasks>`, the repeatable activities introduced in the previous release that can be used to represent microservices
+applications.
+
+We not only added new abstractions and plugins, but also polished the existing interfaces. For example, the declaration of
+multi-zoned platforms was greatly simplified by adding methods with fewer parameters to cover the common cases, leaving the
+complete methods for the more advanced use cases (see the ChangeLog for details). Another difficulty in the earlier interface
+was related to :ref:`Mailbox::get_async()` which used to require the user to store the payload somewhere on her side. Instead,
+it is now possible to retrieve the payload from the communication object once it's over with :ref:`Comm::get_payload()`.
+
+Finally on the SMPI front, we introduced :ref:`SMPI_app_instance_join()` to wait for the completion of a started MPI instance.
+This enables further mixture of MPI codes and controlled by S4U applications and plugins. We are currently considering
+implementing some MPI4 calls, but nothing happened so far.
+
+**On the model-checking front**, the first big news is that we completely removed the liveness checker from the code base. This
+is unfortunate, but the truth is that this code was very fragile and not really tested.
+
+For the context, liveness checking is the part of model checking that can determine whether the studied system always terminates
+(absence of infinite loops, called non-progression loops in this context), or whether the system can reach a desirable state in
+a finite time (for example, when you press the button, you want the elevator to come eventually). This relies on the ability to
+detect loops in the execution, most often through the detection that this system state was already explored earlier. SimGrid
+relied on tricks and heuristics to detect such state equality by leveraging debug information meant for gdb or valgrind. It
+kinda worked, but was very fragile because neither this information nor the compilation process are meant for state equality
+evaluation. Not zeroing the memory induces many crufty bits, for example in the padding bytes of the data structures or on the
+stack. This can be solved by only comparing the relevant bits (as instructed by the debug information), but this process was
+rather slow. Detecting equality in the heap was even more hackish, as we usually don't have any debug information about the
+memory blocks retrieved from malloc(). This prevents any introspection into these blocks, which is problematic because the order
+of malloc calls will create states that are syntactically different (the blocks are not in the same location in memory) but
+semantically equivalent (the data meaning rarely depends on the block location itself). The heuristics we used here were so
+crude that I don't want to detail them here.
+
+If liveness checking were to be re-implemented nowadays, I would go for a compiler-aided approach. I would maybe use a compiler
+plugin to save the type of malloced blocks as in `Compiler-aided type tracking for correctness checking of MPI applications
+<https://scholar.google.com/citations?view_op=view_citation&citation_for_view=dRhZFBsAAAAJ:9yKSN-GCB0IC>`_ and zero the stack on
+call returns to ease introspection. We could even rely on a complete introspection mechanism such as `MetaCPP
+<https://github.com/mlomb/MetaCPP>`_ or similar. We had a great piece of code to checkpoint millions of states in a
+memory-efficient way. It was able to detect the common memory pages between states, and only save the modified ones. I guess
+that this would need to be exhumed from the git when reimplementing liveness checking in SimGrid. But I doubt that we will
+happen anytime soon, as we concentrate our scarce manpower on other parts. In particular, safety checking is about searching for
+failed assertions by inspecting each state. A counter example to a safety property is simply a state where the assertion failed
+/ the property is violated. A counter example to a liveness property is an infinite execution path that violates the property.
+In some sense, safety checking is much easier than liveness checking, but it's already very powerful to exhaustively test an
+application.
+
+In this release, we made several interesting progress on the safety side of model checking. First, we ironed out many bugs in
+the ODPOR exploration algorithm (and dependency and reversible race theorems on which it relies). ODPOR should now be usable,
+and it's much faster than our previous DPOR reduction. We also extended sthread a bit, by adding many tests from the McMini tool
+and by implementing pthread barriers and conditionals. It seems to work rather well with C codes using pthreads and with C++
+codes using the standard library. You can even use sthread on a process running in valgrind or gdb.
+
+Unfortunately, conditionals cannot be verified so far by the model checker, because our implementation of condition variables is
+still synchronous. Our reduction algorithms are optimized because we know that all transitions of our computation model are
+persistent: once a transition gets enabled, it remains so until it's actually fired. This enables to build upon previous
+computations, while everything must be recomputed in each state when previously enabled transitions can get disabled by an
+external event. Unfortunately, this requires that every activity is written in an asynchronous way. You first declare your
+intent to lock that mutex in an asynchronous manner, and then wait for the ongoing_acquisition object. Once a given acquisition
+is granted, it will always remain so even if another actor creates another acquisition on the same mutex. This is the equivalent
+of asynchronous communications that are common in MPI, but for mutex locks, barriers and semaphores. The thing that is missing
+to verify pthread_cond in sthread is that I didn't manage to write an asynchronous version of the condition variables. We have an
+almost working code lying around, but it fails for timed waits on condition variables. This will probably be part of the next
+release.
+
+Version 3.36 (TBD)
+------------------
+
 
 .. |br| raw:: html
 
index 20f31c4..bb06f09 100644 (file)
@@ -33,7 +33,7 @@ of source files.
    cmake_minimum_required(VERSION 2.8.12)
    project(MyFirstSimulator)
 
-   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
+   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
 
    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
    find_package(SimGrid REQUIRED)
@@ -58,16 +58,33 @@ manually but your project will produce relevant error messages when
 trying to compile on a machine where SimGrid is not installed. Please
 also refer to the file header for more information.
 
-MPI projects should include ``find_package (MPI)`` in CMakeLists.txt. Then, the
-variables ``MPI_C_COMPILER``, ``MPI_CXX_COMPILER``, and ``MPI_Fortran_COMPILER`` should
-point to the full path of smpicc, smpicxx, and smpiff respectively.
-It is however not advised to set these variables from the CMakeLists.txt file directly.
-In addition, you may need to set ``SMPI_PRETEND_CC=1`` to please cmake when it tests the compiler.
+MPI projects should NOT search for MPI as usual in cmake, but instead use the ``smpi_c_target()`` macro
+to declare that a given target is meant to be executed in ``smpirun`` (which path is set in ``${SMPIRUN}``).
+This macro should work for C and C++ programs. Here is a small example:
+
+.. code-block:: cmake
+
+   # Search FindSimgrid in my sources
+   set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}")
+   find_package(SimGrid)
+
+   # Declare an executable, and specify that it's meant to run within smpirun
+   add_executable(roundtrip roundtrip.c)
+   smpi_c_target(roundtrip)
+
+   # Declare a test running our executable in ${SMPIRUN}
+   enable_testing()
+   add_test(NAME RoundTrip
+            COMMAND ${SMPIRUN} -platform ${CMAKE_SOURCE_DIR}/../cluster_backbone.xml -np 2 ./roundtrip)
+
+To compile Fortran code with cmake, you must override the ``MPI_Fortran_COMPILER`` variable as follows, but it will probably
+break some configuration checks, so you should export ``SMPI_PRETEND_CC=1`` during the configuration (not during the compilation
+nor the execution).
 
 .. code-block:: console
 
    $ SMPI_PRETEND_CC=1 cmake -DMPI_C_COMPILER=/opt/simgrid/bin/smpicc -DMPI_CXX_COMPILER=/opt/simgrid/bin/smpicxx -DMPI_Fortran_COMPILER=/opt/simgrid/bin/smpiff .
-
+   $ make
 
 Building your project with Makefile
 -----------------------------------
@@ -124,7 +141,7 @@ Develop in C++ with Eclipse
 If you wish to develop your plugin or modify SimGrid using
 Eclipse. You have to run cmake and import it as a Makefile project.
 
-Next, you have to activate C++14 in your build settings, add -std=c++14
+Next, you have to activate C++17 in your build settings, add -std=c++17
 in the CDT GCC Built-in compiler settings.
 
 .. image:: /img/eclipseScreenShot.png
index e807cc4..4bddc09 100644 (file)
@@ -3,7 +3,7 @@
 Simulating DAG
 ==============
 
-This tutorial presents the basics to understand how DAG are represented in Simgrid and how to simulate their workflow. 
+This tutorial presents the basics to understand how DAG are represented in SimGrid and how to simulate their workflow.
 
 Definition of a DAG
 -------------------
@@ -26,7 +26,7 @@ Set of edges representing precedence constraints between :ref:`Activities <API_s
 
    \mathcal{E} = {e_i,j | (i,j) \in {1, ..., V} x {1, ..., V}}
 
-.. image:: /tuto_dag/img/dag.svg
+.. image:: /img/dag.svg
    :align: center
 
 Representing Vertices/Activities
@@ -58,7 +58,7 @@ Representing Edges/Dependencies
 
 An activity will not start until all of its dependencies have been completed.
 Activities may have any number of successors.
-Dependencies between Activities are created using :cpp:func:`Activity::add_successor(ActivityPtr)`.
+Dependencies between Activities are created using :cpp:func:`simgrid::s4u::Activity::add_successor`.
 
 .. code-block:: cpp
 
@@ -71,118 +71,92 @@ Lab 1: Basics
 
 The goal of this lab is to describe the following DAG: 
 
-.. image:: /tuto_dag/img/dag1.svg
+.. image:: /img/dag1.svg
    :align: center
 
 In this DAG we want ``c1`` to compute 1e9 flops, ``c2`` to compute 5e9 flops and ``c3`` to compute 2e9 flops. 
 There is also a data transfer of 5e8 bytes between ``c1`` and ``c3``.
 
-First of all, include the Simgrid library and define the log category.
+First of all, include the SimGrid library and define the log category.
 
-.. code-block:: cpp
-
-   #include "simgrid/s4u.hpp"
-
-   XBT_LOG_NEW_DEFAULT_CATEGORY(main, "Messages specific for this s4u tutorial");
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 6-8
 
 Inside the ``main`` function create an instance of :ref:`Engine <API_s4u_Engine>` and load the platform.
 
-.. code-block:: cpp
-
-    simgrid::s4u::Engine e(&argc, argv);
-    e.load_platform(argv[1]);
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 12-13
 
 Retrieve pointers to some hosts.
 
-.. code-block:: cpp
-
-    simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
-    simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 15-16
 
 Initiate the activities.
 
-.. code-block:: cpp
-
-    simgrid::s4u::ExecPtr c1 = simgrid::s4u::Exec::init();
-    simgrid::s4u::ExecPtr c2 = simgrid::s4u::Exec::init();
-    simgrid::s4u::ExecPtr c3 = simgrid::s4u::Exec::init();
-    simgrid::s4u::CommPtr t1 = simgrid::s4u::Comm::sendto_init();
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 18-21
 
 Give names to thoses activities.
 
-.. code-block:: cpp
-
-    c1->set_name("c1");
-    c2->set_name("c2");
-    c3->set_name("c3");
-    t1->set_name("t1");
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 23-26
 
 Set the amount of work for each activity.
 
-.. code-block:: cpp
-
-    c1->set_flops_amount(1e9);
-    c2->set_flops_amount(5e9);
-    c3->set_flops_amount(2e9);
-    t1->set_payload_size(5e8);
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 28-31
 
 Define the dependencies between the activities.
 
-.. code-block:: cpp
-
-    c1->add_successor(t1);
-    t1->add_successor(c3);
-    c2->add_successor(c3);
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 33-35
 
 Set the location of each Exec activity and source and destination for the Comm activity.
 
-.. code-block:: cpp
-
-    c1->set_host(tremblay);
-    c2->set_host(jupiter);
-    c3->set_host(jupiter);
-    t1->set_source(tremblay);
-    t1->set_destination(jupiter);
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 37-41
 
 Start the executions of Activities without dependencies.
 
-.. code-block:: cpp
-
-    c1->start();
-    c2->start();
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 43-44
 
 Add a callback to monitor the activities.
 
-.. code-block:: cpp
-
-   Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-      XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", activity.get_cname(), activity.get_start_time(),
-               activity.get_finish_time());
-      });
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 46-49
 
 Finally, run the simulation.
 
-.. code-block:: cpp
-
-   e.run();
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.cpp
+   :language: cpp
+   :lines: 51
 
 The execution of this code should give you the following output:
 
-.. code-block:: bash
-
-   [10.194200] [main/INFO] Activity 'c1' is complete (start time: 0.000000, finish time: 10.194200)
-   [65.534235] [main/INFO] Activity 'c2' is complete (start time: 0.000000, finish time: 65.534235)
-   [85.283378] [main/INFO] Activity 't1' is complete (start time: 10.194200, finish time: 85.283378)
-   [111.497072] [main/INFO] Activity 'c3' is complete (start time: 85.283378, finish time: 111.497072)
+.. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.tesh
+   :language: none
+   :lines: 4-
 
 Lab 2: Import a DAG from a file
----------------
+-------------------------------
 
-In this lab we present how to import a DAG into you Simgrid simulation, either using a DOT file, a JSON file, or a DAX file. 
+In this lab we present how to import a DAG into you SimGrid simulation, either using a DOT file, a JSON file, or a DAX file.
 
 The files presented in this lab describe the following DAG:
 
-.. image:: /tuto_dag/img/dag2.svg
+.. image:: /img/dag2.svg
    :align: center
 
 From a DOT file
@@ -192,227 +166,245 @@ A DOT file describes a workflow in accordance with the graphviz format.
 
 The following DOT file describes the workflow presented at the beginning of this lab:
 
-.. code-block:: xml
+.. literalinclude:: ../../examples/cpp/dag-from-dot-simple/dag.dot
+   :language: dot
 
-   digraph G {
-      c1 [size="1e9"];
-      c2 [size="5e9"];
-      c3 [size="2e9"];
+It can be imported as a vector of Activities into SimGrid using :cpp:func:`simgrid::s4u::create_DAG_from_DOT`. Then, you have to assign hosts to your Activities.
 
-      root->c1 [size="2e8"];
-      root->c2 [size="1e8"];
-      c1->c3   [size="5e8"];
-      c2->c3   [size="-1"];
-      c3->end  [size="2e8"];
-   }
+.. literalinclude:: ../../examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.cpp
+   :language: cpp
 
-It can be imported as a vector of Activities into Simgrid using :cpp:func:`create_DAG_from_DOT(const std::string& filename)`. Then, you have to assign hosts to your Activities.
+The execution of this code should give you the following output:
 
-.. code-block:: cpp
+.. literalinclude:: ../../examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.tesh
+   :language: none
+   :lines: 4-
 
-   #include "simgrid/s4u.hpp"
+From a JSON file
+................
 
-   XBT_LOG_NEW_DEFAULT_CATEGORY(main, "Messages specific for this s4u example");
+A JSON file describes a workflow in accordance with the `wfformat <https://github.com/wfcommons/wfformat>`_ .
 
-   int main(int argc, char* argv[]) {
-      simgrid::s4u::Engine e(&argc, argv);
-      e.load_platform(argv[1]);
+The following JSON file describes the workflow presented at the beginning of this lab:
 
-      std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_dot(argv[2]);
+.. literalinclude:: ../../examples/cpp/dag-from-json-simple/dag.json
+   :language: json
 
-      simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
-      simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
-      simgrid::s4u::Host* fafard  = e.host_by_name("Fafard");
+It can be imported as a vector of Activities into SimGrid using :cpp:func:`simgrid::s4u::create_DAG_from_json`.
 
-      dynamic_cast<simgrid::s4u::Exec*>(dag[0].get())->set_host(fafard);
-      dynamic_cast<simgrid::s4u::Exec*>(dag[1].get())->set_host(tremblay);
-      dynamic_cast<simgrid::s4u::Exec*>(dag[2].get())->set_host(jupiter);
-      dynamic_cast<simgrid::s4u::Exec*>(dag[3].get())->set_host(jupiter);
-      dynamic_cast<simgrid::s4u::Exec*>(dag[8].get())->set_host(jupiter);
-    
-      for (const auto& a : dag) {
-         if (auto* comm = dynamic_cast<simgrid::s4u::Comm*>(a.get())) {
-               auto pred = dynamic_cast<simgrid::s4u::Exec*>((*comm->get_dependencies().begin()).get());
-               auto succ = dynamic_cast<simgrid::s4u::Exec*>(comm->get_successors().front().get());
-               comm->set_source(pred->get_host())->set_destination(succ->get_host());
-         }
-      }
+.. literalinclude:: ../../examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.cpp
+   :language: cpp
 
-      simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-      XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", activity.get_cname(), activity.get_start_time(),
-             activity.get_finish_time());
-      });
+The execution of this code should give you the following output:
 
-      e.run();
-      return 0;
-   }
+.. literalinclude:: ../../examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.tesh
+   :language: none
+   :lines: 4-
 
-The execution of this code should give you the following output:
+From a DAX file [deprecated]
+............................
 
-.. code-block:: bash
+A DAX file describes a workflow in accordance with the `Pegasus <http://pegasus.isi.edu/>`_ format.
 
-   [0.000000] [main/INFO] Activity 'root' is complete (start time: 0.000000, finish time: 0.000000)
-   [33.394394] [main/INFO] Activity 'root->c2' is complete (start time: 0.000000, finish time: 33.394394)
-   [39.832311] [main/INFO] Activity 'root->c1' is complete (start time: 0.000000, finish time: 39.832311)
-   [50.026511] [main/INFO] Activity 'c1' is complete (start time: 39.832311, finish time: 50.026511)
-   [98.928629] [main/INFO] Activity 'c2' is complete (start time: 33.394394, finish time: 98.928629)
-   [125.115689] [main/INFO] Activity 'c1->c3' is complete (start time: 50.026511, finish time: 125.115689)
-   [151.329383] [main/INFO] Activity 'c3' is complete (start time: 125.115689, finish time: 151.329383)
-   [151.743605] [main/INFO] Activity 'c3->end' is complete (start time: 151.329383, finish time: 151.743605)
-   [151.743605] [main/INFO] Activity 'end' is complete (start time: 151.743605, finish time: 151.743605)
+The following DAX file describes the workflow presented at the beginning of this lab:
 
-From a JSON file
-................
+.. literalinclude:: ../../examples/cpp/dag-from-dax-simple/dag.xml
+   :language: xml
 
-A JSON file describes a workflow in accordance with the `wfformat <https://github.com/wfcommons/wfformat>`_ .
+It can be imported as a vector of Activities into SimGrid using :cpp:func:`simgrid::s4u::create_DAG_from_DAX`.
 
-The following JSON file describes the workflow presented at the beginning of this lab:
+.. literalinclude:: ../../examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.cpp
+   :language: cpp
 
-.. code-block:: JSON
+Lab 3: Scheduling with the Min-Min algorithm
+--------------------------------------------
 
-   {
-      "name": "simple_json",
-      "schemaVersion": "1.0",
-      "workflow": {
-         "makespan": 0,
-         "executedAt": "2023-03-09T00:00:00-00:00",
-         "tasks": [
-         {
-            "name": "c1",
-            "type": "compute",
-            "parents": [],
-            "runtime": 1e9,
-            "machine": "Tremblay"
-         },
-         {
-            "name": "t1",
-            "type": "transfer",
-            "parents": ["c1"],
-            "bytesWritten": 5e8,
-            "machine": "Jupiter"
-         },
-         {
-            "name": "c2",
-            "type": "compute",
-            "parents": [],
-            "runtime": 5e9,
-            "machine": "Jupiter"
-         },
-         {
-            "name": "c3",
-            "type": "compute",
-            "parents": ["t1","c2"],
-         "runtime": 2e9,
-         "machine": "Jupiter"
-         }
-         ],
-         "machines": [
-            {"nodeName": "Tremblay"},
-            {"nodeName": "Jupiter"}
-         ]
-      }
-   }
+In this lab we present how to schedule activities imported from a DAX file using the 
+`Min-Min algorithm <https://www.researchgate.net/figure/The-Traditional-Min-Min-Scheduling-Algorithm_fig5_236346423>`_.
+
+The source code for this lab can be found `here <https://framagit.org/simgrid/simgrid/-/blob/stable/examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp>`_.
 
-It can be imported as a vector of Activities into Simgrid using :cpp:func:`create_DAG_from_json(const std::string& filename)`. 
+For code readability we first create the `sg4` namespace.
 
 .. code-block:: cpp
 
-   #include "simgrid/s4u.hpp"
+   namespace sg4 = simgrid::s4u;
 
-   XBT_LOG_NEW_DEFAULT_CATEGORY(main, "Messages specific for this s4u example");
+The core mechanism of the algorithm lies in three functions. 
+They respectively serve the purpose of finding tasks to schedule, 
+finding the best host to execute them and properly scheduling them.
 
-   int main(int argc, char* argv[]) {
-      simgrid::s4u::Engine e(&argc, argv);
-      e.load_platform(argv[1]);
+Find Tasks to Schedule
+......................
 
-      std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_json(argv[2]);
+The role of this function is to retrieve tasks that are ready to be scheduled, i.e, that have their dependencies solved.
 
-      simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-      XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", activity.get_cname(), activity.get_start_time(),
-             activity.get_finish_time());
-      });
+.. literalinclude:: ../../examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
+   :language: cpp
+   :lines: 15-38
 
-      e.run();
-      return 0;
-   }
+Find the Best Placement
+.......................
 
-The execution of this code should give you the following output:
+Once we have a task ready to be scheduled, we need to find the best placement for it.
+This is done by evaluating the earliest finish time among all hosts.
+It depends on the duration of the data transfers of the parents of this task to this host.
 
-.. code-block:: bash
+.. literalinclude:: ../../examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
+   :language: cpp
+   :lines: 40-91
 
-   [10.194200] [main/INFO] Activity 'c1' is complete (start time: 0.000000, finish time: 10.194200)
-   [65.534235] [main/INFO] Activity 'c2' is complete (start time: 0.000000, finish time: 65.534235)
-   [85.283378] [main/INFO] Activity 't1' is complete (start time: 10.194200, finish time: 85.283378)
-   [111.497072] [main/INFO] Activity 'c3' is complete (start time: 85.283378, finish time: 111.497072)
+Schedule a Task
+...............
 
-From a DAX file [deprecated]
-............................
+When the best host has been found, the task is scheduled on it:
 
-A DAX file describes a workflow in accordance with the `Pegasus <http://pegasus.isi.edu/>`_ format.
+* it sets the host of the task to schedule
+* it stores the finish time of this task on the host
+* it sets the destination of parents communication
+* it sets the source of any child communication.
 
-The following DAX file describes the workflow presented at the beginning of this lab:
+.. literalinclude:: ../../examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
+   :language: cpp
+   :lines: 93-113
+
+Mixing it all Together
+......................
 
-.. code-block:: xml
-
-   <?xml version="1.0" encoding="UTF-8"?>
-   <adag xmlns="http://pegasus.isi.edu/schema/DAX" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-      xsi:schemaLocation="http://pegasus.isi.edu/schema/DAX http://pegasus.isi.edu/schema/dax-2.1.xsd"
-      version="2.1">
-      <job id="1" name="c1" runtime="10">
-         <uses file="i1" link="input" register="true" transfer="true" optional="false" type="data" size="2e8"/>
-         <uses file="o1" link="output" register="true" transfer="true" optional="false" type="data" size="5e8"/>
-      </job>
-      <job id="2" name="c2" runtime="50">
-         <uses file="i2" link="input" register="true" transfer="true" optional="false" type="data" size="1e8"/>
-      </job>
-      <job id="3" name="c3" runtime="20">
-         <uses file="o1" link="input" register="true" transfer="true" optional="false" type="data" size="5e8"/>
-         <uses file="o3" link="output" register="true" transfer="true" optional="false" type="data" size="2e8"/>
-      </job>
-      <child ref="3">
-         <parent ref="1"/>
-         <parent ref="2"/>
-      </child>
-   </adag>
-
-It can be imported as a vector of Activities into Simgrid using :cpp:func:`create_DAG_from_DAX(std::string)`.
+Now that we have the key components of the algorithm let's merge them inside the main function.
 
 .. code-block:: cpp
 
-   #include "simgrid/s4u.hpp"
+   int main(int argc, char** argv)
+   {
+   ...
+
+First, we initialize the SimGrid Engine.
 
-   XBT_LOG_NEW_DEFAULT_CATEGORY(main, "Messages specific for this s4u example");
+.. code-block:: cpp
 
-   int main(int argc, char* argv[]) {
-      simgrid::s4u::Engine e(&argc, argv);
-      e.load_platform(argv[1]);
+   sg4::Engine e(&argc, argv);
 
-      std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_DAX(argv[2]);
+The Min-Min algorithm schedules unscheduled tasks. 
+To keep track of them we make use of the method :cpp:func:`simgrid::s4u::Engine::track_vetoed_activities`.
 
-      simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
-      simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
-      simgrid::s4u::Host* fafard  = e.host_by_name("Fafard");
+.. code-block:: cpp
 
-      dynamic_cast<simgrid::s4u::Exec*>(dag[0].get())->set_host(fafard);
-      dynamic_cast<simgrid::s4u::Exec*>(dag[1].get())->set_host(tremblay);
-      dynamic_cast<simgrid::s4u::Exec*>(dag[2].get())->set_host(jupiter);
-      dynamic_cast<simgrid::s4u::Exec*>(dag[3].get())->set_host(jupiter);
-      dynamic_cast<simgrid::s4u::Exec*>(dag[8].get())->set_host(jupiter);
-    
-      for (const auto& a : dag) {
-         if (auto* comm = dynamic_cast<simgrid::s4u::Comm*>(a.get())) {
-            auto pred = dynamic_cast<simgrid::s4u::Exec*>((*comm->get_dependencies().begin()).get());
-            auto succ = dynamic_cast<simgrid::s4u::Exec*>(comm->get_successors().front().get());
-            comm->set_source(pred->get_host())->set_destination(succ->get_host());
-         }
+   std::set<sg4::Activity*> vetoed;
+   e.track_vetoed_activities(&vetoed);
+
+We add the following callback that will be triggered at the end of execution activities.
+This callback stores the finish time of the execution, 
+to use it as a start time for any subsequent communications.
+
+.. code-block:: cpp
+
+  sg4::Activity::on_completion_cb([](sg4::Activity const& activity) {
+    // when an Exec completes, we need to set the potential start time of all its ouput comms
+    const auto* exec = dynamic_cast<sg4::Exec const*>(&activity);
+    if (exec == nullptr) // Only Execs are concerned here
+      return;
+    for (const auto& succ : exec->get_successors()) {
+      auto* comm = dynamic_cast<sg4::Comm*>(succ.get());
+      if (comm != nullptr) {
+        auto* finish_time = new double(exec->get_finish_time());
+        // We use the user data field to store the finish time of the predecessor of the comm, i.e., its potential start
+        // time
+        comm->set_data(finish_time);
       }
+    }
+  });
+
+We load the platform and force sequential execution on hosts.
 
-      simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-      XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", activity.get_cname(), activity.get_start_time(),
-         activity.get_finish_time());
-      });
+.. code-block:: cpp
+
+   e.load_platform(argv[1]);
+
+  /* Mark all hosts as sequential, as it ought to be in such a scheduling example.
+   *
+   * It means that the hosts can only compute one thing at a given time. If an execution already takes place on a given
+   * host, any subsequently started execution will be queued until after the first execution terminates */
+  for (auto const& host : e.get_all_hosts()) {
+    host->set_concurrency_limit(1);
+    host->set_data(new double(0.0));
+  }
+
+The tasks are imported from a DAX file.
+
+.. code-block:: cpp
 
+  /* load the DAX file */
+  auto dax = sg4::create_DAG_from_DAX(argv[2]);
+
+We look for the best host for the root task and schedule it. 
+We then advance the simulation to unlock next schedulable tasks.
+
+.. code-block:: cpp
+
+  /* Schedule the root first */
+  double finish_time;
+  auto* root = static_cast<sg4::Exec*>(dax.front().get());
+  auto host  = get_best_host(root, &finish_time);
+  schedule_on(root, host);
+  e.run();
+
+Then, we get to the major loop of the algorithm.
+This loop goes on until all tasks have been scheduled and executed.
+It starts by finding ready tasks using `get_ready_tasks`. 
+It iteratively looks for the task that will finish first among ready tasks using `get_best_host`, and place it using `schedule_on`. 
+When no more tasks can be placed, we advance the simulation.
+
+.. code-block:: cpp
+
+  while (not vetoed.empty()) {
+    XBT_DEBUG("Start new scheduling round");
+    /* Get the set of ready tasks */
+    auto ready_tasks = get_ready_tasks(dax);
+    vetoed.clear();
+
+    if (ready_tasks.empty()) {
+      /* there is no ready exec, let advance the simulation */
       e.run();
-      return 0;
-   }
+      continue;
+    }
+    /* For each ready exec:
+     * get the host that minimizes the completion time.
+     * select the exec that has the minimum completion time on its best host.
+     */
+    double min_finish_time   = std::numeric_limits<double>::max();
+    sg4::Exec* selected_task = nullptr;
+    sg4::Host* selected_host = nullptr;
+
+    for (auto exec : ready_tasks) {
+      XBT_DEBUG("%s is ready", exec->get_cname());
+      double finish_time;
+      host = get_best_host(exec, &finish_time);
+      if (finish_time < min_finish_time) {
+        min_finish_time = finish_time;
+        selected_task   = exec;
+        selected_host   = host;
+      }
+    }
+
+    XBT_INFO("Schedule %s on %s", selected_task->get_cname(), selected_host->get_cname());
+    schedule_on(selected_task, selected_host, min_finish_time);
+
+    ready_tasks.clear();
+    e.run();
+  }
+
+Finally, we clean up the memory.
+
+.. code-block:: cpp
+
+   /* Cleanup memory */
+   for (auto const& h : e.get_all_hosts())
+     delete h->get_data<double>();
+
+
+
+
+
+
 
index 03bf0a0..4e01642 100644 (file)
@@ -4,7 +4,7 @@ Formal Verification and Model-checking
 ======================================
 
 SimGrid can not only predict the performance of your application, but also assess its correctness through formal methods. Mc SimGrid is
-a full-featured model-checker that is embedded in the SimGrid framework. It can be used to formally verify safety and liveness
+a full-featured model-checker that is embedded in the SimGrid framework. It can be used to formally verify safety 
 properties on codes running on top of SimGrid, be it :ref:`simple algorithms <usecase_simalgo>` or :ref:`full MPI applications
 <usecase_smpi>`.
 
@@ -31,7 +31,7 @@ barrier, etc). Since it does not explicitly observe memory accesses, Mc SimGrid
 multithreaded programs. It can however be used to detect misuses of the synchronization functions, such as the ones resulting in
 deadlocks.
 
-Mc SimGrid can be used to verify classical `safety and liveness properties <https://en.wikipedia.org/wiki/Linear_time_property>`_, but
+Mc SimGrid can be used to verify classical `safety properties <https://en.wikipedia.org/wiki/Linear_time_property>`_, but
 also `communication determinism <https://hal.inria.fr/hal-01953167/document>`_, a property that allows more efficient solutions toward
 fault-tolerance. It can alleviate the state space explosion problem through `Dynamic Partial Ordering Reduction (DPOR)
 <https://en.wikipedia.org/wiki/Partial_order_reduction>`_ and `state equality <https://hal.inria.fr/hal-01900120/document>`_. Note that
@@ -308,11 +308,6 @@ If you want to run such analysis on your own code, out of the provided docker, t
 - SimGrid should naturally :ref:`be compiled <install_src>` with model-checking support. This requires a full set of dependencies
   (documented on the :ref:`relevant page <install_src>`) and should not be activated by default as there is a small performance penalty for
   codes using a SimGrid with MC enabled (even if you don't activate the model-checking at run time).
-- You should pass some specific flags to the linker when compiling your application: ``-Wl,-znorelro -Wl,-znoseparate-code`` In the
-  docker, the provided CMakeLists.txt provides them for you when compiling the provided code. ``smpicc`` and friends also add this
-  parameter automatically.
-- If you get error messages complaining about the Dwarf version used, try adding ``-gdwarf-4`` to you CFLAGS and CXXFLAGS.
-  If you find a situation where this flag is needed in ``smpicc``, please report this issue.
 - Also install ``libboost-stacktrace-dev`` to display nice backtraces from the application side (the one from the model-checking side is
   available in any case, but it contains less details).
 - Mc SimGrid uses the ``ptrace`` system call to spy on the verified application. Some versions of Docker forbid the use of this call by
@@ -324,11 +319,12 @@ Going further
 -------------
 
 This tutorial is not complete yet, as there is nothing on reduction
-techniques nor on liveness properties. For now, the best source of
+techniques. For now, the best source of
 information on these topics is `this old tutorial
 <https://simgrid.org/tutorials/simgrid-mc-101.pdf>`_ and `that old
 presentation
-<http://people.irisa.fr/Martin.Quinson/blog/2018/0123/McSimGrid-Boston.pdf>`_.
+<http://people.irisa.fr/Martin.Quinson/blog/2018/0123/McSimGrid-Boston.pdf>`_. But be warned that these source of 
+information are very old: the liveness verification was removed in v3.35, even if these docs still mention it.
 
 .. |br| raw:: html
 
index 7d3d6b0..ff648e0 100644 (file)
@@ -82,6 +82,7 @@ provides many helper functions to simplify the code of actors.
       - :ref:`class Comm <API_s4u_Comm>`: Communication activity, started on Mailboxes and consuming links.
       - :ref:`class Exec <API_s4u_Exec>`: Computation activity, started on Host and consuming CPU resources.
       - :ref:`class Io <API_s4u_Io>`: I/O activity, started on and consuming disks.
+      - :ref:`class ActivtySet <API_s4u_ActivitySet>`: Bag of activities, to wait for any of the set, or all of them.
 
    - **Synchronization Objects**: Classical IPC that actors can use
 
@@ -96,6 +97,9 @@ provides many helper functions to simplify the code of actors.
 .. |API_s4u_Activities| replace:: **Activities**
 .. _API_s4u_Activities: #api-s4u-activity
 
+.. |API_s4u_Tasks| replace:: **Tasks**
+.. _API_s4u_Tasks: #api-s4u-task
+
 .. |API_s4u_Hosts| replace:: **Hosts**
 .. _API_s4u_Hosts: #api-s4u-host
 
@@ -162,38 +166,55 @@ Every kind of activity can be asynchronous.
 :cpp:func:`s4u::Disk::write_async() <simgrid::s4u::Disk::write_async>`; and
 :ref:`s4u::ExecPtr <API_s4u_Exec>` are created with
 :cpp:func:`s4u::Host::exec_async() <simgrid::s4u::Host::exec_async>`.
-In the future, it will become possible to have asynchronous IPC such as asynchronous mutex lock requests.
-
-The following example shows how to have several concurrent
-communications ongoing.  First, you have to declare a vector in which
-we will store the ongoing communications. It is also useful to have a
-vector of mailboxes.
-
-.. literalinclude:: ../../examples/cpp/comm-waitall/s4u-comm-waitall.cpp
-   :language: c++
-   :start-after: init-begin
-   :end-before: init-end
-   :dedent: 2
-
-Then, you start all the communications that should occur concurrently with
-:cpp:func:`s4u::Mailbox::put_async() <simgrid::s4u::Mailbox::put_async>`.
-Finally, the actor waits for the completion of all of them at once
-with :cpp:func:`s4u::Comm::wait_all() <simgrid::s4u::Comm::wait_all>`.
-
-.. literalinclude:: ../../examples/cpp/comm-waitall/s4u-comm-waitall.cpp
-   :language: c++
-   :start-after: put-begin
-   :end-before: put-end
-   :dedent: 2
+In the future, it will become possible to have asynchronous IPC such as asynchronous mutex lock requests (it is already possible
+internally, but the interface is not exposed in S4U yet).
+
+If you want for the completion of any activity in a given set, to react to the earlier occuring completion, then you need an
+:ref:`activity set <API_s4u_ActivitySet>`. Please refer to the :ref:`relevant examples <s4u_ex_activityset>` for more information.
 
 =====================
-Activities Life cycle
+Activities Life Cycle
 =====================
 
 Sometimes, you want to change the setting of an activity before it even starts.
 
 .. todo:: write this section
 
+=====================
+Repeatable Activities
+=====================
+
+In order to simulate the execution of Dataflow applications, we introduced the
+concept of |API_s4u_Tasks|, that can be seen as repeatable activities. A Dataflow
+is defined as a graph of |API_s4u_Tasks|, where each |API_s4u_Tasks| has a set of
+successors and predecessors. When a |API_s4u_Tasks| ends it sends a token to each
+of its successors. Each |API_s4u_Tasks| has to receive a token from each of its
+predecessor to start. Tokens can carry any user-defined data.
+
+|API_s4u_Tasks| are composed of several instances: a dispatcher, a collector, and
+instance_0 to instance_n. The dispatcher rely on a load balancing function to select
+the next instance to fire. Once this instance finishes it fires the collector.
+
+Each instance of an |API_s4u_ExecTask| can be placed on a different host.
+|API_s4u_Comm| activities are automatically created when an instance triggers
+another instance on a different host. Each instance has its own parallelism degree
+to scale horizontally on several cores.
+
+To initiate the execution of a Dataflow, it is possible to some make
+|API_s4u_Tasks| fire one or more activities without waiting for any token with the
+:cpp:func:`s4u::Task::enqueue_firings() <simgrid::s4u::Task::enqueue_firings>`
+function.
+
+The parameters of Tasks can be redefined at runtime by attaching
+callbacks to the
+:cpp:func:`s4u::Task::on_this_start <simgrid::s4u::Task::on_this_start>`
+and
+:cpp:func:`s4u::Task::on_this_completion <simgrid::s4u::Task::on_this_completion>`
+signals. The former is triggered by instances others than the dispatcher and the collector,
+and the latter is triggered by the collector.
+
+
+
 .. _s4u_mailbox:
 
 Mailboxes
@@ -241,8 +262,8 @@ on the data you want to get from the mailbox. To model such settings
 in SimGrid, you'd have one mailbox per potential topic, and subscribe
 to each topic individually with a
 :cpp:func:`get_async() <simgrid::s4u::Mailbox::get_async>` on each mailbox.
-Then, use :cpp:func:`Comm::wait_any() <simgrid::s4u::Comm::wait_any>`
-to get the first message on any of the mailboxes you are subscribed to.
+Then, use an :ref:`class ActivtySet <API_s4u_ActivitySet>` to get the first
+message on any of the mailboxes you are subscribed to.
 
 The mailboxes are not located on the network, and you can access
 them without any latency. The network delays are only related to the
@@ -450,6 +471,8 @@ See also :ref:`the relevant example <s4u_ex_actors_create>`.
 
    .. group-tab:: C
 
+      .. doxygentypedef:: xbt_main_func_t
+
       .. doxygenfunction:: sg_actor_create(const char *name, sg_host_t host, xbt_main_func_t code, int argc, char *const *argv)
       .. doxygenfunction:: sg_actor_init(const char *name, sg_host_t host)
       .. doxygenfunction:: sg_actor_start(sg_actor_t actor, xbt_main_func_t code, int argc, char *const *argv)
@@ -612,12 +635,19 @@ Signals
 
       .. doxygenfunction:: simgrid::s4u::Actor::on_creation_cb
       .. doxygenfunction:: simgrid::s4u::Actor::on_suspend_cb
+      .. doxygenfunction:: simgrid::s4u::Actor::on_this_suspend_cb
       .. doxygenfunction:: simgrid::s4u::Actor::on_host_change_cb
+      .. doxygenfunction:: simgrid::s4u::Actor::on_this_host_change_cb
       .. doxygenfunction:: simgrid::s4u::Actor::on_resume_cb
+      .. doxygenfunction:: simgrid::s4u::Actor::on_this_resume_cb
       .. doxygenfunction:: simgrid::s4u::Actor::on_sleep_cb
+      .. doxygenfunction:: simgrid::s4u::Actor::on_this_sleep_cb
       .. doxygenfunction:: simgrid::s4u::Actor::on_wake_up_cb
+      .. doxygenfunction:: simgrid::s4u::Actor::on_this_wake_up_cb
       .. doxygenfunction:: simgrid::s4u::Actor::on_termination_cb
+      .. doxygenfunction:: simgrid::s4u::Actor::on_this_termination_cb
       .. doxygenfunction:: simgrid::s4u::Actor::on_destruction_cb
+      .. doxygenfunction:: simgrid::s4u::Actor::on_this_destruction_cb
 
 .. _API_s4u_this_actor:
 
@@ -798,7 +828,6 @@ Engin initialization
 
       .. doxygenfunction:: simgrid::s4u::Engine::Engine(int *argc, char **argv)
       .. doxygenfunction:: simgrid::s4u::Engine::is_initialized()
-      .. doxygenfunction:: simgrid::s4u::Engine::shutdown()
       .. doxygenfunction:: simgrid::s4u::Engine::get_instance()
 
    .. group-tab:: Python
@@ -1171,11 +1200,17 @@ Querying info
       .. doxygenfunction:: simgrid::s4u::Disk::set_property(const std::string &, const std::string &value)
       .. doxygenfunction:: simgrid::s4u::Disk::set_sharing_policy
 
+      .. doxygenenum:: simgrid::s4u::Disk::Operation
+      .. doxygenenum:: simgrid::s4u::Disk::SharingPolicy
+
    .. group-tab:: Python
 
       .. autoattribute:: simgrid.Disk.name
       .. automethod:: simgrid.Disk.set_sharing_policy
 
+      .. autoclass:: simgrid.Disk.Operation
+      .. autoclass:: simgrid.Disk.SharingPolicy
+
 I/O operations
 --------------
 
@@ -1205,7 +1240,9 @@ Signals
 
       .. doxygenfunction:: simgrid::s4u::Disk::on_creation_cb
       .. doxygenfunction:: simgrid::s4u::Disk::on_destruction_cb
-      .. doxygenfunction:: simgrid::s4u::Disk::on_state_change_cb
+      .. doxygenfunction:: simgrid::s4u::Disk::on_this_destruction_cb
+      .. doxygenfunction:: simgrid::s4u::Disk::on_onoff_cb
+      .. doxygenfunction:: simgrid::s4u::Disk::on_this_onoff_cb
 
 
 .. _API_s4u_Host:
@@ -1488,8 +1525,12 @@ Signals
 
       .. doxygenfunction:: simgrid::s4u::Host::on_creation_cb
       .. doxygenfunction:: simgrid::s4u::Host::on_destruction_cb
+      .. doxygenfunction:: simgrid::s4u::Host::on_this_destruction_cb
       .. doxygenfunction:: simgrid::s4u::Host::on_speed_change_cb
-      .. doxygenfunction:: simgrid::s4u::Host::on_state_change_cb
+      .. doxygenfunction:: simgrid::s4u::Host::on_this_speed_change_cb
+      .. doxygenfunction:: simgrid::s4u::Host::on_onoff_cb
+      .. doxygenfunction:: simgrid::s4u::Host::on_this_onoff_cb
+      .. doxygenfunction:: simgrid::s4u::Host::on_exec_state_change_cb
 
 .. _API_s4u_Link:
 
@@ -1542,9 +1583,7 @@ Basic management
          #include <simgrid/link.h>
 
       .. doxygentypedef:: sg_link_t
-      .. cpp:type:: const s4u_Link* const_sg_link_t
-
-         Pointer to a constant link object.
+      .. doxygentypedef:: const_sg_link_t
 
 Retrieving links
 ----------------
@@ -1578,52 +1617,70 @@ Querying info
 
    .. group-tab:: C++
 
-      .. doxygenfunction:: simgrid::s4u::Link::get_bandwidth() const
       .. doxygenfunction:: simgrid::s4u::Link::get_cname() const
-      .. doxygenfunction:: simgrid::s4u::Link::get_latency() const
       .. doxygenfunction:: simgrid::s4u::Link::get_name() const
-      .. doxygenfunction:: simgrid::s4u::Link::get_sharing_policy() const
-      .. doxygenfunction:: simgrid::s4u::Link::get_concurrency_limit() const
-      .. doxygenfunction:: simgrid::s4u::Link::get_usage() const
+      .. doxygenfunction:: simgrid::s4u::Link::get_load() const
       .. doxygenfunction:: simgrid::s4u::Link::is_used() const
 
    .. group-tab:: Python
 
-      .. autoattribute:: simgrid.Link.bandwidth
-      .. autoattribute:: simgrid.Link.latency
+      .. autoattribute:: simgrid.Link.name
 
    .. group-tab:: C
 
-      .. doxygenfunction:: sg_link_get_bandwidth(const_sg_link_t link)
-      .. doxygenfunction:: sg_link_get_latency(const_sg_link_t link)
       .. doxygenfunction:: sg_link_get_name(const_sg_link_t link)
       .. doxygenfunction:: sg_link_is_shared(const_sg_link_t link)
 
-Modifying characteristics
--------------------------
+Performance
+-----------
 
 .. tabs::
 
    .. group-tab:: C++
 
+      .. doxygenfunction:: simgrid::s4u::Link::get_bandwidth() const
+      .. doxygenfunction:: simgrid::s4u::Link::get_latency() const
       .. doxygenfunction:: simgrid::s4u::Link::set_bandwidth(double value)
       .. doxygenfunction:: simgrid::s4u::Link::set_latency(double value)
       .. doxygenfunction:: simgrid::s4u::Link::set_latency(const std::string& value)
-      .. doxygenfunction:: simgrid::s4u::Link::set_concurrency_limit(int limit)
-      .. doxygenfunction:: simgrid::s4u::Link::set_sharing_policy
 
    .. group-tab:: Python
 
+      .. autoattribute:: simgrid.Link.bandwidth
+      .. autoattribute:: simgrid.Link.latency
       .. automethod:: simgrid.Link.set_bandwidth
       .. automethod:: simgrid.Link.set_latency
-      .. automethod:: simgrid.Link.set_concurrency_limit
-      .. automethod:: simgrid.Link.set_sharing_policy
 
    .. group-tab:: C
 
+      .. doxygenfunction:: sg_link_get_bandwidth(const_sg_link_t link)
+      .. doxygenfunction:: sg_link_get_latency(const_sg_link_t link)
       .. doxygenfunction:: sg_link_set_bandwidth(sg_link_t link, double value)
       .. doxygenfunction:: sg_link_set_latency(sg_link_t link, double value)
 
+Model policy
+------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenenum:: simgrid::s4u::Link::SharingPolicy
+
+      .. doxygenfunction:: simgrid::s4u::Link::get_sharing_policy() const
+      .. doxygenfunction:: simgrid::s4u::Link::set_sharing_policy
+         
+      .. doxygenfunction:: simgrid::s4u::Link::get_concurrency_limit() const
+      .. doxygenfunction:: simgrid::s4u::Link::set_concurrency_limit(int limit)
+
+   .. group-tab:: Python
+
+      .. automethod:: simgrid.Link.set_concurrency_limit
+      .. automethod:: simgrid.Link.set_sharing_policy
+
+   .. group-tab:: C
+
+
 User data and properties
 ------------------------
 
@@ -1700,10 +1757,13 @@ Signals
    .. group-tab:: C++
 
       .. doxygenfunction:: simgrid::s4u::Link::on_bandwidth_change_cb
+      .. doxygenfunction:: simgrid::s4u::Link::on_this_bandwidth_change_cb
       .. doxygenfunction:: simgrid::s4u::Link::on_communication_state_change_cb
       .. doxygenfunction:: simgrid::s4u::Link::on_creation_cb
       .. doxygenfunction:: simgrid::s4u::Link::on_destruction_cb
-      .. doxygenfunction:: simgrid::s4u::Link::on_state_change_cb
+      .. doxygenfunction:: simgrid::s4u::Link::on_this_destruction_cb
+      .. doxygenfunction:: simgrid::s4u::Link::on_onoff_cb
+      .. doxygenfunction:: simgrid::s4u::Link::on_this_onoff_cb
 
 .. _API_s4u_NetZone:
 
@@ -1782,7 +1842,7 @@ Querying info
 
       .. doxygenfunction:: simgrid::s4u::NetZone::get_cname() const
       .. doxygenfunction:: simgrid::s4u::NetZone::get_name() const
-      .. doxygenfunction:: simgrid::s4u::NetZone::get_netpoint()
+      .. doxygenfunction:: simgrid::s4u::NetZone::get_netpoint
 
    .. group-tab:: Python
 
@@ -1835,8 +1895,10 @@ Routing data
    .. group-tab:: C++
 
       .. doxygenfunction:: simgrid::s4u::NetZone::add_component(kernel::routing::NetPoint *elm)
-      .. doxygenfunction:: simgrid::s4u::NetZone::add_route
-      .. doxygenfunction:: simgrid::s4u::NetZone::add_bypass_route
+      .. doxygenfunction:: simgrid::s4u::NetZone::add_route(const Host *src, const Host *dst, const std::vector< LinkInRoute > &link_list, bool symmetrical=true)
+      .. doxygenfunction:: simgrid::s4u::NetZone::add_route(const Host *src, const Host *dst, const std::vector< const Link * > &links)
+      .. doxygenfunction:: simgrid::s4u::NetZone::add_route(const NetZone *src, const NetZone *dst, const std::vector< LinkInRoute > &link_list, bool symmetrical=true)
+      .. doxygenfunction:: simgrid::s4u::NetZone::add_route(const NetZone *src, const NetZone *dst, const std::vector< const Link * > &links)
       .. doxygenfunction:: simgrid::s4u::NetZone::get_children() const
       .. doxygenfunction:: simgrid::s4u::NetZone::get_parent() const
       .. doxygenfunction:: simgrid::s4u::NetZone::set_parent(const NetZone* parent)
@@ -1904,6 +1966,10 @@ Hosts
      .. doxygenfunction:: simgrid::s4u::NetZone::create_host(const std::string& name, double speed)
      .. doxygenfunction:: simgrid::s4u::NetZone::create_host(const std::string& name, const std::vector<std::string>& speed_per_pstate)
      .. doxygenfunction:: simgrid::s4u::NetZone::create_host(const std::string& name, const std::string& speed)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_host(const std::string &name, const std::string &speed)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_host(const std::string &name, const std::vector< double > &speed_per_pstate)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_host(const std::string &name, const std::vector< std::string > &speed_per_pstate)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_host(const std::string &name, double speed)
 
   .. group-tab:: Python
 
@@ -1916,12 +1982,12 @@ Links
 
   .. group-tab:: C++
 
-     .. doxygenfunction:: simgrid::s4u::NetZone::create_link(const std::string& name, const std::vector<double>& bandwidths)
-     .. doxygenfunction:: simgrid::s4u::NetZone::create_link(const std::stringname, double bandwidth)
-     .. doxygenfunction:: simgrid::s4u::NetZone::create_link(const std::string& name, const std::vector<std::string>& bandwidthds)
-     .. doxygenfunction:: simgrid::s4u::NetZone::create_link(const std::string& name, const std::string& bandwidth)
-     .. doxygenfunction:: simgrid::s4u::NetZone::create_split_duplex_link(const std::string& name, const std::string& bandwidth)
-     .. doxygenfunction:: simgrid::s4u::NetZone::create_split_duplex_link(const std::stringname, double bandwidth)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_link(const std::string &name, const std::vector< double > &bandwidths)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_link(const std::string &name, double bandwidth)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_link(const std::string &name, const std::vector< std::string > &bandwidths)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_link(const std::string &name, const std::string &bandwidth)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_split_duplex_link(const std::string &name, const std::string &bandwidth)
+     .. doxygenfunction:: simgrid::s4u::NetZone::create_split_duplex_link(const std::string &name, double bandwidth)
 
   .. group-tab:: Python
 
@@ -2046,13 +2112,21 @@ Signals
 
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_creation_cb
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_destruction_cb
+      .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_this_destruction_cb
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_migration_end_cb
+      .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_this_migration_end_cb
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_migration_start_cb
+      .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_this_migration_start_cb
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_resume_cb
+      .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_this_resume_cb
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_shutdown_cb
+      .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_this_shutdown_cb
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_start_cb
+      .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_this_start_cb
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_started_cb
+      .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_this_started_cb
       .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_suspend_cb
+      .. doxygenfunction:: simgrid::s4u::VirtualMachine::on_this_suspend_cb
 
 .. _API_s4u_Activity:
 
@@ -2085,6 +2159,11 @@ Basic management
 
       .. doxygentypedef:: ActivityPtr
 
+   .. group-tab:: C
+
+      .. doxygentypedef:: sg_activity_t
+      .. doxygentypedef:: const_sg_activity_t
+
 Querying info
 -------------
 
@@ -2092,8 +2171,8 @@ Querying info
 
    .. group-tab:: C++
 
-      .. doxygenfunction:: simgrid::s4u::Activity::get_cname
-      .. doxygenfunction:: simgrid::s4u::Activity::get_name
+      .. doxygenfunction:: simgrid::s4u::Activity::get_cname() const
+      .. doxygenfunction:: simgrid::s4u::Activity::get_name() const
       .. doxygenfunction:: simgrid::s4u::Activity::get_remaining() const
       .. doxygenfunction:: simgrid::s4u::Activity::get_state() const
       .. doxygenfunction:: simgrid::s4u::Activity::set_remaining(double remains)
@@ -2113,7 +2192,6 @@ Activities life cycle
       .. doxygenfunction:: simgrid::s4u::Activity::wait
       .. doxygenfunction:: simgrid::s4u::Activity::wait_for
       .. doxygenfunction:: simgrid::s4u::Activity::wait_until(double time_limit)
-      .. doxygenfunction:: simgrid::s4u::Activity::vetoable_start()
 
 Suspending and resuming an activity
 -----------------------------------
@@ -2126,17 +2204,6 @@ Suspending and resuming an activity
       .. doxygenfunction:: simgrid::s4u::Activity::resume
       .. doxygenfunction:: simgrid::s4u::Activity::is_suspended
 
-Signals
--------
-
-.. tabs::
-
-   .. group-tab:: C++
-
-      .. doxygenfunction:: simgrid::s4u::Activity::on_completion_cb
-      .. doxygenfunction:: simgrid::s4u::Activity::on_suspended_cb
-      .. doxygenfunction:: simgrid::s4u::Activity::on_resumed_cb
-
 .. _API_s4u_Comm:
 
 =============
@@ -2242,12 +2309,7 @@ Life cycle
       .. doxygenfunction:: simgrid::s4u::Comm::cancel
       .. doxygenfunction:: simgrid::s4u::Comm::start
       .. doxygenfunction:: simgrid::s4u::Comm::test
-      .. doxygenfunction:: simgrid::s4u::Comm::test_any(const std::vector< CommPtr >& comms)
       .. doxygenfunction:: simgrid::s4u::Comm::wait
-      .. doxygenfunction:: simgrid::s4u::Comm::wait_all(const std::vector< CommPtr >& comms)
-      .. doxygenfunction:: simgrid::s4u::Comm::wait_all_for(const std::vector< CommPtr >& comms, double timeout)
-      .. doxygenfunction:: simgrid::s4u::Comm::wait_any(const std::vector< CommPtr >& comms)
-      .. doxygenfunction:: simgrid::s4u::Comm::wait_any_for(const std::vector< CommPtr >& comms, double timeout)
       .. doxygenfunction:: simgrid::s4u::Comm::wait_for
       .. doxygenfunction:: simgrid::s4u::Comm::wait_until
 
@@ -2256,21 +2318,14 @@ Life cycle
       .. automethod:: simgrid.Comm.cancel
       .. automethod:: simgrid.Comm.start
       .. automethod:: simgrid.Comm.test
-      .. automethod:: simgrid.Comm.test_any
       .. automethod:: simgrid.Comm.wait
       .. automethod:: simgrid.Comm.wait_for
-      .. automethod:: simgrid.Comm.wait_all
-      .. automethod:: simgrid.Comm.wait_all_for
-      .. automethod:: simgrid.Comm.wait_any
-      .. automethod:: simgrid.Comm.wait_any_for
       .. automethod:: simgrid.Comm.wait_until
 
    .. group-tab:: C
 
       .. doxygenfunction:: sg_comm_test
       .. doxygenfunction:: sg_comm_wait
-      .. doxygenfunction:: sg_comm_wait_all
-      .. doxygenfunction:: sg_comm_wait_any
 
 Suspending and resuming a communication
 ---------------------------------------
@@ -2296,10 +2351,22 @@ Signals
 
    .. group-tab:: C++
 
-      .. doxygenfunction:: simgrid::s4u::Comm::on_start_cb
       .. doxygenfunction:: simgrid::s4u::Comm::on_completion_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_start_cb
       .. doxygenfunction:: simgrid::s4u::Comm::on_recv_cb
       .. doxygenfunction:: simgrid::s4u::Comm::on_send_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_suspended_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_suspend_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_resume_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_resumed_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_veto_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_this_completion_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_this_recv_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_this_resume_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_this_send_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_this_start_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_this_suspended_cb
+      .. doxygenfunction:: simgrid::s4u::Comm::on_this_veto_cb
 
 .. _API_s4u_Exec:
 
@@ -2317,6 +2384,11 @@ Signals
 
       .. autoclass:: simgrid.Exec
 
+   .. group-tab:: C
+
+      .. doxygentypedef:: sg_exec_t
+      .. doxygentypedef:: const_sg_exec_t
+
 Basic management
 ----------------
 
@@ -2342,9 +2414,6 @@ Basic management
 
          #include <simgrid/exec.h>
 
-      .. doxygentypedef:: sg_exec_t
-      .. doxygentypedef:: const_sg_exec_t
-
 Querying info
 -------------
 
@@ -2389,9 +2458,6 @@ Life cycle
       .. doxygenfunction:: simgrid::s4u::Exec::start
       .. doxygenfunction:: simgrid::s4u::Exec::test
       .. doxygenfunction:: simgrid::s4u::Exec::wait
-      .. doxygenfunction:: simgrid::s4u::Exec::wait_any(const std::vector< ExecPtr >& execs)
-      .. doxygenfunction:: simgrid::s4u::Exec::wait_any_for(const std::vector< ExecPtr >& execs, double timeout)
-      .. doxygenfunction:: simgrid::s4u::Exec::wait_for
 
    .. group-tab:: Python
 
@@ -2406,9 +2472,6 @@ Life cycle
        .. doxygenfunction:: sg_exec_cancel(sg_exec_t exec);
        .. doxygenfunction:: sg_exec_test(sg_exec_t exec);
        .. doxygenfunction:: sg_exec_wait(sg_exec_t exec);
-       .. doxygenfunction:: sg_exec_wait_for(sg_exec_t exec, double timeout);
-       .. doxygenfunction:: sg_exec_wait_any_for(sg_exec_t* execs, size_t count, double timeout);
-       .. doxygenfunction:: sg_exec_wait_any(sg_exec_t* execs, size_t count);
 
 Suspending and resuming an execution
 ------------------------------------
@@ -2435,7 +2498,14 @@ Signals
    .. group-tab:: C++
 
       .. doxygenfunction:: simgrid::s4u::Exec::on_start_cb
+      .. doxygenfunction:: simgrid::s4u::Exec::on_this_start_cb
       .. doxygenfunction:: simgrid::s4u::Exec::on_completion_cb
+      .. doxygenfunction:: simgrid::s4u::Exec::on_this_completion_cb
+
+      .. doxygenfunction:: simgrid::s4u::Exec::on_suspended_cb
+      .. doxygenfunction:: simgrid::s4u::Exec::on_resumed_cb
+      .. doxygenfunction:: simgrid::s4u::Exec::on_veto_cb
+      .. doxygenfunction:: simgrid::s4u::Exec::on_this_veto_cb
 
 .. _API_s4u_Io:
 
@@ -2487,16 +2557,11 @@ Life cycle
       .. doxygenfunction:: simgrid::s4u::Io::start
       .. doxygenfunction:: simgrid::s4u::Io::test
       .. doxygenfunction:: simgrid::s4u::Io::wait
-      .. doxygenfunction:: simgrid::s4u::Io::wait_for
-      .. doxygenfunction:: simgrid::s4u::Io::wait_any(const std::vector<IoPtr> &ios)
-      .. doxygenfunction:: simgrid::s4u::Io::wait_any_for(const std::vector<IoPtr> &ios, double timeout)
 
    .. group-tab:: Python
 
       .. automethod:: simgrid.Io.test
       .. automethod:: simgrid.Io.wait
-      .. automethod:: simgrid.Io.wait_any_for
-      .. automethod:: simgrid.Io.wait_any
 
 Signals
 -------
@@ -2506,7 +2571,336 @@ Signals
    .. group-tab:: C++
 
       .. doxygenfunction:: simgrid::s4u::Io::on_start_cb
+      .. doxygenfunction:: simgrid::s4u::Io::on_this_start_cb
       .. doxygenfunction:: simgrid::s4u::Io::on_completion_cb
+      .. doxygenfunction:: simgrid::s4u::Io::on_this_completion_cb
+
+      .. doxygenfunction:: simgrid::s4u::Io::on_suspended_cb
+      .. doxygenfunction:: simgrid::s4u::Io::on_resumed_cb
+      .. doxygenfunction:: simgrid::s4u::Io::on_veto_cb
+      .. doxygenfunction:: simgrid::s4u::Io::on_this_veto_cb
+
+.. _API_s4u_ActivitySet:
+
+====================
+⁣  class ActivitySet
+====================
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenclass:: simgrid::s4u::ActivitySet
+
+   .. group-tab:: Python
+
+      .. autoclass:: simgrid.ActivitySet
+
+   .. group-tab:: C
+
+      .. doxygentypedef:: sg_activity_set_t
+      .. doxygentypedef:: const_sg_activity_set_t
+
+Basic management
+----------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. code-block:: C++
+
+         #include <simgrid/s4u/ActivitySet.hpp>
+
+      .. doxygentypedef:: ActivitySetPtr
+
+   .. group-tab:: Python
+
+      .. code:: Python
+
+         from simgrid import ActivitySet
+
+   .. group-tab:: C
+
+      .. code-block:: C
+
+         #include <simgrid/activity_set.h>
+
+      .. doxygenfunction:: sg_activity_set_init
+      .. doxygenfunction:: sg_activity_set_delete
+
+Managing activities
+-------------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::push
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::erase
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::empty
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::size
+
+   .. group-tab:: Python
+
+      .. automethod:: simgrid.ActivitySet.push()
+      .. automethod:: simgrid.ActivitySet.erase()
+      .. automethod:: simgrid.ActivitySet.empty()
+      .. automethod:: simgrid.ActivitySet.size()
+
+   .. group-tab:: c
+
+      .. doxygenfunction:: sg_activity_set_push
+      .. doxygenfunction:: sg_activity_set_erase
+      .. doxygenfunction:: sg_activity_set_empty
+      .. doxygenfunction:: sg_activity_set_size
+
+Interacting with the set
+------------------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::test_any
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::wait_all
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::wait_all_for
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::wait_any
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::wait_any_for
+
+   .. group-tab:: Python
+
+      .. automethod:: simgrid.ActivitySet.test_any()
+      .. automethod:: simgrid.ActivitySet.wait_all()
+      .. automethod:: simgrid.ActivitySet.wait_all_for()
+      .. automethod:: simgrid.ActivitySet.wait_any()
+      .. automethod:: simgrid.ActivitySet.wait_any_for()
+
+   .. group-tab:: c
+
+      .. doxygenfunction:: sg_activity_set_test_any
+      .. doxygenfunction:: sg_activity_set_wait_all
+      .. doxygenfunction:: sg_activity_set_wait_all_for
+      .. doxygenfunction:: sg_activity_set_wait_any
+      .. doxygenfunction:: sg_activity_set_wait_any_for
+      .. doxygenfunction:: sg_activity_unref
+
+Dealing with failed activities
+------------------------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::get_failed_activity()
+      .. doxygenfunction:: simgrid::s4u::ActivitySet::has_failed_activities()
+
+.. _API_s4u_Tasks:
+
+==========
+Tasks
+==========
+
+==============
+class Task
+==============
+
+.. doxygenclass:: simgrid::s4u::Task
+
+**Known subclasses:**
+:ref:`Communication Tasks <API_s4u_CommTask>`,
+:ref:`Executions Tasks <API_s4u_ExecTask>`,
+:ref:`I/O Tasks <API_s4u_IoTask>`.
+See also the :ref:`section on activities <s4u_Tasks>` above.
+
+Basic management
+----------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. code-block:: C++
+
+         #include <simgrid/s4u/Task.hpp>
+
+      .. doxygentypedef:: TaskPtr
+
+Querying info
+-------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenfunction:: simgrid::s4u::Task::get_cname() const
+      .. doxygenfunction:: simgrid::s4u::Task::get_name() const
+      .. doxygenfunction:: simgrid::s4u::Task::get_count(std::string instance) const
+      .. doxygenfunction:: simgrid::s4u::Task::get_amount(std::string instance) const
+      .. doxygenfunction:: simgrid::s4u::Task::get_queued_firings(std::string instance) const
+      .. doxygenfunction:: simgrid::s4u::Task::get_running_count(std::string instance) const
+      .. doxygenfunction:: simgrid::s4u::Task::get_parallelism_degree(std::string instance) const
+      .. doxygenfunction:: simgrid::s4u::Task::set_name(std::string name)
+
+Life cycle
+----------
+
+.. tabs::
+
+   .. group-tab:: C++
+      .. doxygenfunction:: simgrid::s4u::Task::enqueue_firings(int n)
+      .. doxygenfunction:: simgrid::s4u::Task::set_amount(double amount, std::string instance)
+      .. doxygenfunction:: simgrid::s4u::Task::set_parallelism_degree(int n, std::string instance)
+
+Managing Dependencies
+---------------------
+
+.. tabs::
+
+   .. group-tab:: C++
+      .. doxygenfunction:: simgrid::s4u::Task::add_successor(TaskPtr t)
+      .. doxygenfunction:: simgrid::s4u::Task::remove_successor(TaskPtr t)
+      .. doxygenfunction:: simgrid::s4u::Task::remove_all_successors()
+      .. doxygenfunction:: simgrid::s4u::Task::get_successors() const
+
+Managing Tokens
+---------------
+
+.. doxygenclass:: simgrid::s4u::Token
+
+.. tabs::
+
+   .. group-tab:: C++
+      .. doxygenfunction:: simgrid::s4u::Task::get_token_from(TaskPtr t) const
+      .. doxygenfunction:: simgrid::s4u::Task::get_tokens_from(TaskPtr t) const
+      .. doxygenfunction:: simgrid::s4u::Task::deque_token_from(TaskPtr t)
+      .. doxygenfunction:: simgrid::s4u::Task::set_token(std::shared_ptr<Token> token)
+
+Signals
+-------
+
+.. tabs::
+
+   .. group-tab:: C++
+      .. doxygenfunction:: simgrid::s4u::Task::on_start_cb
+      .. doxygenfunction:: simgrid::s4u::Task::on_this_start_cb
+      .. doxygenfunction:: simgrid::s4u::Task::on_completion_cb
+      .. doxygenfunction:: simgrid::s4u::Task::on_this_completion_cb
+
+.. _API_s4u_CommTask:
+
+=================
+⁣  class CommTask
+=================
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenclass:: simgrid::s4u::CommTask
+
+Basic management
+----------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. code-block:: C++
+
+         #include <simgrid/s4u/Task.hpp>
+
+      .. doxygentypedef:: CommTaskPtr
+
+Querying info
+-------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenfunction:: simgrid::s4u::CommTask::get_source() const
+      .. doxygenfunction:: simgrid::s4u::CommTask::get_destination() const
+      .. doxygenfunction:: simgrid::s4u::CommTask::get_bytes() const
+      .. doxygenfunction:: simgrid::s4u::CommTask::set_source(Host* source);
+      .. doxygenfunction:: simgrid::s4u::CommTask::set_destination(Host* destination);
+      .. doxygenfunction:: simgrid::s4u::CommTask::set_bytes(double bytes)
+
+
+.. _API_s4u_ExecTask:
+
+=================
+⁣  class ExecTask
+=================
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenclass:: simgrid::s4u::ExecTask
+
+Basic management
+----------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. code-block:: C++
+
+         #include <simgrid/s4u/Task.hpp>
+
+      .. doxygentypedef:: ExecTaskPtr
+
+Querying info
+-------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenfunction:: simgrid::s4u::ExecTask::get_host(std::string instance) const
+      .. doxygenfunction:: simgrid::s4u::ExecTask::get_flops(std::string instance) const
+      .. doxygenfunction:: simgrid::s4u::ExecTask::set_host(Host* host, std::string instance);
+      .. doxygenfunction:: simgrid::s4u::ExecTask::set_flops(double flops, std::string instance);
+      .. doxygenfunction:: simgrid::s4u::ExecTask::add_instances(int n);
+      .. doxygenfunction:: simgrid::s4u::ExecTask::remove_instances(int n);
+
+.. _API_s4u_IoTask:
+
+================
+⁣  class IoTask
+================
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. doxygenclass:: simgrid::s4u::IoTask
+
+Basic management
+----------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+      .. code-block:: C++
+
+         #include <simgrid/s4u/Task.hpp>
+
+      .. doxygentypedef:: IoTaskPtr
+
+Querying info
+-------------
+
+.. tabs::
+
+   .. group-tab:: C++
+
+     .. doxygenfunction:: simgrid::s4u::IoTask::get_disk() const
+     .. doxygenfunction:: simgrid::s4u::IoTask::get_bytes() const
+     .. doxygenfunction:: simgrid::s4u::IoTask::get_op_type() const
+     .. doxygenfunction:: simgrid::s4u::IoTask::set_disk(Disk* disk);
+     .. doxygenfunction:: simgrid::s4u::IoTask::set_bytes(double bytes);
+     .. doxygenfunction:: simgrid::s4u::IoTask::set_op_type(Io::OpType type);
 
 .. _API_s4u_Synchronizations:
 
@@ -2543,7 +2937,7 @@ Basic management
 
          .. doxygentypedef:: MutexPtr
 
-         .. doxygenfunction:: simgrid::s4u::Mutex::create()
+         .. doxygenfunction:: simgrid::s4u::Mutex::create
 
       .. group-tab:: Python
 
@@ -2625,6 +3019,7 @@ Locking
 
       .. doxygenfunction:: simgrid::s4u::Barrier::create(unsigned int expected_actors)
       .. doxygenfunction:: simgrid::s4u::Barrier::wait()
+      .. doxygenfunction:: simgrid::s4u::Barrier::to_string()   
 
    .. group-tab:: Python
 
@@ -2818,7 +3213,7 @@ Error reporting
 
       The following errors denote a problem in the SimGrid tool itself. Most of the time, you should let these
       exception go, so that the simulation stops. But you may want to catch them, for example when you launch
-      simgrid from a python notebook and want to handle the problem accordingly.
+      SimGrid from a python notebook and want to handle the problem accordingly.
 
       .. doxygenclass:: simgrid::AssertionError
       .. doxygenclass:: simgrid::ParseError
@@ -2837,7 +3232,7 @@ Error reporting
 
       The following errors denote a problem in the SimGrid tool itself. Most of the time, you should let these
       exception go, so that the simulation stops. But you may want to catch them, for example when you launch
-      simgrid from a python notebook and want to handle the problem accordingly.
+      SimGrid from a python notebook and want to handle the problem accordingly.
 
       .. autoclass:: simgrid.AssertionError
 
index ddea04e..84bb4fc 100644 (file)
@@ -42,11 +42,121 @@ For **further scalability**, you may modify your code to speed up your
 studies or save memory space.  Maximal **simulation accuracy**
 requires some specific care from you.
 
+-------------------------
+What can run within SMPI?
+-------------------------
+
+You can run unmodified MPI applications (both C/C++ and Fortran) within
+SMPI, provided that you only use MPI calls that we implemented. Global
+variables should be handled correctly on Linux systems.
+
+....................
+MPI coverage of SMPI
+....................
+
+SMPI support a large faction of the MPI interface: we pass many of the MPICH coverage tests, and many of the existing
+:ref:`proxy apps <SMPI_proxy_apps>` run almost unmodified on top of SMPI. But our support is still incomplete, with I/O
+primitives the being one of the major missing feature.
+
+The full list of functions that remain to be implemented is documented in the file `include/smpi/smpi.h
+<https://framagit.org/simgrid/simgrid/tree/master/include/smpi/smpi.h>`_ in your version of SimGrid, between two lines
+containing the ``FIXME`` marker. If you miss a feature, please get in touch with us: we can guide you through the SimGrid
+code to help you implementing it, and we'd be glad to integrate your contribution to the main project.
+
+.. _SMPI_what_globals:
+
+.................................
+Privatization of global variables
+.................................
+
+Concerning the globals, the problem comes from the fact that usually,
+MPI processes run as real UNIX processes while they are all folded
+into threads of a unique system process in SMPI. Global variables are
+usually private to each MPI process while they become shared between
+the processes in SMPI.  The problem and some potential solutions are
+discussed in this article: `Automatic Handling of Global Variables for
+Multi-threaded MPI Programs
+<http://charm.cs.illinois.edu/newPapers/11-23/paper.pdf>` (note that
+this article does not deal with SMPI but with a competing solution
+called AMPI that suffers of the same issue).  This point used to be
+problematic in SimGrid, but the problem should now be handled
+automatically on Linux.
+
+Older versions of SimGrid came with a script that automatically
+privatized the globals through static analysis of the source code. But
+our implementation was not robust enough to be used in production, so
+it was removed at some point. Currently, SMPI comes with two
+privatization mechanisms that you can :ref:`select at runtime
+<cfg=smpi/privatization>`.  The dlopen approach is used by
+default as it is much faster and still very robust.  The mmap approach
+is an older approach that proves to be slower.
+
+With the **mmap approach**, SMPI duplicates and dynamically switch the
+``.data`` and ``.bss`` segments of the ELF process when switching the
+MPI ranks. This allows each ranks to have its own copy of the global
+variables.  No copy actually occurs as this mechanism uses ``mmap()``
+for efficiency. This mechanism is considered to be very robust on all
+systems supporting ``mmap()`` (Linux and most BSDs). Its performance
+is questionable since each context switch between MPI ranks induces
+several syscalls to change the ``mmap`` that redirects the ``.data``
+and ``.bss`` segments to the copies of the new rank. The code will
+also be copied several times in memory, inducing a slight increase of
+memory occupation.
+
+Another limitation is that SMPI only accounts for global variables
+defined in the executable. If the processes use external global
+variables from dynamic libraries, they won't be switched
+correctly. The easiest way to solve this is to statically link against
+the library with these globals. This way, each MPI rank will get its
+own copy of these libraries. Of course you should never statically
+link against the SimGrid library itself.
+
+With the **dlopen approach**, SMPI loads several copies of the same
+executable in memory as if it were a library, so that the global
+variables get naturally duplicated. It first requires the executable
+to be compiled as a relocatable binary, which is less common for
+programs than for libraries. But most distributions are now compiled
+this way for security reason as it allows one to randomize the address
+space layout. It should thus be safe to compile most (any?) program
+this way.  The second trick is that the dynamic linker refuses to link
+the exact same file several times, be it a library or a relocatable
+executable. It makes perfectly sense in the general case, but we need
+to circumvent this rule of thumb in our case. To that extend, the
+binary is copied in a temporary file before being re-linked against.
+``dlmopen()`` cannot be used as it only allows 256 contexts, and as it
+would also duplicate SimGrid itself.
+
+This approach greatly speeds up the context switching, down to about
+40 CPU cycles with our raw contexts, instead of requesting several
+syscalls with the ``mmap()`` approach. Another advantage is that it
+permits one to run the SMPI contexts in parallel, which is obviously not
+possible with the ``mmap()`` approach. It was tricky to implement, but
+we are not aware of any flaws, so smpirun activates it by default.
+
+In the future, it may be possible to further reduce the memory and
+disk consumption. It seems that we could `punch holes
+<https://lwn.net/Articles/415889/>`_ in the files before dl-loading
+them to remove the code and constants, and mmap these area onto a
+unique copy. If done correctly, this would reduce the disk- and
+memory- usage to the bare minimum, and would also reduce the pressure
+on the CPU instruction cache. See the `relevant bug
+<https://github.com/simgrid/simgrid/issues/137>`_ on github for
+implementation leads.\n
+
+Also, currently, only the binary is copied and dlopen-ed for each MPI
+rank. We could probably extend this to external dependencies, but for
+now, any external dependencies must be statically linked into your
+application. As usual, SimGrid itself shall never be statically linked
+in your app. You don't want to give a copy of SimGrid to each MPI rank:
+that's ways too much for them to deal with.
+
+.. todo: speak of smpi/privatize-libs here
+
 .. _SMPI_online:
 
------------------
-Using SMPI online
------------------
+---------------------------
+Online SMPI: live execution
+---------------------------
 
 In this mode, your application is actually executed. Every computation
 occurs for real while every communication is simulated. In addition,
@@ -203,9 +313,11 @@ means that the selected algorithm will be used
 .. Warning:: Some collective may require specific conditions to be
    executed correctly (for instance having a communicator with a power
    of two number of nodes only), which are currently not enforced by
-   Simgrid. Some crashes can be expected while trying these algorithms
+   SimGrid. Some crashes can be expected while trying these algorithms
    with unusual sizes/parameters
 
+To retrieve the full list of implemented algorithms in your version of SimGrid, simply use ``smpirun --help-coll``.
+
 MPI_Alltoall
 ^^^^^^^^^^^^
 
@@ -453,7 +565,7 @@ Adding an algorithm
 ^^^^^^^^^^^^^^^^^^^
 
 To add a new algorithm, one should check in the src/smpi/colls folder
-how other algorithms are coded. Using plain MPI code inside Simgrid
+how other algorithms are coded. Using plain MPI code inside SimGrid
 can't be done, so algorithms have to be changed to use smpi version of
 the calls instead (MPI_Send will become smpi_mpi_send). Some functions
 may have different signatures than their MPI counterpart, please check
@@ -471,7 +583,7 @@ Example: adding a "pair" version of the Alltoall collective.
 
  - To register the new version of the algorithm, simply add a line to the corresponding macro in src/smpi/colls/cools.h ( add a "COLL_APPLY(action, COLL_ALLTOALL_SIG, pair)" to the COLL_ALLTOALLS macro ). The algorithm should now be compiled and be selected when using --cfg=smpi/alltoall:pair at runtime.
 
- - To add a test for the algorithm inside Simgrid's test suite, juste add the new algorithm name in the ALLTOALL_COLL list found inside teshsuite/smpi/CMakeLists.txt . When running ctest, a test for the new algorithm should be generated and executed. If it does not pass, please check your code or contact us.
+ - To add a test for the algorithm inside SimGrid's test suite, juste add the new algorithm name in the ALLTOALL_COLL list found inside teshsuite/smpi/CMakeLists.txt . When running ctest, a test for the new algorithm should be generated and executed. If it does not pass, please check your code or contact us.
 
  - Please submit your patch for inclusion in SMPI, for example through a pull request on GitHub or directly per email.
 
@@ -498,119 +610,38 @@ Alltoall on 16 Nodes with the Ring Algorithm.
 
 Alltoall on 16 Nodes with the Pairwise Algorithm.
 
--------------------------
-What can run within SMPI?
--------------------------
+.. _SMPI_mix_s4u:
 
-You can run unmodified MPI applications (both C/C++ and Fortran) within
-SMPI, provided that you only use MPI calls that we implemented. Global
-variables should be handled correctly on Linux systems.
-
-....................
-MPI coverage of SMPI
-....................
-
-SMPI support a large faction of the MPI interface: we pass many of the MPICH coverage tests, and many of the existing
-:ref:`proxy apps <SMPI_proxy_apps>` run almost unmodified on top of SMPI. But our support is still incomplete, with I/O
-primitives the being one of the major missing feature.
-
-The full list of functions that remain to be implemented is documented in the file `include/smpi/smpi.h
-<https://framagit.org/simgrid/simgrid/tree/master/include/smpi/smpi.h>`_ in your version of SimGrid, between two lines
-containing the ``FIXME`` marker. If you miss a feature, please get in touch with us: we can guide you through the SimGrid
-code to help you implementing it, and we'd be glad to integrate your contribution to the main project.
-
-.. _SMPI_what_globals:
-
-.................................
-Privatization of global variables
-.................................
-
-Concerning the globals, the problem comes from the fact that usually,
-MPI processes run as real UNIX processes while they are all folded
-into threads of a unique system process in SMPI. Global variables are
-usually private to each MPI process while they become shared between
-the processes in SMPI.  The problem and some potential solutions are
-discussed in this article: `Automatic Handling of Global Variables for
-Multi-threaded MPI Programs
-<http://charm.cs.illinois.edu/newPapers/11-23/paper.pdf>` (note that
-this article does not deal with SMPI but with a competing solution
-called AMPI that suffers of the same issue).  This point used to be
-problematic in SimGrid, but the problem should now be handled
-automatically on Linux.
+.............................
+Mixing S4U and MPI simulation
+.............................
 
-Older versions of SimGrid came with a script that automatically
-privatized the globals through static analysis of the source code. But
-our implementation was not robust enough to be used in production, so
-it was removed at some point. Currently, SMPI comes with two
-privatization mechanisms that you can :ref:`select at runtime
-<cfg=smpi/privatization>`.  The dlopen approach is used by
-default as it is much faster and still very robust.  The mmap approach
-is an older approach that proves to be slower.
+Mixing both interfaces is very easy. This can be useful to easily implement a service in S4U that is provided by your
+infrastructure in some way, and test how your MPI application interacts with this service. Or you can use it to start more than
+one MPI application in your simulation, and study their interactions. For that, you just need to use
+:cpp:ref:`SMPI_app_instance_register` in a regular S4U program, as shown in the example below. Compile it as usual (with gcc or
+g++, **not** smpicc) and execute it directly (**not** with smpirun).
 
-With the **mmap approach**, SMPI duplicates and dynamically switch the
-``.data`` and ``.bss`` segments of the ELF process when switching the
-MPI ranks. This allows each ranks to have its own copy of the global
-variables.  No copy actually occurs as this mechanism uses ``mmap()``
-for efficiency. This mechanism is considered to be very robust on all
-systems supporting ``mmap()`` (Linux and most BSDs). Its performance
-is questionable since each context switch between MPI ranks induces
-several syscalls to change the ``mmap`` that redirects the ``.data``
-and ``.bss`` segments to the copies of the new rank. The code will
-also be copied several times in memory, inducing a slight increase of
-memory occupation.
+.. doxygenfunction:: SMPI_app_instance_start
 
-Another limitation is that SMPI only accounts for global variables
-defined in the executable. If the processes use external global
-variables from dynamic libraries, they won't be switched
-correctly. The easiest way to solve this is to statically link against
-the library with these globals. This way, each MPI rank will get its
-own copy of these libraries. Of course you should never statically
-link against the SimGrid library itself.
+.. tabs::
 
-With the **dlopen approach**, SMPI loads several copies of the same
-executable in memory as if it were a library, so that the global
-variables get naturally duplicated. It first requires the executable
-to be compiled as a relocatable binary, which is less common for
-programs than for libraries. But most distributions are now compiled
-this way for security reason as it allows one to randomize the address
-space layout. It should thus be safe to compile most (any?) program
-this way.  The second trick is that the dynamic linker refuses to link
-the exact same file several times, be it a library or a relocatable
-executable. It makes perfectly sense in the general case, but we need
-to circumvent this rule of thumb in our case. To that extend, the
-binary is copied in a temporary file before being re-linked against.
-``dlmopen()`` cannot be used as it only allows 256 contextes, and as it
-would also duplicate simgrid itself.
+   .. group-tab:: Example
 
-This approach greatly speeds up the context switching, down to about
-40 CPU cycles with our raw contextes, instead of requesting several
-syscalls with the ``mmap()`` approach. Another advantage is that it
-permits one to run the SMPI contexts in parallel, which is obviously not
-possible with the ``mmap()`` approach. It was tricky to implement, but
-we are not aware of any flaws, so smpirun activates it by default.
+      Here is a simple example of use, which starts the function ``alltoall_mpi`` as a MPI instance on 4 hosts, along several
+      S4U actors doing a master/workers.
 
-In the future, it may be possible to further reduce the memory and
-disk consumption. It seems that we could `punch holes
-<https://lwn.net/Articles/415889/>`_ in the files before dl-loading
-them to remove the code and constants, and mmap these area onto a
-unique copy. If done correctly, this would reduce the disk- and
-memory- usage to the bare minimum, and would also reduce the pressure
-on the CPU instruction cache. See the `relevant bug
-<https://github.com/simgrid/simgrid/issues/137>`_ on github for
-implementation leads.\n
+      .. showfile:: examples/smpi/smpi_s4u_masterworker/masterworker_mailbox_smpi.cpp
+         :language: cpp
 
-Also, currently, only the binary is copied and dlopen-ed for each MPI
-rank. We could probably extend this to external dependencies, but for
-now, any external dependencies must be statically linked into your
-application. As usual, simgrid itself shall never be statically linked
-in your app. You don't want to give a copy of SimGrid to each MPI rank:
-that's ways too much for them to deal with.
+   .. group-tab:: Deployment file
 
-.. todo: speak of smpi/privatize-libs here
+      .. showfile:: examples/smpi/smpi_s4u_masterworker/deployment_masterworker_mailbox_smpi.xml
+         :language: xml
 
-----------------------------------------------
+..............................................
 Adapting your MPI code for further scalability
-----------------------------------------------
+..............................................
 
 As detailed in the `reference article
 <http://hal.inria.fr/hal-01415484>`_, you may want to adapt your code
@@ -619,9 +650,8 @@ hinder the result quality (or even prevent the app to run) if used
 wrongly. We assume that if you want to simulate an HPC application,
 you know what you are doing. Don't prove us wrong!
 
-..............................
 Reducing your memory footprint
-..............................
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 If you get short on memory (the whole app is executed on a single node when
 simulated), you should have a look at the SMPI_SHARED_MALLOC and
@@ -649,9 +679,8 @@ This feature is demoed by the example file
 
 .. _SMPI_use_faster:
 
-.........................
 Toward Faster Simulations
-.........................
+^^^^^^^^^^^^^^^^^^^^^^^^^
 
 If your application is too slow, try using SMPI_SAMPLE_LOCAL,
 SMPI_SAMPLE_GLOBAL and friends to indicate which computation loops can
@@ -671,9 +700,8 @@ what is necessary to group calls of a given size together.
 This feature is demoed by the example file
 `examples/smpi/NAS/ep.c <https://framagit.org/simgrid/simgrid/tree/master/examples/smpi/NAS/ep.c>`_
 
-.............................
 Ensuring Accurate Simulations
-.............................
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Out of the box, SimGrid may give you fairly accurate results, but
 there is a plenty of factors that could go wrong and make your results
@@ -715,9 +743,9 @@ modeling distributed systems.
 
 .. _SMPI_proxy_apps:
 
-----------------------
+......................
 Examples of SMPI Usage
-----------------------
+......................
 
 A small amount of examples can be found directly in the SimGrid
 archive, under `examples/smpi <https://framagit.org/simgrid/simgrid/-/tree/master/examples/smpi>`_.
@@ -745,6 +773,50 @@ next generation of runtimes and hardware. `This project
 from different sources, along with the patches needed (if any) to run
 them on top of SMPI.
 
+.. _SMPI_offline:
+
+--------------------------
+Offline SMPI: Trace Replay
+--------------------------
+
+Although SMPI is often used for :ref:`online simulation
+<SMPI_online>`, where the application is executed for real, you can
+also go for offline simulation through trace replay.
+
+SimGrid uses time-independent traces, in which each actor is given a
+script of the actions to do sequentially. These trace files can
+actually be captured with the online version of SMPI, as follows:
+
+.. code-block:: console
+
+   $ smpirun -trace-ti --cfg=tracing/filename:LU.A.32 -np 32 -platform ../cluster_backbone.xml bin/lu.A.32
+
+The produced trace is composed of a file ``LU.A.32`` and a folder
+``LU.A.32_files``. The file names don't match with the MPI ranks, but
+that's expected.
+
+To replay this with SMPI, you need to first compile the provided
+``smpi_replay.cpp`` file, that comes from
+`simgrid/examples/smpi/replay
+<https://framagit.org/simgrid/simgrid/tree/master/examples/smpi/replay>`_.
+
+.. code-block:: console
+
+   $ smpicxx ../replay.cpp -O3 -o ../smpi_replay
+
+Afterward, you can replay your trace in SMPI as follows:
+
+.. code-block:: console
+
+   $ smpirun -np 32 -platform ../cluster_torus.xml -ext smpi_replay ../smpi_replay LU.A.32
+
+All the outputs are gone, as the application is not really simulated
+here. Its trace is simply replayed. But if you visualize the live
+simulation and the replay, you will see that the behavior is
+unchanged. The simulation does not run much faster on this very
+example, but this becomes very interesting when your application
+is computationally hungry.
+
 -------------------------
 Troubleshooting with SMPI
 -------------------------
@@ -806,52 +878,6 @@ only if you declare ``_GNU_SOURCE`` before including
 SMPI, then you need to ensure that you pass the right configuration
 defines as advised above.
 
-
-
-.. _SMPI_offline:
-
------------------------------
-Trace Replay and Offline SMPI
------------------------------
-
-Although SMPI is often used for :ref:`online simulation
-<SMPI_online>`, where the application is executed for real, you can
-also go for offline simulation through trace replay.
-
-SimGrid uses time-independent traces, in which each actor is given a
-script of the actions to do sequentially. These trace files can
-actually be captured with the online version of SMPI, as follows:
-
-.. code-block:: console
-
-   $ smpirun -trace-ti --cfg=tracing/filename:LU.A.32 -np 32 -platform ../cluster_backbone.xml bin/lu.A.32
-
-The produced trace is composed of a file ``LU.A.32`` and a folder
-``LU.A.32_files``. The file names don't match with the MPI ranks, but
-that's expected.
-
-To replay this with SMPI, you need to first compile the provided
-``smpi_replay.cpp`` file, that comes from
-`simgrid/examples/smpi/replay
-<https://framagit.org/simgrid/simgrid/tree/master/examples/smpi/replay>`_.
-
-.. code-block:: console
-
-   $ smpicxx ../replay.cpp -O3 -o ../smpi_replay
-
-Afterward, you can replay your trace in SMPI as follows:
-
-.. code-block:: console
-
-   $ smpirun -np 32 -platform ../cluster_torus.xml -ext smpi_replay ../smpi_replay LU.A.32
-
-All the outputs are gone, as the application is not really simulated
-here. Its trace is simply replayed. But if you visualize the live
-simulation and the replay, you will see that the behavior is
-unchanged. The simulation does not run much faster on this very
-example, but this becomes very interesting when your application
-is computationally hungry.
-
 .. |br| raw:: html
 
    <br />
index 1c8d99c..96b64bf 100644 (file)
@@ -34,7 +34,7 @@ copyright = u'2002-2023, The SimGrid Team'
 author = u'The SimGrid Team'
 
 # The short X.Y version
-version = u'3.32.1'
+version = u'3.35.1'
 
 # -- General configuration ---------------------------------------------------
 
diff --git a/docs/source/img/battery_degradation.svg b/docs/source/img/battery_degradation.svg
new file mode 100644 (file)
index 0000000..432fa43
--- /dev/null
@@ -0,0 +1,1986 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="1152pt" height="576pt" viewBox="0 0 1152 576" xmlns="http://www.w3.org/2000/svg" version="1.1">
+ <metadata>
+  <rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+   <cc:Work>
+    <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+    <dc:date>2023-07-13T14:07:53.987014</dc:date>
+    <dc:format>image/svg+xml</dc:format>
+    <dc:creator>
+     <cc:Agent>
+      <dc:title>Matplotlib v3.7.1, https://matplotlib.org/</dc:title>
+     </cc:Agent>
+    </dc:creator>
+   </cc:Work>
+  </rdf:RDF>
+ </metadata>
+ <defs>
+  <style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style>
+ </defs>
+ <g id="figure_1">
+  <g id="patch_1">
+   <path d="M 0 576 
+L 1152 576 
+L 1152 0 
+L 0 0 
+z
+" style="fill: #ffffff"/>
+  </g>
+  <g id="axes_1">
+   <g id="patch_2">
+    <path d="M 144 512.64 
+L 1036.8 512.64 
+L 1036.8 69.12 
+L 144 69.12 
+z
+" style="fill: #eaeaf2"/>
+   </g>
+   <g id="matplotlib.axis_1">
+    <g id="xtick_1">
+     <g id="line2d_1">
+      <path d="M 182.150041 512.64 
+L 182.150041 69.12 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_1">
+      <!-- 0 -->
+      <g style="fill: #262626" transform="translate(178.650666 530.498281) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-30" d="M 2034 4250 
+Q 1547 4250 1301 3770 
+Q 1056 3291 1056 2328 
+Q 1056 1369 1301 889 
+Q 1547 409 2034 409 
+Q 2525 409 2770 889 
+Q 3016 1369 3016 2328 
+Q 3016 3291 2770 3770 
+Q 2525 4250 2034 4250 
+z
+M 2034 4750 
+Q 2819 4750 3233 4129 
+Q 3647 3509 3647 2328 
+Q 3647 1150 3233 529 
+Q 2819 -91 2034 -91 
+Q 1250 -91 836 529 
+Q 422 1150 422 2328 
+Q 422 3509 836 4129 
+Q 1250 4750 2034 4750 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-30"/>
+      </g>
+     </g>
+    </g>
+    <g id="xtick_2">
+     <g id="line2d_2">
+      <path d="M 307.116388 512.64 
+L 307.116388 69.12 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_2">
+      <!-- 10000 -->
+      <g style="fill: #262626" transform="translate(289.619513 530.498281) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-31" d="M 794 531 
+L 1825 531 
+L 1825 4091 
+L 703 3866 
+L 703 4441 
+L 1819 4666 
+L 2450 4666 
+L 2450 531 
+L 3481 531 
+L 3481 0 
+L 794 0 
+L 794 531 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-31"/>
+       <use xlink:href="#DejaVuSans-30" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-30" x="127.246094"/>
+       <use xlink:href="#DejaVuSans-30" x="190.869141"/>
+       <use xlink:href="#DejaVuSans-30" x="254.492188"/>
+      </g>
+     </g>
+    </g>
+    <g id="xtick_3">
+     <g id="line2d_3">
+      <path d="M 432.082736 512.64 
+L 432.082736 69.12 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_3">
+      <!-- 20000 -->
+      <g style="fill: #262626" transform="translate(414.585861 530.498281) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-32" d="M 1228 531 
+L 3431 531 
+L 3431 0 
+L 469 0 
+L 469 531 
+Q 828 903 1448 1529 
+Q 2069 2156 2228 2338 
+Q 2531 2678 2651 2914 
+Q 2772 3150 2772 3378 
+Q 2772 3750 2511 3984 
+Q 2250 4219 1831 4219 
+Q 1534 4219 1204 4116 
+Q 875 4013 500 3803 
+L 500 4441 
+Q 881 4594 1212 4672 
+Q 1544 4750 1819 4750 
+Q 2544 4750 2975 4387 
+Q 3406 4025 3406 3419 
+Q 3406 3131 3298 2873 
+Q 3191 2616 2906 2266 
+Q 2828 2175 2409 1742 
+Q 1991 1309 1228 531 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-32"/>
+       <use xlink:href="#DejaVuSans-30" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-30" x="127.246094"/>
+       <use xlink:href="#DejaVuSans-30" x="190.869141"/>
+       <use xlink:href="#DejaVuSans-30" x="254.492188"/>
+      </g>
+     </g>
+    </g>
+    <g id="xtick_4">
+     <g id="line2d_4">
+      <path d="M 557.049084 512.64 
+L 557.049084 69.12 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_4">
+      <!-- 30000 -->
+      <g style="fill: #262626" transform="translate(539.552209 530.498281) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-33" d="M 2597 2516 
+Q 3050 2419 3304 2112 
+Q 3559 1806 3559 1356 
+Q 3559 666 3084 287 
+Q 2609 -91 1734 -91 
+Q 1441 -91 1130 -33 
+Q 819 25 488 141 
+L 488 750 
+Q 750 597 1062 519 
+Q 1375 441 1716 441 
+Q 2309 441 2620 675 
+Q 2931 909 2931 1356 
+Q 2931 1769 2642 2001 
+Q 2353 2234 1838 2234 
+L 1294 2234 
+L 1294 2753 
+L 1863 2753 
+Q 2328 2753 2575 2939 
+Q 2822 3125 2822 3475 
+Q 2822 3834 2567 4026 
+Q 2313 4219 1838 4219 
+Q 1578 4219 1281 4162 
+Q 984 4106 628 3988 
+L 628 4550 
+Q 988 4650 1302 4700 
+Q 1616 4750 1894 4750 
+Q 2613 4750 3031 4423 
+Q 3450 4097 3450 3541 
+Q 3450 3153 3228 2886 
+Q 3006 2619 2597 2516 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-33"/>
+       <use xlink:href="#DejaVuSans-30" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-30" x="127.246094"/>
+       <use xlink:href="#DejaVuSans-30" x="190.869141"/>
+       <use xlink:href="#DejaVuSans-30" x="254.492188"/>
+      </g>
+     </g>
+    </g>
+    <g id="xtick_5">
+     <g id="line2d_5">
+      <path d="M 682.015432 512.64 
+L 682.015432 69.12 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_5">
+      <!-- 40000 -->
+      <g style="fill: #262626" transform="translate(664.518557 530.498281) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-34" d="M 2419 4116 
+L 825 1625 
+L 2419 1625 
+L 2419 4116 
+z
+M 2253 4666 
+L 3047 4666 
+L 3047 1625 
+L 3713 1625 
+L 3713 1100 
+L 3047 1100 
+L 3047 0 
+L 2419 0 
+L 2419 1100 
+L 313 1100 
+L 313 1709 
+L 2253 4666 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-34"/>
+       <use xlink:href="#DejaVuSans-30" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-30" x="127.246094"/>
+       <use xlink:href="#DejaVuSans-30" x="190.869141"/>
+       <use xlink:href="#DejaVuSans-30" x="254.492188"/>
+      </g>
+     </g>
+    </g>
+    <g id="xtick_6">
+     <g id="line2d_6">
+      <path d="M 806.98178 512.64 
+L 806.98178 69.12 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_6">
+      <!-- 50000 -->
+      <g style="fill: #262626" transform="translate(789.484905 530.498281) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-35" d="M 691 4666 
+L 3169 4666 
+L 3169 4134 
+L 1269 4134 
+L 1269 2991 
+Q 1406 3038 1543 3061 
+Q 1681 3084 1819 3084 
+Q 2600 3084 3056 2656 
+Q 3513 2228 3513 1497 
+Q 3513 744 3044 326 
+Q 2575 -91 1722 -91 
+Q 1428 -91 1123 -41 
+Q 819 9 494 109 
+L 494 744 
+Q 775 591 1075 516 
+Q 1375 441 1709 441 
+Q 2250 441 2565 725 
+Q 2881 1009 2881 1497 
+Q 2881 1984 2565 2268 
+Q 2250 2553 1709 2553 
+Q 1456 2553 1204 2497 
+Q 953 2441 691 2322 
+L 691 4666 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-35"/>
+       <use xlink:href="#DejaVuSans-30" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-30" x="127.246094"/>
+       <use xlink:href="#DejaVuSans-30" x="190.869141"/>
+       <use xlink:href="#DejaVuSans-30" x="254.492188"/>
+      </g>
+     </g>
+    </g>
+    <g id="xtick_7">
+     <g id="line2d_7">
+      <path d="M 931.948127 512.64 
+L 931.948127 69.12 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_7">
+      <!-- 60000 -->
+      <g style="fill: #262626" transform="translate(914.451252 530.498281) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-36" d="M 2113 2584 
+Q 1688 2584 1439 2293 
+Q 1191 2003 1191 1497 
+Q 1191 994 1439 701 
+Q 1688 409 2113 409 
+Q 2538 409 2786 701 
+Q 3034 994 3034 1497 
+Q 3034 2003 2786 2293 
+Q 2538 2584 2113 2584 
+z
+M 3366 4563 
+L 3366 3988 
+Q 3128 4100 2886 4159 
+Q 2644 4219 2406 4219 
+Q 1781 4219 1451 3797 
+Q 1122 3375 1075 2522 
+Q 1259 2794 1537 2939 
+Q 1816 3084 2150 3084 
+Q 2853 3084 3261 2657 
+Q 3669 2231 3669 1497 
+Q 3669 778 3244 343 
+Q 2819 -91 2113 -91 
+Q 1303 -91 875 529 
+Q 447 1150 447 2328 
+Q 447 3434 972 4092 
+Q 1497 4750 2381 4750 
+Q 2619 4750 2861 4703 
+Q 3103 4656 3366 4563 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-36"/>
+       <use xlink:href="#DejaVuSans-30" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-30" x="127.246094"/>
+       <use xlink:href="#DejaVuSans-30" x="190.869141"/>
+       <use xlink:href="#DejaVuSans-30" x="254.492188"/>
+      </g>
+     </g>
+    </g>
+    <g id="text_8">
+     <!-- Time -->
+     <g style="fill: #262626" transform="translate(575.719687 545.904063) scale(0.12 -0.12)">
+      <defs>
+       <path id="DejaVuSans-54" d="M -19 4666 
+L 3928 4666 
+L 3928 4134 
+L 2272 4134 
+L 2272 0 
+L 1638 0 
+L 1638 4134 
+L -19 4134 
+L -19 4666 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-69" d="M 603 3500 
+L 1178 3500 
+L 1178 0 
+L 603 0 
+L 603 3500 
+z
+M 603 4863 
+L 1178 4863 
+L 1178 4134 
+L 603 4134 
+L 603 4863 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-6d" d="M 3328 2828 
+Q 3544 3216 3844 3400 
+Q 4144 3584 4550 3584 
+Q 5097 3584 5394 3201 
+Q 5691 2819 5691 2113 
+L 5691 0 
+L 5113 0 
+L 5113 2094 
+Q 5113 2597 4934 2840 
+Q 4756 3084 4391 3084 
+Q 3944 3084 3684 2787 
+Q 3425 2491 3425 1978 
+L 3425 0 
+L 2847 0 
+L 2847 2094 
+Q 2847 2600 2669 2842 
+Q 2491 3084 2119 3084 
+Q 1678 3084 1418 2786 
+Q 1159 2488 1159 1978 
+L 1159 0 
+L 581 0 
+L 581 3500 
+L 1159 3500 
+L 1159 2956 
+Q 1356 3278 1631 3431 
+Q 1906 3584 2284 3584 
+Q 2666 3584 2933 3390 
+Q 3200 3197 3328 2828 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-65" d="M 3597 1894 
+L 3597 1613 
+L 953 1613 
+Q 991 1019 1311 708 
+Q 1631 397 2203 397 
+Q 2534 397 2845 478 
+Q 3156 559 3463 722 
+L 3463 178 
+Q 3153 47 2828 -22 
+Q 2503 -91 2169 -91 
+Q 1331 -91 842 396 
+Q 353 884 353 1716 
+Q 353 2575 817 3079 
+Q 1281 3584 2069 3584 
+Q 2775 3584 3186 3129 
+Q 3597 2675 3597 1894 
+z
+M 3022 2063 
+Q 3016 2534 2758 2815 
+Q 2500 3097 2075 3097 
+Q 1594 3097 1305 2825 
+Q 1016 2553 972 2059 
+L 3022 2063 
+z
+" transform="scale(0.015625)"/>
+      </defs>
+      <use xlink:href="#DejaVuSans-54"/>
+      <use xlink:href="#DejaVuSans-69" x="57.958984"/>
+      <use xlink:href="#DejaVuSans-6d" x="85.742188"/>
+      <use xlink:href="#DejaVuSans-65" x="183.154297"/>
+     </g>
+    </g>
+   </g>
+   <g id="matplotlib.axis_2">
+    <g id="ytick_1">
+     <g id="line2d_8">
+      <path d="M 144 447.472913 
+L 1036.8 447.472913 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_9">
+      <!-- 0.2 -->
+      <g style="fill: #262626" transform="translate(117.006563 451.652054) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-2e" d="M 684 794 
+L 1344 794 
+L 1344 0 
+L 684 0 
+L 684 794 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-30"/>
+       <use xlink:href="#DejaVuSans-2e" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-32" x="95.410156"/>
+      </g>
+     </g>
+    </g>
+    <g id="ytick_2">
+     <g id="line2d_9">
+      <path d="M 144 357.587277 
+L 1036.8 357.587277 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_10">
+      <!-- 0.4 -->
+      <g style="fill: #262626" transform="translate(117.006563 361.766418) scale(0.11 -0.11)">
+       <use xlink:href="#DejaVuSans-30"/>
+       <use xlink:href="#DejaVuSans-2e" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-34" x="95.410156"/>
+      </g>
+     </g>
+    </g>
+    <g id="ytick_3">
+     <g id="line2d_10">
+      <path d="M 144 267.70164 
+L 1036.8 267.70164 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_11">
+      <!-- 0.6 -->
+      <g style="fill: #262626" transform="translate(117.006563 271.880781) scale(0.11 -0.11)">
+       <use xlink:href="#DejaVuSans-30"/>
+       <use xlink:href="#DejaVuSans-2e" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-36" x="95.410156"/>
+      </g>
+     </g>
+    </g>
+    <g id="ytick_4">
+     <g id="line2d_11">
+      <path d="M 144 177.816004 
+L 1036.8 177.816004 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_12">
+      <!-- 0.8 -->
+      <g style="fill: #262626" transform="translate(117.006563 181.995144) scale(0.11 -0.11)">
+       <defs>
+        <path id="DejaVuSans-38" d="M 2034 2216 
+Q 1584 2216 1326 1975 
+Q 1069 1734 1069 1313 
+Q 1069 891 1326 650 
+Q 1584 409 2034 409 
+Q 2484 409 2743 651 
+Q 3003 894 3003 1313 
+Q 3003 1734 2745 1975 
+Q 2488 2216 2034 2216 
+z
+M 1403 2484 
+Q 997 2584 770 2862 
+Q 544 3141 544 3541 
+Q 544 4100 942 4425 
+Q 1341 4750 2034 4750 
+Q 2731 4750 3128 4425 
+Q 3525 4100 3525 3541 
+Q 3525 3141 3298 2862 
+Q 3072 2584 2669 2484 
+Q 3125 2378 3379 2068 
+Q 3634 1759 3634 1313 
+Q 3634 634 3220 271 
+Q 2806 -91 2034 -91 
+Q 1263 -91 848 271 
+Q 434 634 434 1313 
+Q 434 1759 690 2068 
+Q 947 2378 1403 2484 
+z
+M 1172 3481 
+Q 1172 3119 1398 2916 
+Q 1625 2713 2034 2713 
+Q 2441 2713 2670 2916 
+Q 2900 3119 2900 3481 
+Q 2900 3844 2670 4047 
+Q 2441 4250 2034 4250 
+Q 1625 4250 1398 4047 
+Q 1172 3844 1172 3481 
+z
+" transform="scale(0.015625)"/>
+       </defs>
+       <use xlink:href="#DejaVuSans-30"/>
+       <use xlink:href="#DejaVuSans-2e" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-38" x="95.410156"/>
+      </g>
+     </g>
+    </g>
+    <g id="ytick_5">
+     <g id="line2d_12">
+      <path d="M 144 87.930367 
+L 1036.8 87.930367 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #ffffff; stroke-linecap: round"/>
+     </g>
+     <g id="text_13">
+      <!-- 1.0 -->
+      <g style="fill: #262626" transform="translate(117.006563 92.109508) scale(0.11 -0.11)">
+       <use xlink:href="#DejaVuSans-31"/>
+       <use xlink:href="#DejaVuSans-2e" x="63.623047"/>
+       <use xlink:href="#DejaVuSans-30" x="95.410156"/>
+      </g>
+     </g>
+    </g>
+    <g id="text_14">
+     <!-- Value -->
+     <g style="fill: #262626" transform="translate(110.510937 307.3575) rotate(-90) scale(0.12 -0.12)">
+      <defs>
+       <path id="DejaVuSans-56" d="M 1831 0 
+L 50 4666 
+L 709 4666 
+L 2188 738 
+L 3669 4666 
+L 4325 4666 
+L 2547 0 
+L 1831 0 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-61" d="M 2194 1759 
+Q 1497 1759 1228 1600 
+Q 959 1441 959 1056 
+Q 959 750 1161 570 
+Q 1363 391 1709 391 
+Q 2188 391 2477 730 
+Q 2766 1069 2766 1631 
+L 2766 1759 
+L 2194 1759 
+z
+M 3341 1997 
+L 3341 0 
+L 2766 0 
+L 2766 531 
+Q 2569 213 2275 61 
+Q 1981 -91 1556 -91 
+Q 1019 -91 701 211 
+Q 384 513 384 1019 
+Q 384 1609 779 1909 
+Q 1175 2209 1959 2209 
+L 2766 2209 
+L 2766 2266 
+Q 2766 2663 2505 2880 
+Q 2244 3097 1772 3097 
+Q 1472 3097 1187 3025 
+Q 903 2953 641 2809 
+L 641 3341 
+Q 956 3463 1253 3523 
+Q 1550 3584 1831 3584 
+Q 2591 3584 2966 3190 
+Q 3341 2797 3341 1997 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-6c" d="M 603 4863 
+L 1178 4863 
+L 1178 0 
+L 603 0 
+L 603 4863 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-75" d="M 544 1381 
+L 544 3500 
+L 1119 3500 
+L 1119 1403 
+Q 1119 906 1312 657 
+Q 1506 409 1894 409 
+Q 2359 409 2629 706 
+Q 2900 1003 2900 1516 
+L 2900 3500 
+L 3475 3500 
+L 3475 0 
+L 2900 0 
+L 2900 538 
+Q 2691 219 2414 64 
+Q 2138 -91 1772 -91 
+Q 1169 -91 856 284 
+Q 544 659 544 1381 
+z
+M 1991 3584 
+L 1991 3584 
+z
+" transform="scale(0.015625)"/>
+      </defs>
+      <use xlink:href="#DejaVuSans-56"/>
+      <use xlink:href="#DejaVuSans-61" x="60.658203"/>
+      <use xlink:href="#DejaVuSans-6c" x="121.9375"/>
+      <use xlink:href="#DejaVuSans-75" x="149.720703"/>
+      <use xlink:href="#DejaVuSans-65" x="213.099609"/>
+     </g>
+    </g>
+   </g>
+   <g id="PolyCollection_1"/>
+   <g id="PolyCollection_2"/>
+   <g id="line2d_13">
+    <path d="M 184.581818 447.472913 
+L 187.560091 177.816004 
+L 189.977321 447.472913 
+L 192.937778 177.816004 
+L 195.340548 447.472913 
+L 198.283295 177.816004 
+L 200.671692 447.472913 
+L 203.596835 177.816004 
+L 205.970944 447.472913 
+L 208.878589 177.816004 
+L 211.238496 447.472913 
+L 214.128747 177.816004 
+L 216.474537 447.472913 
+L 219.347498 177.816004 
+L 221.679255 447.472913 
+L 224.53503 177.816004 
+L 226.852839 447.472913 
+L 229.69153 177.816004 
+L 231.995473 447.472913 
+L 234.817183 177.816004 
+L 237.107344 447.472913 
+L 239.912175 177.816004 
+L 242.188636 447.472913 
+L 244.976687 177.816004 
+L 247.23953 447.472913 
+L 250.010904 177.816004 
+L 252.26021 447.472913 
+L 255.015005 177.816004 
+L 257.250856 447.472913 
+L 259.989171 177.816004 
+L 262.211647 447.472913 
+L 264.933582 177.816004 
+L 267.142763 447.472913 
+L 269.848415 177.816004 
+L 272.04438 447.472913 
+L 274.733846 177.816004 
+L 276.916675 447.472913 
+L 279.590053 177.816004 
+L 281.759824 447.472913 
+L 284.41721 177.816004 
+L 286.574001 447.472913 
+L 289.21549 177.816004 
+L 291.359379 447.472913 
+L 293.985066 177.816004 
+L 296.11613 447.472913 
+L 298.726111 177.816004 
+L 300.844427 447.472913 
+L 303.438794 177.816004 
+L 305.544438 447.472913 
+L 308.123285 177.816004 
+L 310.216333 447.472913 
+L 312.779754 177.816004 
+L 314.860281 447.472913 
+L 317.408367 177.816004 
+L 319.476448 447.472913 
+L 322.009291 177.816004 
+L 324.065001 447.472913 
+L 326.582693 177.816004 
+L 328.626105 447.472913 
+L 331.128736 177.816004 
+L 333.159924 447.472913 
+L 335.647584 177.816004 
+L 337.666622 447.472913 
+L 340.1394 177.816004 
+L 342.14636 447.472913 
+L 344.604345 177.816004 
+L 346.5993 447.472913 
+L 349.042581 177.816004 
+L 351.025602 447.472913 
+L 353.454267 177.816004 
+L 355.425425 447.472913 
+L 357.839562 177.816004 
+L 359.798929 447.472913 
+L 362.198624 177.816004 
+L 364.146269 447.472913 
+L 366.53161 177.816004 
+L 368.467604 447.472913 
+L 370.838675 177.816004 
+L 372.763088 447.472913 
+L 375.119976 177.816004 
+L 377.032876 447.472913 
+L 379.375665 177.816004 
+L 381.277122 447.472913 
+L 383.605896 177.816004 
+L 385.495979 447.472913 
+L 387.810822 177.816004 
+L 389.689598 447.472913 
+L 391.990593 177.816004 
+L 393.85813 447.472913 
+L 396.145361 177.816004 
+L 398.001726 447.472913 
+L 400.275274 177.816004 
+L 402.120535 447.472913 
+L 404.380483 177.816004 
+L 406.214705 447.472913 
+L 408.461133 177.816004 
+L 410.284383 447.472913 
+L 412.517373 177.816004 
+L 414.329716 447.472913 
+L 416.549348 177.816004 
+L 418.350849 447.472913 
+L 420.557203 177.816004 
+L 422.347928 447.472913 
+L 424.541083 177.816004 
+L 426.321096 447.472913 
+L 428.501131 177.816004 
+L 430.270496 447.472913 
+L 432.43749 177.816004 
+L 434.19627 447.472913 
+L 436.350302 177.816004 
+L 438.09856 447.472913 
+L 440.239706 177.816004 
+L 441.977506 447.472913 
+L 444.105844 177.816004 
+L 445.833249 447.472913 
+L 447.948854 177.816004 
+L 449.665925 447.472913 
+L 451.768875 177.816004 
+L 453.475675 447.472913 
+L 455.566045 177.816004 
+L 457.262634 447.472913 
+L 459.340499 177.816004 
+L 461.026939 447.472913 
+L 463.092375 177.816004 
+L 464.768726 447.472913 
+L 466.821806 177.816004 
+L 468.48813 447.472913 
+L 470.528928 177.816004 
+L 472.185283 447.472913 
+L 474.213873 177.816004 
+L 475.86032 447.472913 
+L 477.876775 177.816004 
+L 479.513373 447.472913 
+L 481.517765 177.816004 
+L 483.144572 447.472913 
+L 485.136974 177.816004 
+L 486.75405 447.472913 
+L 488.734533 177.816004 
+L 490.341935 447.472913 
+L 492.310571 177.816004 
+L 493.908358 447.472913 
+L 495.865217 177.816004 
+L 497.453446 447.472913 
+L 499.398598 177.816004 
+L 500.977326 447.472913 
+L 502.910843 177.816004 
+L 504.480127 447.472913 
+L 506.402077 177.816004 
+L 507.961974 447.472913 
+L 509.872427 177.816004 
+L 511.422992 447.472913 
+L 513.322016 177.816004 
+L 514.863305 447.472913 
+L 516.75097 177.816004 
+L 518.283039 447.472913 
+L 520.159411 177.816004 
+L 521.682316 447.472913 
+L 523.547463 177.816004 
+L 525.061257 447.472913 
+L 526.915248 177.816004 
+L 528.419986 447.472913 
+L 530.262886 177.816004 
+L 531.758623 447.472913 
+L 533.590498 177.816004 
+L 535.077287 447.472913 
+L 536.898204 177.816004 
+L 538.376099 447.472913 
+L 540.186123 177.816004 
+L 541.655178 447.472913 
+L 543.454374 177.816004 
+L 544.91464 447.472913 
+L 546.703073 177.816004 
+L 548.154604 447.472913 
+L 549.932339 177.816004 
+L 551.375187 447.472913 
+L 553.142287 177.816004 
+L 554.576504 447.472913 
+L 556.333033 177.816004 
+L 557.75867 447.472913 
+L 559.504691 177.816004 
+L 560.9218 447.472913 
+L 562.657377 177.816004 
+L 564.066008 447.472913 
+L 565.791203 177.816004 
+L 567.191408 447.472913 
+L 568.906282 177.816004 
+L 570.29811 447.472913 
+L 572.002726 177.816004 
+L 573.386229 447.472913 
+L 575.080647 177.816004 
+L 576.455874 447.472913 
+L 578.140156 177.816004 
+L 579.507156 447.472913 
+L 581.181363 177.816004 
+L 582.540185 447.472913 
+L 584.204376 177.816004 
+L 585.55507 447.472913 
+L 587.209306 177.816004 
+L 588.55192 447.472913 
+L 590.196261 177.816004 
+L 591.530843 447.472913 
+L 593.165347 177.816004 
+L 594.491945 447.472913 
+L 596.116672 177.816004 
+L 597.435334 447.472913 
+L 599.050341 177.816004 
+L 600.361116 447.472913 
+L 601.966461 177.816004 
+L 603.269395 447.472913 
+L 604.865137 177.816004 
+L 606.160276 447.472913 
+L 607.746473 177.816004 
+L 609.033864 447.472913 
+L 610.610572 177.816004 
+L 611.890263 447.472913 
+L 613.457538 177.816004 
+L 614.729573 447.472913 
+L 616.287474 177.816004 
+L 617.551899 447.472913 
+L 619.10048 177.816004 
+L 620.357342 447.472913 
+L 621.896659 177.816004 
+L 623.146002 447.472913 
+L 624.676111 177.816004 
+L 625.91798 447.472913 
+L 627.438936 177.816004 
+L 628.673376 447.472913 
+L 630.185233 177.816004 
+L 631.412289 447.472913 
+L 632.915102 177.816004 
+L 634.134818 447.472913 
+L 635.628641 177.816004 
+L 636.84106 447.472913 
+L 638.325947 177.816004 
+L 639.531113 447.472913 
+L 641.007117 177.816004 
+L 642.205074 447.472913 
+L 643.672249 177.816004 
+L 644.863039 447.472913 
+L 646.321437 177.816004 
+L 647.505105 447.472913 
+L 648.954778 177.816004 
+L 650.131365 447.472913 
+L 651.572366 177.816004 
+L 652.741914 447.472913 
+L 654.174296 177.816004 
+L 655.336847 447.472913 
+L 656.76066 177.816004 
+L 657.916257 447.472913 
+L 659.331553 177.816004 
+L 660.480237 447.472913 
+L 661.887066 177.816004 
+L 663.028879 447.472913 
+L 664.427292 177.816004 
+L 665.562275 447.472913 
+L 666.952323 177.816004 
+L 668.080515 447.472913 
+L 669.462248 177.816004 
+L 670.583692 447.472913 
+L 671.957159 177.816004 
+L 673.071894 447.472913 
+L 674.437145 177.816004 
+L 675.545212 447.472913 
+L 676.902295 177.816004 
+L 678.003734 447.472913 
+L 679.352699 177.816004 
+L 680.447549 447.472913 
+L 681.788444 177.816004 
+L 682.876744 447.472913 
+L 684.209619 177.816004 
+L 685.291409 447.472913 
+L 686.61631 177.816004 
+L 687.691628 447.472913 
+L 689.008604 177.816004 
+L 690.077489 447.472913 
+L 691.386586 177.816004 
+L 692.449078 447.472913 
+L 693.750344 177.816004 
+L 694.80648 447.472913 
+L 696.099962 177.816004 
+L 697.149779 447.472913 
+L 698.435524 177.816004 
+L 699.479061 447.472913 
+L 700.757114 177.816004 
+L 701.794409 447.472913 
+L 703.064816 177.816004 
+L 704.095906 447.472913 
+L 705.358714 177.816004 
+L 706.383636 447.472913 
+L 707.638889 177.816004 
+L 708.65768 447.472913 
+L 709.905424 177.816004 
+L 710.918121 447.472913 
+L 712.158401 177.816004 
+L 713.165039 447.472913 
+L 714.3979 177.816004 
+L 715.398516 447.472913 
+L 716.624002 177.816004 
+L 717.618633 447.472913 
+L 718.836788 177.816004 
+L 719.825468 447.472913 
+L 721.036336 177.816004 
+L 722.019102 447.472913 
+L 723.222727 177.816004 
+L 724.199614 447.472913 
+L 725.396038 177.816004 
+L 726.367082 447.472913 
+L 727.556349 177.816004 
+L 728.521583 447.472913 
+L 729.703736 177.816004 
+L 730.663197 447.472913 
+L 731.838277 177.816004 
+L 732.791998 447.472913 
+L 733.96005 177.816004 
+L 734.908066 447.472913 
+L 736.06913 177.816004 
+L 737.011475 447.472913 
+L 738.165593 177.816004 
+L 739.102301 447.472913 
+L 740.249515 177.816004 
+L 741.180619 447.472913 
+L 742.320971 177.816004 
+L 743.246505 447.472913 
+L 744.380035 177.816004 
+L 745.300033 447.472913 
+L 746.426782 177.816004 
+L 747.341276 447.472913 
+L 748.461285 177.816004 
+L 749.370308 447.472913 
+L 750.483617 177.816004 
+L 751.387203 447.472913 
+L 752.493852 177.816004 
+L 753.392032 447.472913 
+L 754.492061 177.816004 
+L 755.384868 447.472913 
+L 756.478317 177.816004 
+L 757.365783 447.472913 
+L 758.452691 177.816004 
+L 759.334848 447.472913 
+L 760.415254 177.816004 
+L 761.292134 447.472913 
+L 762.366077 177.816004 
+L 763.237711 447.472913 
+L 764.305229 177.816004 
+L 765.17165 447.472913 
+L 766.232782 177.816004 
+L 767.09402 447.472913 
+L 768.148804 177.816004 
+L 769.00489 447.472913 
+L 770.053364 177.816004 
+L 770.904329 447.472913 
+L 771.946531 177.816004 
+L 772.792405 447.472913 
+L 773.828373 177.816004 
+L 774.669187 447.472913 
+L 775.698957 177.816004 
+L 776.534741 447.472913 
+L 777.558352 177.816004 
+L 778.389136 447.472913 
+L 779.406623 177.816004 
+L 780.232438 447.472913 
+L 781.243838 177.816004 
+L 782.064713 447.472913 
+L 783.070063 177.816004 
+L 783.886027 447.472913 
+L 784.885363 177.816004 
+L 785.696446 447.472913 
+L 786.689804 177.816004 
+L 787.496034 447.472913 
+L 788.48345 177.816004 
+L 789.284858 447.472913 
+L 790.266367 177.816004 
+L 791.062981 447.472913 
+L 792.038618 177.816004 
+L 792.830466 447.472913 
+L 793.800267 177.816004 
+L 794.587379 447.472913 
+L 795.551378 177.816004 
+L 796.333781 447.472913 
+L 797.292014 177.816004 
+L 798.069737 447.472913 
+L 799.022237 177.816004 
+L 799.795307 447.472913 
+L 800.74211 177.816004 
+L 801.510556 447.472913 
+L 802.451695 177.816004 
+L 803.215543 447.472913 
+L 804.151052 177.816004 
+L 804.910331 447.472913 
+L 805.840244 177.816004 
+L 806.594981 447.472913 
+L 807.519331 177.816004 
+L 808.269553 447.472913 
+L 809.188374 177.816004 
+L 809.934108 447.472913 
+L 810.847432 177.816004 
+L 811.588705 447.472913 
+L 812.496565 177.816004 
+L 813.233404 447.472913 
+L 814.135834 177.816004 
+L 814.868265 447.472913 
+L 815.765296 177.816004 
+L 816.493346 447.472913 
+L 817.385011 177.816004 
+L 818.108705 447.472913 
+L 818.995036 177.816004 
+L 819.714401 447.472913 
+L 820.59543 177.816004 
+L 821.310492 447.472913 
+L 822.18625 177.816004 
+L 822.897035 447.472913 
+L 823.767554 177.816004 
+L 824.474087 447.472913 
+L 825.339399 177.816004 
+L 826.041704 447.472913 
+L 826.90184 177.816004 
+L 827.599945 447.472913 
+L 828.454935 177.816004 
+L 829.148864 447.472913 
+L 829.998739 177.816004 
+L 830.688517 447.472913 
+L 831.533308 177.816004 
+L 832.218959 447.472913 
+L 833.058697 177.816004 
+L 833.740247 447.472913 
+L 834.574961 177.816004 
+L 835.252434 447.472913 
+L 836.082155 177.816004 
+L 836.755575 447.472913 
+L 837.580333 177.816004 
+L 838.249724 447.472913 
+L 839.069548 177.816004 
+L 839.734935 447.472913 
+L 840.549855 177.816004 
+L 841.211261 447.472913 
+L 842.021306 177.816004 
+L 842.678756 447.472913 
+L 843.483955 177.816004 
+L 844.137472 447.472913 
+L 844.937854 177.816004 
+L 845.587462 447.472913 
+L 846.383056 177.816004 
+L 847.028778 447.472913 
+L 847.819613 177.816004 
+L 848.461472 447.472913 
+L 849.247576 177.816004 
+L 849.885596 447.472913 
+L 850.666997 177.816004 
+L 851.3012 447.472913 
+L 852.077927 177.816004 
+L 852.708336 447.472913 
+L 853.480417 177.816004 
+L 854.107054 447.472913 
+L 854.874517 177.816004 
+L 855.497406 447.472913 
+L 856.260277 177.816004 
+L 856.87944 447.472913 
+L 857.637747 177.816004 
+L 858.253206 447.472913 
+L 859.006978 177.816004 
+L 859.618755 447.472913 
+L 860.368017 177.816004 
+L 860.976134 447.472913 
+L 861.720915 177.816004 
+L 862.325394 447.472913 
+L 863.065719 177.816004 
+L 863.666583 447.472913 
+L 864.402479 177.816004 
+L 864.999748 447.472913 
+L 865.731242 177.816004 
+L 866.324938 447.472913 
+L 867.052056 177.816004 
+L 867.642201 447.472913 
+L 868.36497 177.816004 
+L 868.951584 447.472913 
+L 869.670029 177.816004 
+L 870.253134 447.472913 
+L 870.967281 177.816004 
+L 871.546898 447.472913 
+L 872.256773 177.816004 
+L 872.832923 447.472913 
+L 873.538551 177.816004 
+L 874.111254 447.472913 
+L 874.812662 177.816004 
+L 875.381939 447.472913 
+L 876.07915 177.816004 
+L 876.645022 447.472913 
+L 877.338063 177.816004 
+L 877.900549 447.472913 
+L 878.589444 177.816004 
+L 879.148566 447.472913 
+L 879.83334 177.816004 
+L 880.389117 447.472913 
+L 881.069794 177.816004 
+L 881.622247 447.472913 
+L 882.298852 177.816004 
+L 882.848 447.472913 
+L 883.520558 177.816004 
+L 884.066421 447.472913 
+L 884.734955 177.816004 
+L 885.277553 447.472913 
+L 885.942088 177.816004 
+L 886.481439 447.472913 
+L 887.142 177.816004 
+L 887.678125 447.472913 
+L 888.334733 177.816004 
+L 888.867651 447.472913 
+L 889.520332 177.816004 
+L 890.050062 447.472913 
+L 890.698838 177.816004 
+L 891.225399 447.472913 
+L 891.870294 177.816004 
+L 892.393705 447.472913 
+L 893.034743 177.816004 
+L 893.555023 447.472913 
+L 894.192226 177.816004 
+L 894.709393 447.472913 
+L 895.342784 177.816004 
+L 895.856858 447.472913 
+L 896.48646 177.816004 
+L 896.997459 447.472913 
+L 897.623294 177.816004 
+L 898.131236 447.472913 
+L 898.753328 177.816004 
+L 899.258231 447.472913 
+L 899.876602 177.816004 
+L 900.378484 447.472913 
+L 900.993156 177.816004 
+L 901.492036 447.472913 
+L 902.103031 177.816004 
+L 902.598927 447.472913 
+L 903.206266 177.816004 
+L 903.699196 447.472913 
+L 904.302902 177.816004 
+L 904.792883 447.472913 
+L 905.392978 177.816004 
+L 905.880028 447.472913 
+L 906.476533 177.816004 
+L 906.960669 447.472913 
+L 907.553606 177.816004 
+L 908.034846 447.472913 
+L 908.624235 177.816004 
+L 909.102597 447.472913 
+L 909.68846 177.816004 
+L 910.16396 447.472913 
+L 910.746319 177.816004 
+L 911.218975 447.472913 
+L 911.79785 177.816004 
+L 912.267678 447.472913 
+L 912.84309 177.816004 
+L 913.310108 447.472913 
+L 913.882078 177.816004 
+L 914.346302 447.472913 
+L 914.91485 177.816004 
+L 915.376297 447.472913 
+L 915.941445 177.816004 
+L 916.400131 447.472913 
+L 916.961898 177.816004 
+L 917.41784 447.472913 
+L 917.976246 177.816004 
+L 918.429461 447.472913 
+L 918.984527 177.816004 
+L 919.435031 447.472913 
+L 919.986776 177.816004 
+L 920.434585 447.472913 
+L 920.98303 177.816004 
+L 921.42816 447.472913 
+L 921.973324 177.816004 
+L 922.415791 447.472913 
+L 922.957694 177.816004 
+L 923.397514 447.472913 
+L 923.936175 177.816004 
+L 924.373364 447.472913 
+L 924.908803 177.816004 
+L 925.343377 447.472913 
+L 925.875612 177.816004 
+L 926.307587 447.472913 
+L 926.836639 177.816004 
+L 927.266029 447.472913 
+L 927.791916 177.816004 
+L 928.218737 447.472913 
+L 928.741478 177.816004 
+L 929.165746 447.472913 
+L 929.685361 177.816004 
+L 930.107091 447.472913 
+L 930.623597 177.816004 
+L 931.042804 447.472913 
+L 931.55622 177.816004 
+L 931.972919 447.472913 
+L 932.483264 177.816004 
+L 932.897471 447.472913 
+L 933.404763 177.816004 
+L 933.816492 447.472913 
+L 934.320749 177.816004 
+L 934.730015 447.472913 
+L 935.231255 177.816004 
+L 935.638073 447.472913 
+L 936.136315 177.816004 
+L 936.540699 447.472913 
+L 937.035961 177.816004 
+L 937.437926 447.472913 
+L 937.930225 177.816004 
+L 938.329786 447.472913 
+L 938.81914 177.816004 
+L 939.21631 447.472913 
+L 939.702737 177.816004 
+L 940.097531 447.472913 
+L 940.581048 177.816004 
+L 940.97348 447.472913 
+L 941.454105 177.816004 
+L 941.84419 447.472913 
+L 942.321939 177.816004 
+L 942.709691 447.472913 
+L 943.184582 177.816004 
+L 943.570014 447.472913 
+L 944.042064 177.816004 
+L 944.425191 447.472913 
+L 944.894417 177.816004 
+L 945.275252 447.472913 
+L 945.741672 177.816004 
+L 946.120228 447.472913 
+L 946.583857 177.816004 
+L 946.960149 447.472913 
+L 947.421005 177.816004 
+L 947.795046 447.472913 
+L 948.253145 177.816004 
+L 948.624948 447.472913 
+L 949.080307 177.816004 
+L 949.449886 447.472913 
+L 949.902521 177.816004 
+L 950.269889 447.472913 
+L 950.719816 177.816004 
+L 951.084987 447.472913 
+L 951.532222 177.816004 
+L 951.895208 447.472913 
+L 952.339768 177.816004 
+L 952.700583 447.472913 
+L 953.142484 177.816004 
+L 953.50114 447.472913 
+L 953.940397 177.816004 
+L 954.296908 447.472913 
+L 954.733538 177.816004 
+L 955.087916 447.472913 
+L 955.521934 177.816004 
+L 955.874192 447.472913 
+L 956.305613 177.816004 
+L 956.655764 447.472913 
+L 957.084605 177.816004 
+L 957.432661 447.472913 
+L 957.858936 177.816004 
+L 958.20491 447.472913 
+L 958.628635 177.816004 
+L 958.97254 447.472913 
+L 959.39373 177.816004 
+L 959.735578 447.472913 
+L 960.154248 177.816004 
+L 960.494051 447.472913 
+L 960.910217 177.816004 
+L 961.247987 447.472913 
+L 961.661663 177.816004 
+L 961.997413 447.472913 
+L 962.408615 177.816004 
+L 962.742355 447.472913 
+L 963.151097 177.816004 
+L 963.482842 447.472913 
+L 963.889139 177.816004 
+L 964.218898 447.472913 
+L 964.622765 177.816004 
+L 964.950552 447.472913 
+L 965.352003 177.816004 
+L 965.677829 447.472913 
+L 966.076878 177.816004 
+L 966.400755 447.472913 
+L 966.797417 177.816004 
+L 967.119356 447.472913 
+L 967.513646 177.816004 
+L 967.833659 447.472913 
+L 968.22559 177.816004 
+L 968.543689 447.472913 
+L 968.933275 177.816004 
+L 969.249471 447.472913 
+L 969.636727 177.816004 
+L 969.951032 447.472913 
+L 970.33597 177.816004 
+L 970.648395 447.472913 
+L 971.031031 177.816004 
+L 971.341587 447.472913 
+L 971.721934 177.816004 
+L 972.030632 447.472913 
+L 972.408704 177.816004 
+L 972.715555 447.472913 
+L 973.091365 177.816004 
+L 973.396381 447.472913 
+L 973.769943 177.816004 
+L 974.073134 447.472913 
+L 974.444462 177.816004 
+L 974.745839 447.472913 
+L 975.114945 177.816004 
+L 975.41452 447.472913 
+L 975.781418 177.816004 
+L 976.0792 447.472913 
+L 976.443903 177.816004 
+L 976.739905 447.472913 
+L 977.102426 177.816004 
+L 977.396657 447.472913 
+L 977.757009 177.816004 
+L 978.04948 447.472913 
+L 978.407677 177.816004 
+L 978.698398 447.472913 
+L 979.054452 177.816004 
+L 979.343434 447.472913 
+L 979.697358 177.816004 
+L 979.984611 447.472913 
+L 980.336419 177.816004 
+L 980.621953 447.472913 
+L 980.971656 177.816004 
+L 981.255482 447.472913 
+L 981.603093 177.816004 
+L 981.885222 447.472913 
+L 982.230753 177.816004 
+L 982.511194 447.472913 
+L 982.854658 177.816004 
+L 983.133422 447.472913 
+L 983.474831 177.816004 
+L 983.751927 447.472913 
+L 984.091295 177.816004 
+L 984.366733 447.472913 
+L 984.70407 177.816004 
+L 984.97786 447.472913 
+L 985.31318 177.816004 
+L 985.585332 447.472913 
+L 985.918646 177.816004 
+L 986.18917 447.472913 
+L 986.52049 177.816004 
+L 986.789396 447.472913 
+L 987.118733 177.816004 
+L 987.386031 447.472913 
+L 987.713398 177.816004 
+L 987.979097 447.472913 
+L 988.304506 177.816004 
+L 988.568615 447.472913 
+L 988.892078 177.816004 
+L 989.154607 447.472913 
+L 989.476134 177.816004 
+L 989.737093 447.472913 
+L 990.056697 177.816004 
+L 990.316095 447.472913 
+L 990.633787 177.816004 
+L 990.891633 447.472913 
+L 991.207425 177.816004 
+L 991.463728 447.472913 
+L 991.777631 177.816004 
+L 992.032401 447.472913 
+L 992.344426 177.816004 
+L 992.597672 447.472913 
+L 992.90783 177.816004 
+L 993.159562 447.472913 
+L 993.467865 177.816004 
+L 993.71809 447.472913 
+L 994.024548 177.816004 
+L 994.273277 447.472913 
+L 994.577902 177.816004 
+L 994.825143 447.472913 
+L 995.127946 177.816004 
+L 995.373708 447.472913 
+L 995.674699 177.816004 
+L 995.918991 447.472913 
+L 996.218182 177.816004 
+L 996.218182 177.816004 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #4c72b0; stroke-width: 1.5; stroke-linecap: round"/>
+   </g>
+   <g id="line2d_14">
+    <path d="M 184.581818 89.28 
+L 187.560091 90.618847 
+L 189.977321 91.96039 
+L 192.937778 93.291147 
+L 195.340548 94.625049 
+L 198.283295 95.947717 
+L 200.671692 97.27353 
+L 203.596835 98.588107 
+L 205.970944 99.905831 
+L 208.878589 101.213217 
+L 211.238496 102.522851 
+L 214.128747 103.822148 
+L 216.474537 105.124141 
+L 219.347498 106.415798 
+L 221.679255 107.709701 
+L 224.53503 108.993718 
+L 226.852839 110.279981 
+L 229.69153 111.555908 
+L 231.995473 112.834531 
+L 234.817183 114.103267 
+L 237.107344 115.37425 
+L 239.912175 116.635345 
+L 242.188636 117.898688 
+L 244.976687 119.152143 
+L 247.23953 120.407845 
+L 250.010904 121.65366 
+L 252.26021 122.902172 
+L 255.015005 124.140346 
+L 257.250856 125.381218 
+L 259.989171 126.612201 
+L 262.211647 127.845882 
+L 264.933582 129.069675 
+L 267.142763 130.295715 
+L 269.848415 131.511867 
+L 272.04438 132.730717 
+L 274.733846 133.939679 
+L 276.916675 135.151337 
+L 279.590053 136.353108 
+L 281.759824 137.557126 
+L 284.41721 138.751706 
+L 286.574001 139.948983 
+L 289.21549 141.136372 
+L 291.359379 142.326008 
+L 293.985066 143.506656 
+L 296.11613 144.689102 
+L 298.726111 145.862559 
+L 300.844427 147.038263 
+L 303.438794 148.204529 
+L 305.544438 149.373042 
+L 308.123285 150.532567 
+L 310.216333 151.694339 
+L 312.779754 152.846673 
+L 314.860281 154.001254 
+L 317.408367 155.146846 
+L 319.476448 156.294686 
+L 322.009291 157.433087 
+L 324.065001 158.574186 
+L 326.582693 159.705846 
+L 328.626105 160.840202 
+L 331.128736 161.965121 
+L 333.159924 163.092287 
+L 335.647584 164.210464 
+L 337.666622 165.331338 
+L 340.1394 166.442774 
+L 342.14636 167.556907 
+L 344.604345 168.661601 
+L 346.5993 169.768992 
+L 349.042581 170.867395 
+L 351.025602 171.968044 
+L 353.454267 173.059705 
+L 355.425425 174.153613 
+L 357.839562 175.238983 
+L 359.798929 176.326599 
+L 362.198624 177.405226 
+L 364.146269 178.486101 
+L 366.53161 179.558437 
+L 368.467604 180.63302 
+L 370.838675 181.698614 
+L 372.763088 182.766905 
+L 375.119976 183.826207 
+L 377.032876 184.888206 
+L 379.375665 185.941216 
+L 381.277122 186.996473 
+L 383.605896 188.043641 
+L 385.495979 189.092606 
+L 387.810822 190.133033 
+L 389.689598 191.175706 
+L 391.990593 192.21029 
+L 393.85813 193.246671 
+L 396.145361 194.274963 
+L 398.001726 195.305052 
+L 400.275274 196.327501 
+L 402.120535 197.351299 
+L 404.380483 198.367456 
+L 406.214705 199.385411 
+L 408.461133 200.395276 
+L 410.284383 201.406938 
+L 412.517373 202.410961 
+L 414.329716 203.416781 
+L 416.549348 204.414512 
+L 418.350849 205.41449 
+L 420.557203 206.406378 
+L 422.347928 207.400063 
+L 424.541083 208.386109 
+L 426.321096 209.373952 
+L 428.501131 210.354155 
+L 430.270496 211.336155 
+L 432.43749 212.310066 
+L 434.19627 213.286224 
+L 436.350302 214.254742 
+L 438.09856 215.225057 
+L 440.239706 216.187733 
+L 441.977506 217.152205 
+L 444.105844 218.108589 
+L 445.833249 219.067668 
+L 447.948854 220.018658 
+L 449.665925 220.971446 
+L 451.768875 221.917043 
+L 453.475675 222.863988 
+L 455.566045 223.803743 
+L 457.262634 224.745744 
+L 459.340499 225.679656 
+L 461.026939 226.615815 
+L 463.092375 227.544333 
+L 464.768726 228.47465 
+L 466.821806 229.397326 
+L 468.48813 230.322249 
+L 470.528928 231.239532 
+L 472.185283 232.159062 
+L 474.213873 233.070952 
+L 475.86032 233.984639 
+L 477.876775 234.891136 
+L 479.513373 235.79943 
+L 481.517765 236.700534 
+L 483.144572 237.603435 
+L 485.136974 238.499145 
+L 486.75405 239.396653 
+L 488.734533 240.286971 
+L 490.341935 241.179086 
+L 492.310571 242.06401 
+L 493.908358 242.950731 
+L 495.865217 243.830712 
+L 497.453446 244.71204 
+L 499.398598 245.586628 
+L 500.977326 246.462563 
+L 502.910843 247.331757 
+L 504.480127 248.202749 
+L 506.402077 249.067 
+L 507.961974 249.932598 
+L 509.872427 250.791456 
+L 511.422992 251.65211 
+L 513.322016 252.505575 
+L 514.863305 253.361286 
+L 516.75097 254.209806 
+L 518.283039 255.060124 
+L 520.159411 255.903701 
+L 521.682316 256.748626 
+L 523.547463 257.587259 
+L 525.061257 258.42724 
+L 526.915248 259.26093 
+L 528.419986 260.095967 
+L 530.262886 260.924263 
+L 531.758623 261.754357 
+L 533.590498 262.578159 
+L 535.077287 263.403309 
+L 536.898204 264.221718 
+L 538.376099 265.041924 
+L 540.186123 265.855839 
+L 541.655178 266.671102 
+L 543.454374 267.480072 
+L 544.91464 268.290391 
+L 546.703073 269.094418 
+L 548.154604 269.899794 
+L 549.932339 270.698877 
+L 551.375187 271.499758 
+L 553.142287 272.294347 
+L 554.576504 273.090284 
+L 556.333033 273.87993 
+L 557.75867 274.670923 
+L 559.504691 275.456074 
+L 560.9218 276.242574 
+L 562.657377 277.022781 
+L 564.066008 277.804786 
+L 565.791203 278.580049 
+L 567.191408 279.357111 
+L 568.906282 280.12833 
+L 570.29811 280.900447 
+L 572.002726 281.666722 
+L 573.386229 282.434795 
+L 575.080647 283.196576 
+L 576.455874 283.959705 
+L 578.140156 284.716991 
+L 579.507156 285.475626 
+L 581.181363 286.228418 
+L 582.540185 286.982559 
+L 584.204376 287.730407 
+L 585.55507 288.480054 
+L 587.209306 289.223857 
+L 588.55192 289.969009 
+L 590.196261 290.708318 
+L 591.530843 291.448976 
+L 593.165347 292.183791 
+L 594.491945 292.919955 
+L 596.116672 293.650275 
+L 597.435334 294.381944 
+L 599.050341 295.10822 
+L 600.361116 295.835845 
+L 601.966461 296.557177 
+L 603.269395 297.280307 
+L 604.865137 297.998044 
+L 606.160276 298.716679 
+L 607.746473 299.429922 
+L 609.033864 300.144063 
+L 610.610572 300.852811 
+L 611.890263 301.563357 
+L 613.457538 302.267611 
+L 614.729573 302.973663 
+L 616.287474 303.674322 
+L 617.551899 304.375879 
+L 619.10048 305.072043 
+L 620.357342 305.769556 
+L 621.896659 306.461675 
+L 623.146002 307.155143 
+L 624.676111 307.842768 
+L 625.91798 308.532191 
+L 627.438936 309.215771 
+L 628.673376 309.901149 
+L 630.185233 310.580684 
+L 631.412289 311.261568 
+L 632.915102 311.937059 
+L 634.134818 312.614347 
+L 635.628641 313.285793 
+L 636.84106 313.958587 
+L 638.325947 314.625987 
+L 639.531113 315.295186 
+L 641.007117 315.958542 
+L 642.205074 316.623246 
+L 643.672249 317.283007 
+L 644.863039 317.943666 
+L 646.321437 318.599382 
+L 647.505105 319.256446 
+L 648.954778 319.908117 
+L 650.131365 320.561136 
+L 651.572366 321.208762 
+L 652.741914 321.858186 
+L 654.174296 322.501767 
+L 655.336847 323.147146 
+L 656.76066 323.787132 
+L 657.916257 324.428466 
+L 661.887066 326.33494 
+L 663.028879 326.968634 
+L 666.952323 328.851738 
+L 668.080515 329.478241 
+L 671.957159 331.338873 
+L 673.071894 331.957736 
+L 676.902295 333.796347 
+L 678.003734 334.408018 
+L 681.788444 336.224607 
+L 682.876744 336.828639 
+L 686.61631 338.624104 
+L 687.691628 339.220945 
+L 691.386586 340.994388 
+L 692.449078 341.584038 
+L 696.099962 343.336808 
+L 697.149779 343.919267 
+L 700.757114 345.651363 
+L 701.794409 346.227081 
+L 705.358714 347.938054 
+L 706.383636 348.50658 
+L 709.905424 350.197329 
+L 710.918121 350.759564 
+L 714.3979 352.430089 
+L 715.398516 352.985132 
+L 718.836788 354.635882 
+L 719.825468 355.184634 
+L 723.222727 356.815609 
+L 726.367082 358.434449 
+L 729.703736 360.036211 
+L 732.791998 361.626288 
+L 736.06913 363.199287 
+L 739.102301 364.76105 
+L 742.320971 366.306184 
+L 745.300033 367.840082 
+L 748.461285 369.357801 
+L 751.387203 370.864284 
+L 754.492061 372.354588 
+L 757.365783 373.834106 
+L 760.415254 375.298343 
+L 763.237711 376.751344 
+L 766.232782 378.189065 
+L 769.00489 379.616449 
+L 771.946531 381.028552 
+L 774.669187 382.430319 
+L 777.558352 383.817254 
+L 780.232438 385.194302 
+L 783.070063 386.556519 
+L 785.696446 387.908848 
+L 788.48345 389.246796 
+L 791.062981 390.574856 
+L 793.800267 391.888984 
+L 796.333781 393.193225 
+L 799.022237 394.483982 
+L 801.510556 395.764853 
+L 804.151052 397.03269 
+L 806.594981 398.291089 
+L 809.188374 399.536005 
+L 811.588705 400.771932 
+L 814.135834 401.994377 
+L 816.493346 403.208282 
+L 818.995036 404.409154 
+L 821.310492 405.601487 
+L 823.767554 406.780787 
+L 826.041704 407.951997 
+L 828.454935 409.110173 
+L 830.688517 410.26026 
+L 833.058697 411.398212 
+L 835.252434 412.527625 
+L 837.580333 413.645353 
+L 839.734935 414.754542 
+L 842.021306 415.852045 
+L 844.137472 416.941909 
+L 846.383056 418.019638 
+L 848.461472 419.089726 
+L 850.666997 420.148579 
+L 852.708336 421.199791 
+L 854.874517 422.239319 
+L 856.87944 423.271655 
+L 859.006978 424.293206 
+L 860.976134 425.307116 
+L 863.065719 426.310239 
+L 864.999748 427.305723 
+L 867.052056 428.291319 
+L 868.951584 429.269274 
+L 870.967281 430.236893 
+L 872.832923 431.197321 
+L 876.07915 432.777061 
+L 877.900549 433.715018 
+L 881.069794 435.257006 
+L 882.848 436.172941 
+L 885.942088 437.678525 
+L 887.678125 438.572438 
+L 890.698838 440.042517 
+L 892.393705 440.914857 
+L 895.342784 442.350331 
+L 896.997459 443.201997 
+L 899.876602 444.603315 
+L 901.492036 445.434757 
+L 904.302902 446.802816 
+L 906.960669 448.15155 
+L 909.68846 449.479161 
+L 912.267678 450.788345 
+L 914.91485 452.076406 
+L 917.41784 453.34694 
+L 919.986776 454.5968 
+L 922.415791 455.829581 
+L 924.908803 457.043037 
+L 927.266029 458.239415 
+L 929.685361 459.416467 
+L 931.972919 460.57779 
+L 934.320749 461.720236 
+L 936.540699 462.846953 
+L 938.81914 463.955692 
+L 940.97348 465.049151 
+L 943.184582 466.125082 
+L 945.275252 467.186182 
+L 948.253145 468.643677 
+L 950.269889 469.667475 
+L 953.142484 471.073736 
+L 955.087916 472.061129 
+L 957.858936 473.417504 
+L 959.735578 474.369842 
+L 962.408615 475.678577 
+L 964.218898 476.597208 
+L 966.797417 477.859202 
+L 969.249471 479.096478 
+L 971.721934 480.306788 
+L 974.073134 481.492829 
+L 976.443903 482.653253 
+L 978.698398 483.790306 
+L 981.603093 485.217241 
+L 983.751927 486.300812 
+L 986.52049 487.660782 
+L 988.568615 488.694017 
+L 991.207425 489.989718 
+L 993.159562 490.974416 
+L 995.674699 492.209894 
+L 996.218182 492.48 
+L 996.218182 492.48 
+" clip-path="url(#pc407524690)" style="fill: none; stroke: #dd8452; stroke-width: 1.5; stroke-linecap: round"/>
+   </g>
+   <g id="line2d_15"/>
+   <g id="line2d_16"/>
+   <g id="patch_3">
+    <path d="M 144 512.64 
+L 144 69.12 
+" style="fill: none; stroke: #ffffff; stroke-width: 1.25; stroke-linejoin: miter; stroke-linecap: square"/>
+   </g>
+   <g id="patch_4">
+    <path d="M 1036.8 512.64 
+L 1036.8 69.12 
+" style="fill: none; stroke: #ffffff; stroke-width: 1.25; stroke-linejoin: miter; stroke-linecap: square"/>
+   </g>
+   <g id="patch_5">
+    <path d="M 144 512.64 
+L 1036.8 512.64 
+" style="fill: none; stroke: #ffffff; stroke-width: 1.25; stroke-linejoin: miter; stroke-linecap: square"/>
+   </g>
+   <g id="patch_6">
+    <path d="M 144 69.12 
+L 1036.8 69.12 
+" style="fill: none; stroke: #ffffff; stroke-width: 1.25; stroke-linejoin: miter; stroke-linecap: square"/>
+   </g>
+   <g id="legend_1">
+    <g id="patch_7">
+     <path d="M 965.418125 127.325625 
+L 1029.1 127.325625 
+Q 1031.3 127.325625 1031.3 125.125625 
+L 1031.3 76.82 
+Q 1031.3 74.62 1029.1 74.62 
+L 965.418125 74.62 
+Q 963.218125 74.62 963.218125 76.82 
+L 963.218125 125.125625 
+Q 963.218125 127.325625 965.418125 127.325625 
+z
+" style="fill: #eaeaf2; opacity: 0.8; stroke: #cccccc; stroke-linejoin: miter"/>
+    </g>
+    <g id="text_15">
+     <!-- SoC - SoH -->
+     <g style="fill: #262626" transform="translate(967.618125 88.138125) scale(0.12 -0.12)">
+      <defs>
+       <path id="DejaVuSans-53" d="M 3425 4513 
+L 3425 3897 
+Q 3066 4069 2747 4153 
+Q 2428 4238 2131 4238 
+Q 1616 4238 1336 4038 
+Q 1056 3838 1056 3469 
+Q 1056 3159 1242 3001 
+Q 1428 2844 1947 2747 
+L 2328 2669 
+Q 3034 2534 3370 2195 
+Q 3706 1856 3706 1288 
+Q 3706 609 3251 259 
+Q 2797 -91 1919 -91 
+Q 1588 -91 1214 -16 
+Q 841 59 441 206 
+L 441 856 
+Q 825 641 1194 531 
+Q 1563 422 1919 422 
+Q 2459 422 2753 634 
+Q 3047 847 3047 1241 
+Q 3047 1584 2836 1778 
+Q 2625 1972 2144 2069 
+L 1759 2144 
+Q 1053 2284 737 2584 
+Q 422 2884 422 3419 
+Q 422 4038 858 4394 
+Q 1294 4750 2059 4750 
+Q 2388 4750 2728 4690 
+Q 3069 4631 3425 4513 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-6f" d="M 1959 3097 
+Q 1497 3097 1228 2736 
+Q 959 2375 959 1747 
+Q 959 1119 1226 758 
+Q 1494 397 1959 397 
+Q 2419 397 2687 759 
+Q 2956 1122 2956 1747 
+Q 2956 2369 2687 2733 
+Q 2419 3097 1959 3097 
+z
+M 1959 3584 
+Q 2709 3584 3137 3096 
+Q 3566 2609 3566 1747 
+Q 3566 888 3137 398 
+Q 2709 -91 1959 -91 
+Q 1206 -91 779 398 
+Q 353 888 353 1747 
+Q 353 2609 779 3096 
+Q 1206 3584 1959 3584 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-43" d="M 4122 4306 
+L 4122 3641 
+Q 3803 3938 3442 4084 
+Q 3081 4231 2675 4231 
+Q 1875 4231 1450 3742 
+Q 1025 3253 1025 2328 
+Q 1025 1406 1450 917 
+Q 1875 428 2675 428 
+Q 3081 428 3442 575 
+Q 3803 722 4122 1019 
+L 4122 359 
+Q 3791 134 3420 21 
+Q 3050 -91 2638 -91 
+Q 1578 -91 968 557 
+Q 359 1206 359 2328 
+Q 359 3453 968 4101 
+Q 1578 4750 2638 4750 
+Q 3056 4750 3426 4639 
+Q 3797 4528 4122 4306 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-20" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-2d" d="M 313 2009 
+L 1997 2009 
+L 1997 1497 
+L 313 1497 
+L 313 2009 
+z
+" transform="scale(0.015625)"/>
+       <path id="DejaVuSans-48" d="M 628 4666 
+L 1259 4666 
+L 1259 2753 
+L 3553 2753 
+L 3553 4666 
+L 4184 4666 
+L 4184 0 
+L 3553 0 
+L 3553 2222 
+L 1259 2222 
+L 1259 0 
+L 628 0 
+L 628 4666 
+z
+" transform="scale(0.015625)"/>
+      </defs>
+      <use xlink:href="#DejaVuSans-53"/>
+      <use xlink:href="#DejaVuSans-6f" x="63.476562"/>
+      <use xlink:href="#DejaVuSans-43" x="124.658203"/>
+      <use xlink:href="#DejaVuSans-20" x="194.482422"/>
+      <use xlink:href="#DejaVuSans-2d" x="226.269531"/>
+      <use xlink:href="#DejaVuSans-20" x="262.353516"/>
+      <use xlink:href="#DejaVuSans-53" x="294.140625"/>
+      <use xlink:href="#DejaVuSans-6f" x="357.617188"/>
+      <use xlink:href="#DejaVuSans-48" x="418.798828"/>
+     </g>
+    </g>
+    <g id="line2d_17">
+     <path d="M 970.865937 100.642031 
+L 981.865937 100.642031 
+L 992.865937 100.642031 
+" style="fill: none; stroke: #4c72b0; stroke-width: 1.5; stroke-linecap: round"/>
+    </g>
+    <g id="text_16">
+     <!-- SoC -->
+     <g style="fill: #262626" transform="translate(1001.665937 104.492031) scale(0.11 -0.11)">
+      <use xlink:href="#DejaVuSans-53"/>
+      <use xlink:href="#DejaVuSans-6f" x="63.476562"/>
+      <use xlink:href="#DejaVuSans-43" x="124.658203"/>
+     </g>
+    </g>
+    <g id="line2d_18">
+     <path d="M 970.865937 116.787969 
+L 981.865937 116.787969 
+L 992.865937 116.787969 
+" style="fill: none; stroke: #dd8452; stroke-width: 1.5; stroke-linecap: round"/>
+    </g>
+    <g id="text_17">
+     <!-- SoH -->
+     <g style="fill: #262626" transform="translate(1001.665937 120.637969) scale(0.11 -0.11)">
+      <use xlink:href="#DejaVuSans-53"/>
+      <use xlink:href="#DejaVuSans-6f" x="63.476562"/>
+      <use xlink:href="#DejaVuSans-48" x="124.658203"/>
+     </g>
+    </g>
+   </g>
+  </g>
+ </g>
+ <defs>
+  <clipPath id="pc407524690">
+   <rect x="144" y="69.12" width="892.8" height="443.52"/>
+  </clipPath>
+ </defs>
+</svg>
diff --git a/docs/source/tuto_dag/dag_lab1.cpp b/docs/source/tuto_dag/dag_lab1.cpp
deleted file mode 100644 (file)
index 1242ffa..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#include "simgrid/s4u.hpp"
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(main, "Messages specific for this s4u tutorial");
-
-int main(int argc, char* argv[]) {
-    simgrid::s4u::Engine e(&argc, argv);
-    e.load_platform(argv[1]);
-
-    simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
-    simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
-
-    simgrid::s4u::ExecPtr c1 = simgrid::s4u::Exec::init();
-    simgrid::s4u::ExecPtr c2 = simgrid::s4u::Exec::init();
-    simgrid::s4u::ExecPtr c3 = simgrid::s4u::Exec::init();
-    simgrid::s4u::CommPtr t1 = simgrid::s4u::Comm::sendto_init();
-
-    c1->set_name("c1");
-    c2->set_name("c2");
-    c3->set_name("c3");
-    t1->set_name("t1");
-
-    c1->set_flops_amount(1e9);
-    c2->set_flops_amount(5e9);
-    c3->set_flops_amount(2e9);
-    t1->set_payload_size(5e8);
-
-    c1->add_successor(t1);
-    t1->add_successor(c3);
-    c2->add_successor(c3);
-
-    c1->set_host(tremblay);
-    c2->set_host(jupiter);
-    c3->set_host(jupiter);
-    t1->set_source(tremblay);
-    t1->set_destination(jupiter);
-
-    c1->start();
-    c2->start();
-
-    simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-    XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", activity.get_cname(), activity.get_start_time(),
-             activity.get_finish_time());
-    });
-
-    e.run();
-       return 0;
-}
-
diff --git a/docs/source/tuto_dag/dag_lab2-1.cpp b/docs/source/tuto_dag/dag_lab2-1.cpp
deleted file mode 100644 (file)
index 9ee5baa..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "simgrid/s4u.hpp"
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(main, "Messages specific for this s4u example");
-
-int main(int argc, char* argv[]) {
-    simgrid::s4u::Engine e(&argc, argv);
-    e.load_platform(argv[1]);
-
-    std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_dot(argv[2]);
-
-    simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
-    simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
-    simgrid::s4u::Host* fafard  = e.host_by_name("Fafard");
-
-    dynamic_cast<simgrid::s4u::Exec*>(dag[0].get())->set_host(fafard);
-    dynamic_cast<simgrid::s4u::Exec*>(dag[1].get())->set_host(tremblay);
-    dynamic_cast<simgrid::s4u::Exec*>(dag[2].get())->set_host(jupiter);
-    dynamic_cast<simgrid::s4u::Exec*>(dag[3].get())->set_host(jupiter);
-    dynamic_cast<simgrid::s4u::Exec*>(dag[8].get())->set_host(jupiter);
-    
-    for (const auto& a : dag) {
-        if (auto* comm = dynamic_cast<simgrid::s4u::Comm*>(a.get())) {
-            auto pred = dynamic_cast<simgrid::s4u::Exec*>((*comm->get_dependencies().begin()).get());
-            auto succ = dynamic_cast<simgrid::s4u::Exec*>(comm->get_successors().front().get());
-            comm->set_source(pred->get_host())->set_destination(succ->get_host());
-        }
-    }
-
-    simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-    XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", activity.get_cname(), activity.get_start_time(),
-             activity.get_finish_time());
-    });
-
-    e.run();
-       return 0;
-}
-
diff --git a/docs/source/tuto_dag/dag_lab2-2.cpp b/docs/source/tuto_dag/dag_lab2-2.cpp
deleted file mode 100644 (file)
index f392ecb..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "simgrid/s4u.hpp"
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(main, "Messages specific for this s4u example");
-
-int main(int argc, char* argv[]) {
-    simgrid::s4u::Engine e(&argc, argv);
-    e.load_platform(argv[1]);
-
-    std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_json(argv[2]);
-
-    simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-    XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", activity.get_cname(), activity.get_start_time(),
-             activity.get_finish_time());
-    });
-
-    e.run();
-       return 0;
-}
-
diff --git a/docs/source/tuto_dag/dag_lab2-3.cpp b/docs/source/tuto_dag/dag_lab2-3.cpp
deleted file mode 100644 (file)
index e3db543..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "simgrid/s4u.hpp"
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(main, "Messages specific for this s4u example");
-
-int main(int argc, char* argv[]) {
-    simgrid::s4u::Engine e(&argc, argv);
-    e.load_platform(argv[1]);
-
-    std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_DAX(argv[2]);
-
-    simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
-    simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
-    simgrid::s4u::Host* fafard  = e.host_by_name("Fafard");
-
-    dynamic_cast<simgrid::s4u::Exec*>(dag[0].get())->set_host(fafard);
-    dynamic_cast<simgrid::s4u::Exec*>(dag[1].get())->set_host(tremblay);
-    dynamic_cast<simgrid::s4u::Exec*>(dag[2].get())->set_host(jupiter);
-    dynamic_cast<simgrid::s4u::Exec*>(dag[3].get())->set_host(jupiter);
-    dynamic_cast<simgrid::s4u::Exec*>(dag[8].get())->set_host(jupiter);
-    
-    for (const auto& a : dag) {
-        if (auto* comm = dynamic_cast<simgrid::s4u::Comm*>(a.get())) {
-            auto pred = dynamic_cast<simgrid::s4u::Exec*>((*comm->get_dependencies().begin()).get());
-            auto succ = dynamic_cast<simgrid::s4u::Exec*>(comm->get_successors().front().get());
-            comm->set_source(pred->get_host())->set_destination(succ->get_host());
-        }
-    }
-
-    simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-    XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", activity.get_cname(), activity.get_start_time(),
-             activity.get_finish_time());
-    });
-
-    e.run();
-       return 0;
-}
-
diff --git a/docs/source/tuto_dag/small_platform.xml b/docs/source/tuto_dag/small_platform.xml
deleted file mode 100644 (file)
index 69bdcae..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-<?xml version='1.0'?>
-<!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
-<platform version="4.1">
-  <zone id="zone0" routing="Full">
-    <host id="Tremblay" speed="98.095Mf"/>
-    <host id="Jupiter" speed="76.296Mf"/>
-    <host id="Fafard" speed="76.296Mf"/>
-    <host id="Ginette" speed="48.492Mf"/>
-    <host id="Bourassa" speed="48.492Mf"/>
-    <host id="Jacquelin" speed="137.333Mf"/>
-    <host id="Boivin" speed="98.095Mf"/>
-
-    <link id="6" bandwidth="41.279125MBps" latency="59.904us"/>
-    <link id="3" bandwidth="34.285625MBps" latency="514.433us"/>
-    <link id="7" bandwidth="11.618875MBps" latency="189.98us"/>
-    <link id="9" bandwidth="7.20975MBps" latency="1.461517ms"/>
-    <link id="2" bandwidth="118.6825MBps" latency="136.931us"/>
-    <link id="8" bandwidth="8.158MBps" latency="270.544us"/>
-    <link id="1" bandwidth="34.285625MBps" latency="514.433us"/>
-    <link id="4" bandwidth="10.099625MBps" latency="479.78us"/>
-    <link id="0" bandwidth="41.279125MBps" latency="59.904us"/>
-    <link id="5" bandwidth="27.94625MBps" latency="278.066us"/>
-    <link id="145" bandwidth="2.583375MBps" latency="410.463us"/>
-    <link id="10" bandwidth="34.285625MBps" latency="514.433us"/>
-    <link id="11" bandwidth="118.6825MBps" latency="136.931us"/>
-    <link id="16" bandwidth="34.285625MBps" latency="514.433us"/>
-    <link id="17" bandwidth="118.6825MBps" latency="136.931us"/>
-    <link id="44" bandwidth="10.314625MBps" latency="6.932556ms"/>
-    <link id="47" bandwidth="10.314625MBps" latency="6.932556ms"/>
-    <link id="54" bandwidth="15.376875MBps" latency="35.083019ms"/>
-    <link id="56" bandwidth="21.41475MBps" latency="29.5890617ms"/>
-    <link id="59" bandwidth="11.845375MBps" latency="370.788us"/>
-    <link id="78" bandwidth="27.94625MBps" latency="278.066us"/>
-    <link id="79" bandwidth="8.42725MBps" latency="156.056us"/>
-    <link id="80" bandwidth="15.376875MBps" latency="35.083019ms"/>
-    <link id="loopback" bandwidth="498MBps" latency="15us" sharing_policy="FATPIPE"/>
-
-    <route src="Tremblay" dst="Tremblay">
-      <link_ctn id="loopback"/>
-    </route>
-    <route src="Jupiter" dst="Jupiter">
-      <link_ctn id="loopback"/>
-    </route>
-    <route src="Fafard" dst="Fafard">
-      <link_ctn id="loopback"/>
-    </route>
-    <route src="Ginette" dst="Ginette">
-      <link_ctn id="loopback"/>
-    </route>
-    <route src="Bourassa" dst="Bourassa">
-      <link_ctn id="loopback"/>
-    </route>
-    <route src="Tremblay" dst="Jupiter">
-      <link_ctn id="9"/>
-    </route>
-    <route src="Tremblay" dst="Fafard">
-      <link_ctn id="4"/>
-      <link_ctn id="3"/>
-      <link_ctn id="2"/>
-      <link_ctn id="0"/>
-      <link_ctn id="1"/>
-      <link_ctn id="8"/>
-    </route>
-    <route src="Tremblay" dst="Ginette">
-      <link_ctn id="4"/>
-      <link_ctn id="3"/>
-      <link_ctn id="5"/>
-    </route>
-    <route src="Tremblay" dst="Bourassa">
-      <link_ctn id="4"/>
-      <link_ctn id="3"/>
-      <link_ctn id="2"/>
-      <link_ctn id="0"/>
-      <link_ctn id="1"/>
-      <link_ctn id="6"/>
-      <link_ctn id="7"/>
-    </route>
-    <route src="Jupiter" dst="Fafard">
-      <link_ctn id="9"/>
-      <link_ctn id="4"/>
-      <link_ctn id="3"/>
-      <link_ctn id="2"/>
-      <link_ctn id="0"/>
-      <link_ctn id="1"/>
-      <link_ctn id="8"/>
-    </route>
-    <route src="Jupiter" dst="Bourassa">
-      <link_ctn id="9"/>
-      <link_ctn id="4"/>
-      <link_ctn id="3"/>
-      <link_ctn id="2"/>
-      <link_ctn id="0"/>
-      <link_ctn id="1"/>
-      <link_ctn id="6"/>
-      <link_ctn id="7"/>
-    </route>
-    <route src="Fafard" dst="Ginette">
-      <link_ctn id="8"/>
-      <link_ctn id="1"/>
-      <link_ctn id="0"/>
-      <link_ctn id="2"/>
-      <link_ctn id="5"/>
-    </route>
-    <route src="Jupiter" dst="Jacquelin">
-      <link_ctn id="145"/>
-    </route>
-    <route src="Jupiter" dst="Boivin">
-      <link_ctn id="47"/>
-    </route>
-    <route src="Jupiter" dst="Ginette">
-      <link_ctn id="9"/>
-      <link_ctn id="4"/>
-      <link_ctn id="3"/>
-      <link_ctn id="5"/>
-    </route>
-    <route src="Fafard" dst="Bourassa">
-      <link_ctn id="8"/>
-      <link_ctn id="6"/>
-      <link_ctn id="7"/>
-    </route>
-    <route src="Ginette" dst="Bourassa">
-      <link_ctn id="5"/>
-      <link_ctn id="2"/>
-      <link_ctn id="0"/>
-      <link_ctn id="1"/>
-      <link_ctn id="6"/>
-      <link_ctn id="7"/>
-    </route>
-    <route src="Ginette" dst="Jacquelin">
-      <link_ctn id="145"/>
-    </route>
-    <route src="Ginette" dst="Boivin">
-      <link_ctn id="47"/>
-    </route>
-    <route src="Bourassa" dst="Jacquelin">
-      <link_ctn id="145"/>
-    </route>
-    <route src="Bourassa" dst="Boivin">
-      <link_ctn id="47"/>
-    </route>
-    <route src="Jacquelin" dst="Boivin">
-      <link_ctn id="145"/>
-      <link_ctn id="59"/>
-      <link_ctn id="56"/>
-      <link_ctn id="54"/>
-      <link_ctn id="17"/>
-      <link_ctn id="16"/>
-      <link_ctn id="10"/>
-      <link_ctn id="11"/>
-      <link_ctn id="44"/>
-      <link_ctn id="47"/>
-    </route>
-    <route src="Jacquelin" dst="Fafard">
-      <link_ctn id="145"/>
-      <link_ctn id="59"/>
-      <link_ctn id="56"/>
-      <link_ctn id="54"/>
-      <link_ctn id="17"/>
-      <link_ctn id="16"/>
-      <link_ctn id="10"/>
-      <link_ctn id="6"/>
-      <link_ctn id="9"/>
-      <link_ctn id="79"/>
-      <link_ctn id="78"/>
-    </route>
-    <route src="Jacquelin" dst="Tremblay">
-      <link_ctn id="145"/>
-      <link_ctn id="59"/>
-      <link_ctn id="56"/>
-      <link_ctn id="54"/>
-      <link_ctn id="2"/>
-      <link_ctn id="3"/>
-    </route>
-    <route src="Boivin" dst="Tremblay">
-      <link_ctn id="47"/>
-      <link_ctn id="44"/>
-      <link_ctn id="11"/>
-      <link_ctn id="10"/>
-      <link_ctn id="16"/>
-      <link_ctn id="0"/>
-      <link_ctn id="3"/>
-    </route>
-    <route src="Boivin" dst="Fafard">
-      <link_ctn id="47"/>
-      <link_ctn id="44"/>
-      <link_ctn id="11"/>
-      <link_ctn id="6"/>
-      <link_ctn id="9"/>
-      <link_ctn id="79"/>
-      <link_ctn id="78"/>
-      <link_ctn id="80"/>
-    </route>
-  </zone>
-</platform>
index d346172..ea673f3 100644 (file)
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 2.8.12)
 project(tuto_disk)
 
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
 
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/" "../../../")
 find_package(SimGrid REQUIRED)
index dbf2671..582d016 100644 (file)
@@ -20,7 +20,7 @@ RUN printf '%s\n' \
     r-cran-plyr \
     r-cran-jsonlite \
     r-cran-gridextra \
-# simgrid dependencies
+# SimGrid dependencies
     g++ \
     gcc \
     git \
@@ -41,7 +41,7 @@ RUN printf '%s\n' \
 RUN mkdir /source && cd /source && \
     git clone https://github.com/msnoigrs/ox-rst.git ox-rst.git
 
-# compile install simgrid
+# compile install SimGrid
 RUN cd /source && git clone --depth=1 https://framagit.org/simgrid/simgrid.git simgrid.git && \
     cd simgrid.git && \
     cmake -DCMAKE_INSTALL_PREFIX=/usr/ -Denable_documentation=OFF -Denable_smpi=ON -Denable_compile_optimizations=ON . && \
index 061ae71..cf1aba3 100644 (file)
@@ -17,7 +17,7 @@ XBT_LOG_NEW_DEFAULT_CATEGORY(example, "this example");
 
 static void server()
 {
-  auto mb = sg4::Mailbox::by_name("mymailbox");
+  auto* mb      = sg4::Mailbox::by_name("mymailbox");
   int value_got = -1;
   for (int count = 0; count < N; count++) {
     int *received = mb->get<int>();
index 72660b4..d8a7314 100644 (file)
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 2.8.12)
 project(tuto_network)
 
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
 
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/" "../../../")
 find_package(SimGrid REQUIRED)
index 3bf0cb6..105aa7d 100644 (file)
@@ -15,7 +15,7 @@ RUN printf '%s\n' \
     r-cran-dplyr \
     r-cran-irkernel \
     r-cran-quantreg \
-# simgrid dependencies
+# SimGrid dependencies
     g++ \
     gcc \
     git \
@@ -63,7 +63,7 @@ RUN pip install --no-cache-dir --upgrade pip && \
     papermill==2.3.3 \
     ipywidgets==7.6.5
 
-# simgrid
+# SimGrid
 RUN mkdir -p /source && cd /source && git clone --depth=1 https://framagit.org/simgrid/simgrid.git simgrid.git && \
     cd simgrid.git && \
     cmake -DCMAKE_INSTALL_PREFIX=/usr/ -Denable_documentation=OFF -Denable_smpi=ON -Denable_compile_optimizations=ON . && \
index 4ee3584..2ac5db2 100644 (file)
@@ -39,7 +39,7 @@ public:
  *
  * @param latency_base The base latency for this calibration (user-defined)
  * @param seg Segmentation (user-defined)
- * @param size Message size (simgrid)
+ * @param size Message size (SimGrid)
  */
 static double latency_factor_cb(double latency_base, const SegmentedRegression& seg, double size,
                                 const sg4::Host* /*src*/, const sg4::Host* /*dst*/,
@@ -57,7 +57,7 @@ static double latency_factor_cb(double latency_base, const SegmentedRegression&
  *
  * @param bw_base The base bandwidth for this calibration (user-defined)
  * @param seg Segmentation (user-defined)
- * @param size Message size (simgrid)
+ * @param size Message size (SimGrid)
  */
 static double bw_factor_cb(double bw_base, const SegmentedRegression& seg, double size, const sg4::Host* /*src*/,
                            const sg4::Host* /*dst*/, const std::vector<sg4::Link*>& /*links*/,
@@ -118,7 +118,7 @@ void load_platform(const sg4::Engine& e)
   static std::mt19937 gen(42); // remove it from stack, since we need it after this this load_platform function is over
 
   /* setting network factors callbacks */
-  auto zone = e.get_netzone_root();
+  auto* zone = e.get_netzone_root();
 
   SegmentedRegression seg = read_json_file("pingpong_ckmeans.json", gen, false);
   zone->set_latency_factor_cb(std::bind(&latency_factor_cb, lat_base, seg, std::placeholders::_1, std::placeholders::_2,
index cc817e3..d48288b 100644 (file)
@@ -38,7 +38,7 @@ public:
  *
  * @param latency_base The base latency for this calibration (user-defined)
  * @param seg Segmentation (user-defined)
- * @param size Message size (simgrid)
+ * @param size Message size (SimGrid)
  */
 static double latency_factor_cb(double latency_base, const SegmentedRegression& seg, double size,
                                 const sg4::Host* /*src*/, const sg4::Host* /*dst*/,
@@ -56,7 +56,7 @@ static double latency_factor_cb(double latency_base, const SegmentedRegression&
  *
  * @param bw_base The base bandwidth for this calibration (user-defined)
  * @param seg Segmentation (user-defined)
- * @param size Message size (simgrid)
+ * @param size Message size (SimGrid)
  */
 static double bw_factor_cb(double bw_base, const SegmentedRegression& seg, double size, const sg4::Host* /*src*/,
                            const sg4::Host* /*dst*/, const std::vector<sg4::Link*>& /*links*/,
index 8f7ebf2..7b77c0e 100644 (file)
     "import json\n",
     "\n",
     "def plot_compare(df):\n",
-    "    \"\"\" Auxiliary function to compare simgrid and reality \"\"\"\n",
+    "    \"\"\" Auxiliary function to compare SimGrid and reality \"\"\"\n",
     "    func = list(df['op'].unique())\n",
     "    assert len(func) == 1\n",
     "    func = func[0]\n",
     }
    ],
    "source": [
-    "# simgrid has fewer executions than real life, keep the same amount of samples for better visualization\n",
+    "# SimGrid has fewer executions than real life, keep the same amount of samples for better visualization\n",
     "N = df_smpi_send.groupby(\"msg_size\").size().iloc[0]\n",
     "\n",
     "tmp = pandas.concat([df_send.groupby(\"msg_size\").sample(N), df_smpi_send, df_isend.groupby(\"msg_size\").sample(N), df_smpi_isend, df_recv.groupby(\"msg_size\").sample(N), df_smpi_recv, df_pingpong.groupby(\"msg_size\").sample(N), df_smpi_pingpong])\n",
     }
    ],
    "source": [
-    "# simgrid has fewer executions than real life, keep the same amount of samples for better visualization\n",
+    "# SimGrid has fewer executions than real life, keep the same amount of samples for better visualization\n",
     "N = df_smpi_send.groupby(\"msg_size\").size().iloc[0]\n",
     "\n",
     "tmp = pandas.concat([df_send.groupby(\"msg_size\").sample(N), df_smpi_send, df_isend.groupby(\"msg_size\").sample(N), df_smpi_isend, df_recv.groupby(\"msg_size\").sample(N), df_smpi_recv, df_pingpong.groupby(\"msg_size\").sample(N), df_smpi_pingpong])\n",
index 99a2054..7a3d02d 100644 (file)
@@ -10,7 +10,7 @@ Specially, it is based on Tom Cornebize’s Phd thesis (https://tel.archives-ouv
 
 You can execute the notebook `network_calibration_tutorial.ipynb <https://framagit.org/simgrid/simgrid/tree/master/docs/source/tuto_network_calibration/network_calibration_tutorial.ipynb>`_) by yourself using the docker image
 available at: `Dockerfile <https://framagit.org/simgrid/simgrid/tree/master/docs/source/tuto_network_calibration/Dockerfile>`_. For that, run the
-following commands in the tutorial folder inside simgrid's code source (``docs/source/tuto_network_calibration``):
+following commands in the tutorial folder inside SimGrid's code source (``docs/source/tuto_network_calibration``):
 
 .. code-block::
 
index ecc2cc4..e412cd4 100644 (file)
@@ -6,7 +6,7 @@ library(pajengr)
 # Load and relabel the data
 df = pajeng_read(args[1])
 df$state %>%
-    # rename some columns to use simgrid terminology
+    # rename some columns to use SimGrid terminology
     rename(Actor = Container,
            State = Value) %>%
     # do the plot
index cbe1f7e..9b22d37 100644 (file)
@@ -1,4 +1,4 @@
-.. S4U (Simgrid for you) is the modern interface of SimGrid, which new project should use.
+.. S4U (SimGrid for you) is the modern interface of SimGrid, which new project should use.
 ..
 .. This file follows the ReStructured syntax to be included in the
 .. documentation, but it should remain readable directly.
@@ -366,7 +366,7 @@ Checking for incoming communications
 ------------------------------------
 
 This example uses ``Mailbox.ready()`` to check for completed communications. When this function returns true, then at least a message
-is arrived, so you know that ``Mailbox.get()`` will complete imediately. This is thus another way toward asynchronous communications.
+is arrived, so you know that ``Mailbox.get()`` will complete immediately. This is thus another way toward asynchronous communications.
 
 .. tabs::
 
@@ -398,59 +398,6 @@ The ``suspend()`` and ``resume()`` functions block the progression of a given co
       See also :py:func:`simgrid.Comm.suspend()` and
       :py:func:`simgrid.Comm.resume()`.
 
-Waiting for all communications in a set
----------------------------------------
-
-The ``wait_all()`` function is useful when you want to block until all activities in a given set have been completed.
-
-.. tabs::
-
-   .. example-tab:: examples/cpp/comm-waitall/s4u-comm-waitall.cpp
-
-      See also :cpp:func:`simgrid::s4u::Comm::wait_all()`.
-
-   .. example-tab:: examples/python/comm-waitall/comm-waitall.py
-
-      See also :py:func:`simgrid.Comm.wait_all()`.
-
-   .. example-tab:: examples/c/comm-waitall/comm-waitall.c
-
-      See also :cpp:func:`sg_comm_wait_all()`.
-
-Waiting for the first completed communication in a set
-------------------------------------------------------
-
-The ``wait_any()`` blocks until one activity of the set completes, no matter which terminates first.
-
-.. tabs::
-
-   .. example-tab:: examples/cpp/comm-waitany/s4u-comm-waitany.cpp
-
-      See also :cpp:func:`simgrid::s4u::Comm::wait_any()`.
-
-   .. example-tab:: examples/python/comm-waitany/comm-waitany.py
-
-      See also :py:func:`simgrid.Comm.wait_any()`.
-
-   .. example-tab:: examples/c/comm-waitany/comm-waitany.c
-
-      See also :cpp:func:`sg_comm_wait_any`.
-
-Testing whether at least one communication completed
-----------------------------------------------------
-
-The ``test_any()`` returns whether at least one activity of the set has completed, or -1.
-
-.. tabs::
-
-   .. example-tab:: examples/cpp/comm-testany/s4u-comm-testany.cpp
-
-      See also :cpp:func:`simgrid::s4u::Comm::test_any()`.
-
-   .. example-tab:: examples/python/comm-testany/comm-testany.py
-
-      See also :py:func:`simgrid.Comm.test_any()`.
-
 .. _s4u_ex_comm_failure:
 
 Dealing with network failures
@@ -620,7 +567,7 @@ on which they run is turned off: they are just terminated in this case, and thei
 failing hosts however, any blocking operation such as ``exec`` or ``wait`` will raise an exception that you can catch and react to. See also
 :ref:`howto_churn`,
 :ref:`this example <s4u_ex_platform_state_profile>` on how to attach a state profile to hosts, and
-:ref:`that example <s4u_ex_comm_failure>` on how to react to networ failures.
+:ref:`that example <s4u_ex_comm_failure>` on how to react to network failures.
 
 .. tabs::
 
@@ -715,6 +662,90 @@ result in short reads and short writes, as in reality.
 
        .. example-tab:: examples/c/io-file-remote/io-file-remote.c
 
+.. _s4u_ex_activityset:
+
+Bags of activities
+==================
+
+Sometimes, you want to block on a set of activities, getting unblocked when any activity of the set unblocks, or waiting for the
+completion of all activities in the set. This is where the ActivitySet become useful.
+
+Waiting for all activities in a set
+-----------------------------------
+
+The ``wait_all()`` function is useful when you want to block until all activities in a given set have been completed.
+
+.. tabs::
+
+   .. example-tab:: examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp
+
+      See also :cpp:func:`simgrid::s4u::ActivitySet::wait_all()`.
+
+   .. example-tab:: examples/python/activityset-waitall/activityset-waitall.py
+
+      See also :py:func:`simgrid.ActivitySet.wait_all()`.
+
+   .. example-tab:: examples/c/activityset-waitall/activityset-waitall.c
+
+      See also :cpp:func:`sg_activity_set_wait_all()`.
+
+Waiting for all activities in a set (with timeout)
+--------------------------------------------------
+
+The ``wait_all_for()`` function is very similar to ``wait_all()`` but allows to specify a timeout.
+
+.. tabs::
+
+   .. example-tab:: examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp
+
+      See also :cpp:func:`simgrid::s4u::ActivitySet::wait_all_for()`.
+
+   .. example-tab:: examples/python/activityset-waitallfor/activityset-waitallfor.py
+
+      See also :py:func:`simgrid.ActivitySet.wait_all_for()`.
+
+   .. example-tab:: examples/c/activityset-waitallfor/activityset-waitallfor.c
+
+      See also :cpp:func:`sg_activity_set_wait_all_for()`.
+
+Waiting for the first completed activity in a set
+-------------------------------------------------
+
+The ``wait_any()`` blocks until one activity of the set completes, no matter which terminates first.
+
+.. tabs::
+
+   .. example-tab:: examples/cpp/activityset-waitany/s4u-activityset-waitany.cpp
+
+      See also :cpp:func:`simgrid::s4u::ActivitySet::wait_any()`.
+
+   .. example-tab:: examples/python/activityset-waitany/activityset-waitany.py
+
+      See also :py:func:`simgrid.ActivitySet.wait_any()`.
+
+   .. example-tab:: examples/c/activityset-waitany/activityset-waitany.c
+
+      See also :cpp:func:`sg_activity_set_wait_any`.
+
+Testing whether at least one activity completed
+-----------------------------------------------
+
+The ``test_any()`` returns whether at least one activity of the set has completed.
+
+.. tabs::
+
+   .. example-tab:: examples/cpp/activityset-testany/s4u-activityset-testany.cpp
+
+      See also :cpp:func:`simgrid::s4u::ActivitySet::test_any()`.
+
+   .. example-tab:: examples/python/activityset-testany/activityset-testany.py
+
+      See also :py:func:`simgrid.ActivitySet.test_any()`.
+
+   .. example-tab:: examples/c/activityset-testany/activityset-testany.c
+
+      See also :cpp:func:`sg_activity_set_test_any`.
+
 .. _s4u_ex_dag:
 
 Dependencies between activities
@@ -727,7 +758,7 @@ schedules activities itself.
 Simple dependencies
 -------------------
 
-When you declare dependencies between two activities, the depedent will not actually start until all its dependencies complete,
+When you declare dependencies between two activities, the dependent will not actually start until all its dependencies complete,
 as shown in the following examples. The first one declare dependencies between executions while the second one declare
 dependencies between communications. You could declare such dependencies between arbitrary activities.
 
@@ -754,7 +785,7 @@ Simple DAG of activities
 ------------------------
 
 This example shows how to create activities from the maestro directly without relying on an actor, organize the dependencies of
-activities as a DAG (direct acyclic graph), and start them. Each activity will start as soon as its dependencies are fullfiled.
+activities as a DAG (direct acyclic graph), and start them. Each activity will start as soon as its dependencies are fulfilled.
 
 .. tabs::
 
@@ -791,7 +822,7 @@ to determine which host is the better fit for a given activity, and this example
 Loading DAGs from file
 ----------------------
 
-There is currently two file formats that you can load directly in SimGrid, but writting another loader for your beloved format should not be difficult.
+There is currently two file formats that you can load directly in SimGrid, but writing another loader for your beloved format should not be difficult.
 
 .. tabs::
 
index 25cccf5..3a9d3a6 100644 (file)
@@ -4,11 +4,12 @@
 foreach(x
         actor-create actor-daemon actor-exiting actor-join actor-kill actor-lifetime actor-migrate actor-stacksize
         actor-suspend actor-yield
+        activityset-testany activityset-waitall activityset-waitallfor activityset-waitany
         app-masterworker app-token-ring
-        comm-pingpong comm-wait comm-waitall comm-waitany
+        comm-pingpong comm-wait
         cloud-capping cloud-masterworker cloud-migration cloud-simple
         dht-pastry
-        exec-async exec-basic exec-dvfs exec-remote exec-waitany
+        exec-async exec-basic exec-dvfs exec-remote
         energy-exec energy-exec-ptask energy-vm
         io-disk-raw io-file-remote io-file-system
         platform-failures platform-properties
@@ -85,8 +86,6 @@ set(xml_files     ${xml_files} ${CMAKE_CURRENT_SOURCE_DIR}/actor-create/actor-cr
                                ${CMAKE_CURRENT_SOURCE_DIR}/comm-wait/comm-wait2_d.xml
                                ${CMAKE_CURRENT_SOURCE_DIR}/comm-wait/comm-wait3_d.xml
                                ${CMAKE_CURRENT_SOURCE_DIR}/comm-wait/comm-wait4_d.xml
-                               ${CMAKE_CURRENT_SOURCE_DIR}/comm-waitall/comm-waitall_d.xml
-                               ${CMAKE_CURRENT_SOURCE_DIR}/comm-waitany/comm-waitany_d.xml
                                ${CMAKE_CURRENT_SOURCE_DIR}/dht-kademlia/dht-kademlia_d.xml
                                ${CMAKE_CURRENT_SOURCE_DIR}/dht-pastry/dht-pastry_d.xml
                                ${CMAKE_CURRENT_SOURCE_DIR}/io-file-remote/io-file-remote_d.xml
@@ -96,11 +95,12 @@ set(xml_files     ${xml_files} ${CMAKE_CURRENT_SOURCE_DIR}/actor-create/actor-cr
 foreach(x
         actor-create actor-daemon actor-exiting actor-join actor-kill actor-lifetime actor-migrate actor-stacksize
         actor-suspend actor-yield
+        activityset-testany activityset-waitall activityset-waitallfor activityset-waitany
         app-bittorrent app-chainsend app-masterworker app-token-ring
-        comm-pingpong comm-wait comm-waitall comm-waitany
+        comm-pingpong comm-wait
         cloud-capping  cloud-masterworker cloud-migration cloud-simple
         dht-kademlia dht-pastry
-        exec-async exec-basic exec-dvfs exec-remote exec-waitany
+        exec-async exec-basic exec-dvfs exec-remote
         energy-exec energy-exec-ptask energy-vm
         io-disk-raw io-file-remote io-file-system
         platform-failures platform-properties
diff --git a/examples/c/activityset-testany/activityset-testany.c b/examples/c/activityset-testany/activityset-testany.c
new file mode 100644 (file)
index 0000000..b0c8702
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/activity_set.h"
+#include "simgrid/actor.h"
+#include "simgrid/comm.h"
+#include "simgrid/engine.h"
+#include "simgrid/exec.h"
+#include "simgrid/host.h"
+#include "simgrid/mailbox.h"
+
+#include "xbt/log.h"
+#include "xbt/sysdep.h"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_testany, "Messages specific for this s4u example");
+
+static void bob(int argc, char* argv[])
+{
+  XBT_INFO("Create my asynchronous activities");
+  sg_exec_t exec = sg_actor_exec_init(5e9);
+  sg_exec_start(exec);
+
+  sg_mailbox_t mbox = sg_mailbox_by_name("mbox");
+  void* payload     = NULL;
+  sg_comm_t comm    = sg_mailbox_get_async(mbox, &payload);
+
+  sg_activity_set_t pending_activities = sg_activity_set_init();
+  sg_activity_set_push(pending_activities, (sg_activity_t)exec);
+  sg_activity_set_push(pending_activities, (sg_activity_t)comm);
+
+  XBT_INFO("Sleep_for a while");
+  sg_actor_sleep_for(1);
+
+  XBT_INFO("Test for completed activities");
+  while (!sg_activity_set_empty(pending_activities)) {
+    sg_activity_t completed_one = sg_activity_set_test_any(pending_activities);
+    if (completed_one != NULL) {
+      if (sg_comm_isinstance(completed_one))
+        XBT_INFO("Completed a Comm");
+      if (sg_exec_isinstance(completed_one))
+        XBT_INFO("Completed an Exec");
+      sg_activity_unref(completed_one);
+    } else {
+      XBT_INFO("Nothing matches, test again in 0.5s");
+      sg_actor_sleep_for(.5);
+    }
+  }
+  XBT_INFO("Last activity is complete");
+  free(payload);
+}
+
+static void alice(int argc, char* argv[])
+{
+  char* payload = xbt_strdup("Message");
+  XBT_INFO("Send '%s'", payload);
+  sg_mailbox_put(sg_mailbox_by_name("mbox"), payload, 6e8);
+}
+
+int main(int argc, char* argv[])
+{
+  simgrid_init(&argc, argv);
+  xbt_assert(argc > 1,
+             "Usage: %s platform_file\n"
+             "\tExample: %s hosts_with_disks.xml\n",
+             argv[0], argv[0]);
+
+  simgrid_load_platform(argv[1]);
+
+  sg_actor_create("alice", sg_host_by_name("alice"), alice, 0, NULL);
+  sg_actor_create("bob", sg_host_by_name("bob"), bob, 0, NULL);
+
+  simgrid_run();
+
+  return 0;
+}
diff --git a/examples/c/activityset-testany/activityset-testany.tesh b/examples/c/activityset-testany/activityset-testany.tesh
new file mode 100644 (file)
index 0000000..6293fa3
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/c-activityset-testany ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%4.2r]%e[%5a]%e%m%n"
+> [0.00] [alice] Send 'Message'
+> [0.00] [  bob] Create my asynchronous activities
+> [0.00] [  bob] Sleep_for a while
+> [1.00] [  bob] Test for completed activities
+> [1.00] [  bob] Nothing matches, test again in 0.5s
+> [1.50] [  bob] Nothing matches, test again in 0.5s
+> [2.00] [  bob] Nothing matches, test again in 0.5s
+> [2.50] [  bob] Nothing matches, test again in 0.5s
+> [3.00] [  bob] Nothing matches, test again in 0.5s
+> [3.50] [  bob] Nothing matches, test again in 0.5s
+> [4.00] [  bob] Nothing matches, test again in 0.5s
+> [4.50] [  bob] Nothing matches, test again in 0.5s
+> [5.00] [  bob] Completed an Exec
+> [5.00] [  bob] Nothing matches, test again in 0.5s
+> [5.50] [  bob] Completed a Comm
+> [5.50] [  bob] Last activity is complete
diff --git a/examples/c/activityset-waitall/activityset-waitall.c b/examples/c/activityset-waitall/activityset-waitall.c
new file mode 100644 (file)
index 0000000..fe9e271
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/activity_set.h"
+#include "simgrid/actor.h"
+#include "simgrid/comm.h"
+#include "simgrid/engine.h"
+#include "simgrid/exec.h"
+#include "simgrid/host.h"
+#include "simgrid/mailbox.h"
+
+#include "xbt/log.h"
+#include "xbt/sysdep.h"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waitall, "Messages specific for this s4u example");
+
+static void bob()
+{
+  XBT_INFO("Create my asynchronous activities");
+  sg_exec_t exec = sg_actor_exec_init(5e9);
+  sg_exec_start(exec);
+
+  sg_mailbox_t mbox = sg_mailbox_by_name("mbox");
+  void* payload     = NULL;
+  sg_comm_t comm    = sg_mailbox_get_async(mbox, &payload);
+
+  sg_activity_set_t pending_activities = sg_activity_set_init();
+  sg_activity_set_push(pending_activities, (sg_activity_t)exec);
+  sg_activity_set_push(pending_activities, (sg_activity_t)comm);
+
+  XBT_INFO("Wait for asynchronous activities to complete, all in one shot.");
+  sg_activity_set_wait_all(pending_activities);
+  sg_activity_unref((sg_activity_t)exec);
+  sg_activity_unref((sg_activity_t)comm);
+
+  XBT_INFO("All activities are completed.");
+  free(payload);
+}
+
+static void alice()
+{
+  char* payload = xbt_strdup("Message");
+  XBT_INFO("Send '%s'", payload);
+  sg_mailbox_put(sg_mailbox_by_name("mbox"), payload, 6e8);
+}
+
+int main(int argc, char* argv[])
+{
+  simgrid_init(&argc, argv);
+  xbt_assert(argc > 1,
+             "Usage: %s platform_file\n"
+             "\tExample: %s hosts_with_disks.xml\n",
+             argv[0], argv[0]);
+
+  simgrid_load_platform(argv[1]);
+
+  sg_actor_create("alice", sg_host_by_name("alice"), alice, 0, NULL);
+  sg_actor_create("bob", sg_host_by_name("bob"), bob, 0, NULL);
+
+  simgrid_run();
+
+  return 0;
+}
diff --git a/examples/c/activityset-waitall/activityset-waitall.tesh b/examples/c/activityset-waitall/activityset-waitall.tesh
new file mode 100644 (file)
index 0000000..1093563
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/c-activityset-waitall ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%7.6r]%e[%5a]%e%m%n"
+> [0.000000] [alice] Send 'Message'
+> [0.000000] [  bob] Create my asynchronous activities
+> [0.000000] [  bob] Wait for asynchronous activities to complete, all in one shot.
+> [5.197828] [  bob] All activities are completed.
diff --git a/examples/c/activityset-waitallfor/activityset-waitallfor.c b/examples/c/activityset-waitallfor/activityset-waitallfor.c
new file mode 100644 (file)
index 0000000..5bc1ede
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/activity_set.h"
+#include "simgrid/actor.h"
+#include "simgrid/comm.h"
+#include "simgrid/engine.h"
+#include "simgrid/exec.h"
+#include "simgrid/host.h"
+#include "simgrid/mailbox.h"
+
+#include "xbt/log.h"
+#include "xbt/sysdep.h"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waitallfor, "Messages specific for this s4u example");
+
+static void bob()
+{
+  XBT_INFO("Create my asynchronous activities");
+  sg_exec_t exec = sg_actor_exec_init(5e9);
+  sg_exec_start(exec);
+
+  sg_mailbox_t mbox = sg_mailbox_by_name("mbox");
+  void* payload     = NULL;
+  sg_comm_t comm    = sg_mailbox_get_async(mbox, &payload);
+
+  sg_activity_set_t pending_activities = sg_activity_set_init();
+  sg_activity_set_push(pending_activities, (sg_activity_t)exec);
+  sg_activity_set_push(pending_activities, (sg_activity_t)comm);
+
+  XBT_INFO("Wait for asynchronous activities to complete");
+  while (!sg_activity_set_empty(pending_activities)) {
+    if (!sg_activity_set_wait_all_for(pending_activities, 1)) {
+      XBT_INFO("Not all activities are terminated yet.");
+    }
+
+    sg_activity_t completed_one = sg_activity_set_test_any(pending_activities);
+    while (completed_one != NULL) {
+      if (sg_comm_isinstance(completed_one))
+        XBT_INFO("Completed a Comm");
+      if (sg_exec_isinstance(completed_one))
+        XBT_INFO("Completed an Exec");
+      sg_activity_unref(completed_one);
+      completed_one = sg_activity_set_test_any(pending_activities);
+    }
+  }
+
+  XBT_INFO("Last activity is complete");
+  free(payload);
+}
+
+static void alice()
+{
+  char* payload = xbt_strdup("Message");
+  XBT_INFO("Send '%s'", payload);
+  sg_mailbox_put(sg_mailbox_by_name("mbox"), payload, 6e8);
+}
+
+int main(int argc, char* argv[])
+{
+  simgrid_init(&argc, argv);
+  xbt_assert(argc > 1,
+             "Usage: %s platform_file\n"
+             "\tExample: %s hosts_with_disks.xml\n",
+             argv[0], argv[0]);
+
+  simgrid_load_platform(argv[1]);
+
+  sg_actor_create("alice", sg_host_by_name("alice"), alice, 0, NULL);
+  sg_actor_create("bob", sg_host_by_name("bob"), bob, 0, NULL);
+
+  simgrid_run();
+
+  return 0;
+}
diff --git a/examples/c/activityset-waitallfor/activityset-waitallfor.tesh b/examples/c/activityset-waitallfor/activityset-waitallfor.tesh
new file mode 100644 (file)
index 0000000..26a73c5
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/c-activityset-waitallfor ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%7.6r]%e[%5a]%e%m%n"
+> [0.000000] [alice] Send 'Message'
+> [0.000000] [  bob] Create my asynchronous activities
+> [0.000000] [  bob] Wait for asynchronous activities to complete
+> [1.000000] [  bob] Not all activities are terminated yet.
+> [2.000000] [  bob] Not all activities are terminated yet.
+> [3.000000] [  bob] Not all activities are terminated yet.
+> [4.000000] [  bob] Not all activities are terminated yet.
+> [5.000000] [  bob] Not all activities are terminated yet.
+> [5.000000] [  bob] Completed an Exec
+> [5.197828] [  bob] Completed a Comm
+> [5.197828] [  bob] Last activity is complete
diff --git a/examples/c/activityset-waitany/activityset-waitany.c b/examples/c/activityset-waitany/activityset-waitany.c
new file mode 100644 (file)
index 0000000..3bf9b25
--- /dev/null
@@ -0,0 +1,72 @@
+/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/activity_set.h"
+#include "simgrid/actor.h"
+#include "simgrid/comm.h"
+#include "simgrid/engine.h"
+#include "simgrid/exec.h"
+#include "simgrid/host.h"
+#include "simgrid/mailbox.h"
+
+#include "xbt/log.h"
+#include "xbt/sysdep.h"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waittany, "Messages specific for this s4u example");
+
+static void bob()
+{
+  XBT_INFO("Create my asynchronous activities");
+  sg_exec_t exec = sg_actor_exec_init(5e9);
+  sg_exec_start(exec);
+
+  sg_mailbox_t mbox = sg_mailbox_by_name("mbox");
+  void* payload     = NULL;
+  sg_comm_t comm    = sg_mailbox_get_async(mbox, &payload);
+
+  sg_activity_set_t pending_activities = sg_activity_set_init();
+  sg_activity_set_push(pending_activities, (sg_activity_t)exec);
+  sg_activity_set_push(pending_activities, (sg_activity_t)comm);
+
+  XBT_INFO("Wait for asynchronous activities to complete");
+  while (!sg_activity_set_empty(pending_activities)) {
+
+    sg_activity_t completed_one = sg_activity_set_wait_any(pending_activities);
+    if (sg_comm_isinstance(completed_one))
+      XBT_INFO("Completed a Comm");
+    else if (sg_exec_isinstance(completed_one))
+      XBT_INFO("Completed an Exec");
+    else
+      xbt_die("This activity set is supposed to only contain Comm or Exec");
+    sg_activity_unref(completed_one);
+  }
+  XBT_INFO("Last activity is complete");
+  free(payload);
+}
+
+static void alice()
+{
+  char* payload = xbt_strdup("Message");
+  XBT_INFO("Send '%s'", payload);
+  sg_mailbox_put(sg_mailbox_by_name("mbox"), payload, 6e8);
+}
+
+int main(int argc, char* argv[])
+{
+  simgrid_init(&argc, argv);
+  xbt_assert(argc > 1,
+             "Usage: %s platform_file\n"
+             "\tExample: %s hosts_with_disks.xml\n",
+             argv[0], argv[0]);
+
+  simgrid_load_platform(argv[1]);
+
+  sg_actor_create("alice", sg_host_by_name("alice"), alice, 0, NULL);
+  sg_actor_create("bob", sg_host_by_name("bob"), bob, 0, NULL);
+
+  simgrid_run();
+
+  return 0;
+}
diff --git a/examples/c/activityset-waitany/activityset-waitany.tesh b/examples/c/activityset-waitany/activityset-waitany.tesh
new file mode 100644 (file)
index 0000000..dac02a8
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/c-activityset-waitany ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%7.6r]%e[%5a]%e%m%n"
+> [0.000000] [alice] Send 'Message'
+> [0.000000] [  bob] Create my asynchronous activities
+> [0.000000] [  bob] Wait for asynchronous activities to complete
+> [5.000000] [  bob] Completed an Exec
+> [5.197828] [  bob] Completed a Comm
+> [5.197828] [  bob] Last activity is complete
index 3e71581..7133408 100644 (file)
@@ -36,16 +36,14 @@ static void broadcaster_build_chain(broadcaster_t bc)
 
 static void broadcaster_send_file(const_broadcaster_t bc)
 {
-  int nb_pending_sends = 0;
-
   for (unsigned int current_piece = 0; current_piece < bc->piece_count; current_piece++) {
     XBT_DEBUG("Sending (send) piece %u from %s into mailbox %s", current_piece, sg_host_self_get_name(),
               sg_mailbox_get_name(bc->first));
     char* file_piece = bprintf("piece-%u", current_piece);
     sg_comm_t comm   = sg_mailbox_put_async(bc->first, file_piece, MESSAGE_SEND_DATA_HEADER_SIZE + PIECE_SIZE);
-    bc->pending_sends[nb_pending_sends++] = comm;
+    sg_activity_set_push(bc->pending_sends, (sg_activity_t)comm);
   }
-  sg_comm_wait_all(bc->pending_sends, nb_pending_sends);
+  sg_activity_set_wait_all(bc->pending_sends);
 }
 
 static broadcaster_t broadcaster_init(sg_mailbox_t* mailboxes, unsigned int host_count, unsigned int piece_count)
@@ -56,7 +54,7 @@ static broadcaster_t broadcaster_init(sg_mailbox_t* mailboxes, unsigned int host
   bc->host_count    = host_count;
   bc->piece_count   = piece_count;
   bc->mailboxes     = mailboxes;
-  bc->pending_sends = xbt_malloc(sizeof(sg_comm_t) * MAX_PENDING_COMMS);
+  bc->pending_sends = sg_activity_set_init();
 
   broadcaster_build_chain(bc);
 
@@ -65,7 +63,7 @@ static broadcaster_t broadcaster_init(sg_mailbox_t* mailboxes, unsigned int host
 
 static void broadcaster_destroy(broadcaster_t bc)
 {
-  xbt_free(bc->pending_sends);
+  sg_activity_set_delete(bc->pending_sends);
   xbt_free(bc->mailboxes);
   xbt_free(bc);
 }
index 8bbe961..86a86aa 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef CHAINSEND_H
 #define CHAINSEND_H
 
+#include "simgrid/activity_set.h"
 #include "simgrid/actor.h"
 #include "simgrid/comm.h"
 #include "simgrid/engine.h"
@@ -30,7 +31,7 @@ typedef struct s_broadcaster {
   unsigned int piece_count;
   sg_mailbox_t first;
   sg_mailbox_t* mailboxes;
-  sg_comm_t* pending_sends;
+  sg_activity_set_t pending_sends;
 } s_broadcaster_t;
 
 typedef s_broadcaster_t* broadcaster_t;
@@ -54,8 +55,8 @@ typedef struct s_peer {
   unsigned long long received_bytes;
   unsigned int received_pieces;
   unsigned int total_pieces;
-  sg_comm_t* pending_recvs;
-  sg_comm_t* pending_sends;
+  sg_activity_set_t pending_recvs;
+  sg_activity_set_t pending_sends;
 } s_peer_t;
 
 typedef s_peer_t* peer_t;
index 513c123..f4591f8 100644 (file)
@@ -1,5 +1,4 @@
-/* Copyright (c) 2012-2023. The SimGrid Team.
- * All rights reserved.                                                     */
+/* Copyright (c) 2012-2023. The SimGrid Team. All rights reserved.          */
 
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
@@ -22,26 +21,21 @@ static void peer_join_chain(peer_t p)
 static void peer_forward_file(peer_t p)
 {
   void* received;
-  int done                = 0;
-  size_t nb_pending_sends = 0;
-  size_t nb_pending_recvs = 0;
+  int done = 0;
 
   while (!done) {
-    p->pending_recvs[nb_pending_recvs] = sg_mailbox_get_async(p->me, &received);
-    nb_pending_recvs++;
+    sg_activity_set_push(p->pending_recvs, (sg_activity_t)sg_mailbox_get_async(p->me, &received));
 
-    ssize_t idx = sg_comm_wait_any(p->pending_recvs, nb_pending_recvs);
-    if (idx != -1) {
+    sg_activity_t acti = sg_activity_set_wait_any(p->pending_recvs);
+    if (acti != NULL) {
+      sg_comm_unref((sg_comm_t)acti);
       XBT_DEBUG("Peer %s got a 'SEND_DATA' message", sg_mailbox_get_name(p->me));
-      /* move the last pending comm where the finished one was, and decrement */
-      p->pending_recvs[idx] = p->pending_recvs[--nb_pending_recvs];
 
       if (p->next != NULL) {
         XBT_DEBUG("Sending %s (asynchronously) from %s to %s", (char*)received, sg_mailbox_get_name(p->me),
                   sg_mailbox_get_name(p->next));
         sg_comm_t send = sg_mailbox_put_async(p->next, received, MESSAGE_SEND_DATA_HEADER_SIZE + PIECE_SIZE);
-        p->pending_sends[nb_pending_sends] = send;
-        nb_pending_sends++;
+        sg_activity_set_push(p->pending_sends, (sg_activity_t)send);
       } else
         free(received);
 
@@ -53,7 +47,7 @@ static void peer_forward_file(peer_t p)
       }
     }
   }
-  sg_comm_wait_all(p->pending_sends, nb_pending_sends);
+  sg_activity_set_wait_all(p->pending_sends);
 }
 
 static peer_t peer_init(int argc, char* argv[])
@@ -63,8 +57,8 @@ static peer_t peer_init(int argc, char* argv[])
   p->next            = NULL;
   p->received_pieces = 0;
   p->received_bytes  = 0;
-  p->pending_recvs   = xbt_malloc(sizeof(sg_comm_t) * MAX_PENDING_COMMS);
-  p->pending_sends   = xbt_malloc(sizeof(sg_comm_t) * MAX_PENDING_COMMS);
+  p->pending_recvs   = sg_activity_set_init();
+  p->pending_sends   = sg_activity_set_init();
 
   p->me = sg_mailbox_by_name(sg_host_self_get_name());
 
@@ -73,8 +67,8 @@ static peer_t peer_init(int argc, char* argv[])
 
 static void peer_delete(peer_t p)
 {
-  xbt_free(p->pending_recvs);
-  xbt_free(p->pending_sends);
+  sg_activity_set_delete(p->pending_recvs);
+  sg_activity_set_delete(p->pending_sends);
 
   xbt_free(p);
 }
diff --git a/examples/c/comm-waitall/comm-waitall.c b/examples/c/comm-waitall/comm-waitall.c
deleted file mode 100644 (file)
index 4477c68..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "simgrid/actor.h"
-#include "simgrid/comm.h"
-#include "simgrid/engine.h"
-#include "simgrid/host.h"
-#include "simgrid/mailbox.h"
-
-#include "xbt/log.h"
-#include "xbt/str.h"
-#include "xbt/sysdep.h"
-
-#include <stdio.h> /* snprintf */
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(comm_waitall, "Messages specific for this example");
-
-static void sender(int argc, char* argv[])
-{
-  xbt_assert(argc == 4, "This function expects 3 parameters from the XML deployment file");
-  long messages_count  = xbt_str_parse_int(argv[1], "Invalid message count");
-  long message_size    = xbt_str_parse_int(argv[2], "Invalid message size");
-  long receivers_count = xbt_str_parse_int(argv[3], "Invalid amount of receivers");
-  xbt_assert(receivers_count > 0);
-
-  /* Array in which we store all ongoing communications */
-  sg_comm_t* pending_comms = xbt_malloc(sizeof(sg_comm_t) * (messages_count + receivers_count));
-  int pending_comms_count  = 0;
-
-  /* Make an array of the mailboxes to use */
-  sg_mailbox_t* mboxes = xbt_malloc(sizeof(sg_mailbox_t) * receivers_count);
-  for (long i = 0; i < receivers_count; i++) {
-    char mailbox_name[80];
-    snprintf(mailbox_name, 79, "receiver-%ld", i);
-    sg_mailbox_t mbox = sg_mailbox_by_name(mailbox_name);
-    mboxes[i]         = mbox;
-  }
-
-  /* Start dispatching all messages to receivers, in a round robin fashion */
-  for (long i = 0; i < messages_count; i++) {
-    char msg_content[80];
-    snprintf(msg_content, 79, "Message %ld", i);
-    sg_mailbox_t mbox = mboxes[i % receivers_count];
-    XBT_INFO("Send '%s' to '%s'", msg_content, sg_mailbox_get_name(mbox));
-    /* Create a communication representing the ongoing communication, and store it in pending_comms */
-    pending_comms[pending_comms_count++] = sg_mailbox_put_async(mbox, xbt_strdup(msg_content), message_size);
-  }
-
-  /* Start sending messages to let the workers know that they should stop */
-  for (long i = 0; i < receivers_count; i++) {
-    XBT_INFO("Send 'finalize' to 'receiver-%ld'", i);
-    char* end_msg                        = xbt_strdup("finalize");
-    sg_mailbox_t mbox                    = mboxes[i % receivers_count];
-    pending_comms[pending_comms_count++] = sg_mailbox_put_async(mbox, end_msg, 0);
-  }
-
-  XBT_INFO("Done dispatching all messages");
-
-  /* Now that all message exchanges were initiated, wait for their completion in one single call */
-  sg_comm_wait_all(pending_comms, pending_comms_count);
-
-  xbt_free(pending_comms);
-  xbt_free(mboxes);
-
-  XBT_INFO("Goodbye now!");
-}
-
-static void receiver(int argc, char* argv[])
-{
-  xbt_assert(argc == 2, "Expecting one parameter from the XML deployment file but got %d", argc);
-  int id = (int)xbt_str_parse_int(argv[1], "ID should be numerical");
-  char mailbox_name[80];
-  snprintf(mailbox_name, 79, "receiver-%d", id);
-  sg_mailbox_t mbox = sg_mailbox_by_name(mailbox_name);
-  XBT_INFO("Wait for my first message");
-  while (1) {
-    char* received = (char*)sg_mailbox_get(mbox);
-    XBT_INFO("I got a '%s'.", received);
-    if (!strcmp(received, "finalize")) { // If it's a finalize message, we're done
-      xbt_free(received);
-      break;
-    }
-    xbt_free(received);
-  }
-}
-
-int main(int argc, char* argv[])
-{
-  simgrid_init(&argc, argv);
-  xbt_assert(argc > 2,
-             "Usage: %s platform_file deployment_file\n"
-             "\tExample: %s platform.xml deployment.xml\n",
-             argv[0], argv[0]);
-
-  simgrid_load_platform(argv[1]);
-
-  simgrid_register_function("sender", sender);
-  simgrid_register_function("receiver", receiver);
-  simgrid_load_deployment(argv[2]);
-
-  simgrid_run();
-
-  return 0;
-}
diff --git a/examples/c/comm-waitall/comm-waitall.tesh b/examples/c/comm-waitall/comm-waitall.tesh
deleted file mode 100644 (file)
index 1c3cfe6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env tesh
-
-! output sort 19
-$ ${bindir:=.}/c-comm-waitall ${platfdir:=.}/small_platform_fatpipe.xml ${srcdir:=.}/comm-waitall_d.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (1:sender@Tremblay) Send 'Message 0' to 'receiver-0'
-> [  0.000000] (2:receiver@Ruby) Wait for my first message
-> [  0.000000] (3:receiver@Perl) Wait for my first message
-> [  0.000000] (1:sender@Tremblay) Send 'Message 1' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 2' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 3' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 4' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Done dispatching all messages
-> [  0.004022] (2:receiver@Ruby) I got a 'Message 0'.
-> [  0.004022] (3:receiver@Perl) I got a 'Message 1'.
-> [  0.008043] (2:receiver@Ruby) I got a 'Message 2'.
-> [  0.008043] (3:receiver@Perl) I got a 'Message 3'.
-> [  0.009995] (3:receiver@Perl) I got a 'finalize'.
-> [  0.012065] (2:receiver@Ruby) I got a 'Message 4'.
-> [  0.014016] (2:receiver@Ruby) I got a 'finalize'.
-> [  0.014016] (1:sender@Tremblay) Goodbye now!
diff --git a/examples/c/comm-waitall/comm-waitall_d.xml b/examples/c/comm-waitall/comm-waitall_d.xml
deleted file mode 100644 (file)
index 8f9d88b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version='1.0'?>
-<!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
-<platform version="4.1">
-  <!-- The master actor (with some arguments) -->
-  <actor host="Tremblay" function="sender">
-    <argument value="5"/>       <!-- Number of messages -->
-    <argument value="1000000"/> <!-- Size of messages -->
-    <argument value="2"/>       <!-- Number of receivers -->
-  </actor>
-  <!-- The receiver actors -->
-  <actor host="Ruby" function="receiver">
-    <argument value="0"/>
-  </actor>
-  <actor host="Perl" function="receiver">
-    <argument value="1"/>
-  </actor>
-</platform>
diff --git a/examples/c/comm-waitany/comm-waitany.c b/examples/c/comm-waitany/comm-waitany.c
deleted file mode 100644 (file)
index 03504d8..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "simgrid/actor.h"
-#include "simgrid/comm.h"
-#include "simgrid/engine.h"
-#include "simgrid/forward.h"
-#include "simgrid/mailbox.h"
-#include "xbt/log.h"
-#include "xbt/str.h"
-#include "xbt/sysdep.h"
-
-#include <stdio.h> /* snprintf */
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(comm_waitany, "Messages specific for this example");
-
-static void sender(int argc, char* argv[])
-{
-  xbt_assert(argc == 4, "Expecting 3 parameters from the XML deployment file but got %d", argc);
-  long messages_count  = xbt_str_parse_int(argv[1], "Invalid message count");
-  long msg_size        = xbt_str_parse_int(argv[2], "Invalid message size");
-  long receivers_count = xbt_str_parse_int(argv[3], "Invalid amount of receivers");
-  xbt_assert(receivers_count > 0);
-
-  /* Array in which we store all ongoing communications */
-  sg_comm_t* pending_comms = xbt_malloc(sizeof(sg_comm_t) * (messages_count + receivers_count));
-  int pending_comms_count  = 0;
-
-  /* Make an array of the mailboxes to use */
-  sg_mailbox_t* mboxes = xbt_malloc(sizeof(sg_mailbox_t) * receivers_count);
-  for (long i = 0; i < receivers_count; i++) {
-    char mailbox_name[80];
-    snprintf(mailbox_name, 79, "receiver-%ld", i);
-    sg_mailbox_t mbox = sg_mailbox_by_name(mailbox_name);
-    mboxes[i]         = mbox;
-  }
-
-  /* Start dispatching all messages to receivers, in a round robin fashion */
-  for (long i = 0; i < messages_count; i++) {
-    char msg_content[80];
-    snprintf(msg_content, 79, "Message %ld", i);
-    sg_mailbox_t mbox = mboxes[i % receivers_count];
-    XBT_INFO("Send '%s' to '%s'", msg_content, sg_mailbox_get_name(mbox));
-
-    /* Create a communication representing the ongoing communication, and store it in pending_comms */
-    pending_comms[pending_comms_count++] = sg_mailbox_put_async(mbox, xbt_strdup(msg_content), msg_size);
-  }
-  /* Start sending messages to let the workers know that they should stop */
-  for (long i = 0; i < receivers_count; i++) {
-    XBT_INFO("Send 'finalize' to 'receiver-%ld'", i);
-    char* end_msg                        = xbt_strdup("finalize");
-    sg_mailbox_t mbox                    = mboxes[i % receivers_count];
-    pending_comms[pending_comms_count++] = sg_mailbox_put_async(mbox, end_msg, 0);
-  }
-
-  XBT_INFO("Done dispatching all messages");
-
-  /* Now that all message exchanges were initiated, wait for their completion, in order of termination.
-   *
-   * This loop waits for first terminating message with wait_any() and remove it from the array (with a memmove),
-   *  until all comms are terminated.
-   * Even in this simple example, the pending comms do not terminate in the exact same order of creation.
-   */
-  while (pending_comms_count != 0) {
-    ssize_t changed_pos = sg_comm_wait_any(pending_comms, pending_comms_count);
-    memmove(pending_comms + changed_pos, pending_comms + changed_pos + 1,
-            sizeof(sg_comm_t) * (pending_comms_count - changed_pos - 1));
-    pending_comms_count--;
-
-    if (changed_pos != 0)
-      XBT_INFO("Remove the %zdth pending comm: it terminated earlier than another comm that was initiated first.",
-               changed_pos);
-  }
-
-  xbt_free(pending_comms);
-  xbt_free(mboxes);
-
-  XBT_INFO("Goodbye now!");
-}
-
-static void receiver(int argc, char* argv[])
-{
-  xbt_assert(argc == 2, "Expecting one parameter from the XML deployment file but got %d", argc);
-  int id = (int)xbt_str_parse_int(argv[1], "ID should be numerical");
-  char mailbox_name[80];
-  snprintf(mailbox_name, 79, "receiver-%d", id);
-  sg_mailbox_t mbox = sg_mailbox_by_name(mailbox_name);
-  XBT_INFO("Wait for my first message on '%s'", mailbox_name);
-  while (1) {
-    char* received = (char*)sg_mailbox_get(mbox);
-    XBT_INFO("I got a '%s'.", received);
-    if (!strcmp(received, "finalize")) { // If it's a finalize message, we're done
-      xbt_free(received);
-      break;
-    }
-    xbt_free(received);
-  }
-
-  XBT_INFO("I'm done. See you!");
-}
-
-int main(int argc, char* argv[])
-{
-  simgrid_init(&argc, argv);
-  xbt_assert(argc > 2,
-             "Usage: %s platform_file deployment_file\n"
-             "\tExample: %s platform.xml deployment.xml\n",
-             argv[0], argv[0]);
-
-  simgrid_load_platform(argv[1]);
-
-  simgrid_register_function("sender", sender);
-  simgrid_register_function("receiver", receiver);
-  simgrid_load_deployment(argv[2]);
-
-  simgrid_run();
-  XBT_INFO("Simulation time %g", simgrid_get_clock());
-
-  return 0;
-}
diff --git a/examples/c/comm-waitany/comm-waitany.tesh b/examples/c/comm-waitany/comm-waitany.tesh
deleted file mode 100644 (file)
index b9e4a98..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env tesh
-
-! output sort 19
-$ ${bindir:=.}/c-comm-waitany ${platfdir:=.}/small_platform.xml ${srcdir:=.}/comm-waitany_d.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (1:sender@Tremblay) Send 'Message 0' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 1' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 2' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 3' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 4' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 5' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Done dispatching all messages
-> [  0.000000] (2:receiver@Fafard) Wait for my first message on 'receiver-0'
-> [  0.000000] (3:receiver@Jupiter) Wait for my first message on 'receiver-1'
-> [  0.158397] (2:receiver@Fafard) I got a 'Message 0'.
-> [  0.169155] (3:receiver@Jupiter) I got a 'Message 1'.
-> [  0.316794] (2:receiver@Fafard) I got a 'Message 2'.
-> [  0.338309] (3:receiver@Jupiter) I got a 'Message 3'.
-> [  0.475190] (2:receiver@Fafard) I got a 'Message 4'.
-> [  0.500898] (1:sender@Tremblay) Remove the 1th pending comm: it terminated earlier than another comm that was initiated first.
-> [  0.500898] (2:receiver@Fafard) I got a 'finalize'.
-> [  0.500898] (2:receiver@Fafard) I'm done. See you!
-> [  0.507464] (3:receiver@Jupiter) I got a 'Message 5'.
-> [  0.526478] (0:maestro@) Simulation time 0.526478
-> [  0.526478] (1:sender@Tremblay) Goodbye now!
-> [  0.526478] (3:receiver@Jupiter) I got a 'finalize'.
-> [  0.526478] (3:receiver@Jupiter) I'm done. See you!
\ No newline at end of file
diff --git a/examples/c/comm-waitany/comm-waitany_d.xml b/examples/c/comm-waitany/comm-waitany_d.xml
deleted file mode 100644 (file)
index dd639f5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version='1.0'?>
-<!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
-<platform version="4.1">
-  <!-- The master actor (with some arguments) -->
-  <actor host="Tremblay" function="sender">
-    <argument value="6"/>       <!-- Number of tasks -->
-    <argument value="1000000"/>      <!-- Communication size of tasks -->
-    <argument value="2"/>         <!-- Number of receivers -->
-  </actor>
-  <!-- The receiver actors -->
-  <actor host="Fafard" function="receiver">
-    <argument value="0"/>
-  </actor>
-  <actor host="Jupiter" function="receiver">
-    <argument value="1"/>
-  </actor>
-</platform>
diff --git a/examples/c/exec-waitany/exec-waitany.c b/examples/c/exec-waitany/exec-waitany.c
deleted file mode 100644 (file)
index bfff989..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Copyright (c) 2019-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "simgrid/actor.h"
-#include "simgrid/engine.h"
-#include "simgrid/exec.h"
-#include "simgrid/host.h"
-
-#include "xbt/log.h"
-#include "xbt/sysdep.h"
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(exec_waitany, "Messages specific for this example");
-
-static void worker(int argc, char* argv[])
-{
-  xbt_assert(argc > 1);
-  int with_timeout = !strcmp(argv[1], "true");
-
-  /* Vector in which we store all pending executions*/
-  sg_exec_t* pending_execs = xbt_malloc(sizeof(sg_exec_t) * 3);
-  int pending_execs_count  = 0;
-
-  for (int i = 0; i < 3; i++) {
-    char* name    = bprintf("Exec-%d", i);
-    double amount = (6 * (i % 2) + i + 1) * sg_host_get_speed(sg_host_self());
-
-    sg_exec_t exec = sg_actor_exec_init(amount);
-    sg_exec_set_name(exec, name);
-    pending_execs[pending_execs_count++] = exec;
-    sg_exec_start(exec);
-
-    XBT_INFO("Activity %s has started for %.0f seconds", name, amount / sg_host_get_speed(sg_host_self()));
-    free(name);
-  }
-
-  /* Now that executions were initiated, wait for their completion, in order of termination.
-   *
-   * This loop waits for first terminating execution with wait_any() and remove it with erase(), until all execs are
-   * terminated.
-   */
-  while (pending_execs_count > 0) {
-    ssize_t pos;
-    if (with_timeout)
-      pos = sg_exec_wait_any_for(pending_execs, pending_execs_count, 4);
-    else
-      pos = sg_exec_wait_any(pending_execs, pending_execs_count);
-
-    if (pos < 0) {
-      XBT_INFO("Do not wait any longer for an activity");
-      pending_execs_count = 0;
-    } else {
-      XBT_INFO("Activity at position %zd is complete", pos);
-      memmove(pending_execs + pos, pending_execs + pos + 1, sizeof(sg_exec_t) * (pending_execs_count - pos - 1));
-      pending_execs_count--;
-    }
-    XBT_INFO("%d activities remain pending", pending_execs_count);
-  }
-
-  xbt_free(pending_execs);
-}
-
-int main(int argc, char* argv[])
-{
-  simgrid_init(&argc, argv);
-  simgrid_load_platform(argv[1]);
-
-  const char* worker_argv[] = {"worker", "false"};
-  sg_actor_create_("worker", sg_host_by_name("Tremblay"), worker, 2, worker_argv);
-
-  worker_argv[1] = "true";
-  sg_actor_create_("worker_timeout", sg_host_by_name("Tremblay"), worker, 2, worker_argv);
-
-  simgrid_run();
-  return 0;
-}
diff --git a/examples/c/exec-waitany/exec-waitany.tesh b/examples/c/exec-waitany/exec-waitany.tesh
deleted file mode 100644 (file)
index 2ea0293..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env tesh
-
-! output sort 19
-$ ${bindir:=.}/c-exec-waitany ${platfdir}/multicore_machine.xml "--log=root.fmt:[%10.6r]%e[%14P]%e%m%n"
-> [  0.000000] [        worker] Activity Exec-0 has started for 1 seconds
-> [  0.000000] [worker_timeout] Activity Exec-0 has started for 1 seconds
-> [  0.000000] [        worker] Activity Exec-1 has started for 8 seconds
-> [  0.000000] [worker_timeout] Activity Exec-1 has started for 8 seconds
-> [  0.000000] [        worker] Activity Exec-2 has started for 3 seconds
-> [  0.000000] [worker_timeout] Activity Exec-2 has started for 3 seconds
-> [  1.000000] [worker_timeout] Activity at position 0 is complete
-> [  1.000000] [worker_timeout] 2 activities remain pending
-> [  1.000000] [        worker] Activity at position 0 is complete
-> [  1.000000] [        worker] 2 activities remain pending
-> [  3.000000] [worker_timeout] Activity at position 1 is complete
-> [  3.000000] [worker_timeout] 1 activities remain pending
-> [  3.000000] [        worker] Activity at position 1 is complete
-> [  3.000000] [        worker] 1 activities remain pending
-> [  7.000000] [worker_timeout] Do not wait any longer for an activity
-> [  7.000000] [worker_timeout] 0 activities remain pending
-> [  8.000000] [        worker] Activity at position 0 is complete
-> [  8.000000] [        worker] 0 activities remain pending
index 74e5c71..5aadcd8 100644 (file)
@@ -3,7 +3,7 @@
 p Testing a simple master/worker example application handling failures TCP crosstraffic DISABLED
 
 ! output sort 19
-$ ${bindir:=.}/c-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/../../cpp/platform-failures/s4u-platform-failures_d.xml --cfg=path:${srcdir} --cfg=network/crosstraffic:0 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
+$ ${bindir:=.}/c-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/../../cpp/platform-failures/s4u-platform-failures_d.xml --cfg=network/crosstraffic:0 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
 > [  0.000000] (0:maestro@) Cannot launch actor 'worker' on failed host 'Fafard'
 > [  0.000000] (0:maestro@) Starting actor worker(Fafard) failed because its host is turned off.
 > [  0.000000] (1:master@Tremblay) Got 5 workers and 20 tasks to process
@@ -108,7 +108,7 @@ $ ${bindir:=.}/c-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${p
 p Testing a simple master/worker example application handling failures. TCP crosstraffic ENABLED
 
 ! output sort 19
-$ ${bindir:=.}/c-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/../../cpp/platform-failures/s4u-platform-failures_d.xml --cfg=path:${srcdir} "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
+$ ${bindir:=.}/c-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/../../cpp/platform-failures/s4u-platform-failures_d.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
 > [  0.000000] (0:maestro@) Cannot launch actor 'worker' on failed host 'Fafard'
 > [  0.000000] (0:maestro@) Starting actor worker(Fafard) failed because its host is turned off.
 > [  0.000000] (1:master@Tremblay) Got 5 workers and 20 tasks to process
@@ -217,4 +217,4 @@ p   complex with such an integration test. One day, we will setup a set of
 p   unit tests for the model's solver, and such issues will be addressable again.
 p For the time being, I just give up, sorry.
 
-p $ ${bindir:=.}/c-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/../../cpp/platform-failures/s4u-platform-failures_d.xml --cfg=path:${srcdir} --cfg=cpu/optim:TI "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
+p $ ${bindir:=.}/c-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/../../cpp/platform-failures/s4u-platform-failures_d.xml --cfg=cpu/optim:TI "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
index cea4755..0361ccb 100644 (file)
@@ -17,60 +17,19 @@ set(_actor-stacksize_factories "^thread") # Threads ignore modifications of the
 set(_maestro-set_factories "thread")
 
 if(SIMGRID_HAVE_MC)
-  # These tests timeout with threads, maybe because of dwarf parsing? not sure
+  # These tests timeout with threads, not sure why
   foreach(example mc-bugged1 mc-bugged2 mc-failing-assert mc-electric-fence)
-     set(_${example}_factories "^thread") # Timeout
-     add_dependencies(tests-mc s4u-${example})
+    set(_${example}_factories "^thread") # Timeout
+    add_dependencies(tests-mc s4u-${example})
   endforeach()
 
-  if(HAVE_C_STACK_CLEANER)
-    add_executable       (s4u-mc-bugged1-liveness-cleaner-on  EXCLUDE_FROM_ALL s4u-mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp)
-    target_link_libraries(s4u-mc-bugged1-liveness-cleaner-on  simgrid)
-    set_target_properties(s4u-mc-bugged1-liveness-cleaner-on  PROPERTIES COMPILE_FLAGS "-DGARBAGE_STACK -fstack-cleaner")
-    add_dependencies(tests-mc s4u-mc-bugged1-liveness-cleaner-on)
-
-    add_executable       (s4u-mc-bugged1-liveness-cleaner-off EXCLUDE_FROM_ALL s4u-mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp)
-    target_link_libraries(s4u-mc-bugged1-liveness-cleaner-off simgrid)
-    set_target_properties(s4u-mc-bugged1-liveness-cleaner-off PROPERTIES COMPILE_FLAGS "-DGARBAGE_STACK -fno-stack-cleaner")
-    add_dependencies(tests-mc s4u-mc-bugged1-liveness-cleaner-off)
-  endif()
-
-  # Model-checking liveness
-  if(HAVE_UCONTEXT_CONTEXTS AND SIMGRID_PROCESSOR_x86_64)
-    # liveness model-checking works only on 64bits (for now ...)
-    set(_mc-bugged1-liveness_factories "ucontext")
-    add_dependencies(tests-mc s4u-mc-bugged1-liveness)
-    set(_mc-bugged2-liveness_factories "ucontext")
-
-    # This example never ends, disable it for now
-    set(_mc-bugged2-liveness_disable 1)
-
-    ADD_TESH(s4u-mc-bugged1-liveness-visited-ucontext --setenv bindir=${CMAKE_CURRENT_BINARY_DIR}/mc-bugged1-liveness
-                                                      --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms
-                                                      --cd ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness
-                                                       ${CMAKE_HOME_DIRECTORY}/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh)
-    IF(HAVE_C_STACK_CLEANER)
-      add_dependencies(tests-mc s4u-mc-bugged1-liveness-stack-cleaner)
-      # This test checks if the stack cleaner is making a difference:
-      ADD_TEST(s4u-mc-bugged1-liveness-stack-cleaner ${CMAKE_HOME_DIRECTORY}/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner
-                                                     ${CMAKE_HOME_DIRECTORY}/examples/cpp/mc-bugged1-liveness/
-                                                     ${CMAKE_CURRENT_BINARY_DIR}/mc-bugged1-liveness/)
-    ENDIF()
-  else()
-    set(_mc-bugged1-liveness_disable 1)
-    set(_mc-bugged2-liveness_disable 1)
-  endif()
-
   if(enable_coverage)
     foreach (example mc-bugged1 mc-bugged2 mc-electric-fence mc-failing-assert)
       ADD_TEST(cover-${example} ${CMAKE_CURRENT_BINARY_DIR}/${example}/s4u-${example} ${CMAKE_HOME_DIRECTORY}/examples/platforms/model_checker_platform.xml)
     endforeach()
-    ADD_TEST(cover-mc-bugged1-liveness ${CMAKE_CURRENT_BINARY_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness ${CMAKE_HOME_DIRECTORY}/examples/platforms/small_platform.xml 1 1001)
   endif()
-
 else()
-  foreach (example mc-bugged1 mc-bugged2  mc-centralized-mutex mc-failing-assert mc-electric-fence
-                   mc-bugged1-liveness mc-bugged2-liveness)
+  foreach (example mc-bugged1 mc-bugged2  mc-centralized-mutex mc-failing-assert mc-electric-fence)
     set(_${example}_disable 1)
   endforeach()
 endif()
@@ -81,12 +40,12 @@ foreach (example synchro-barrier synchro-mutex synchro-semaphore)
 
   if (SIMGRID_HAVE_MC)
     ADD_TESH(s4u-mc-${example}
-             --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-mc-${example}.tesh)
+              --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-mc-${example}.tesh)
 
     add_dependencies(tests-mc s4u-${example})
   endif()
@@ -99,12 +58,33 @@ if (SIMGRID_HAVE_MC)
   endforeach()
 endif()
 
-
 if(NOT HAVE_GRAPHVIZ)
   set(_dag-from-dot_disable 1)
+  set(_dag-from-dot-simple_disable 1)
 endif()
 
-if(NOT SIMGRID_HAVE_NS3)
+if (NOT SIMGRID_HAVE_JSON)
+  set(_dag-from-json-simple_disable 1)
+endif()
+
+if(SIMGRID_HAVE_NS3)
+  if(NS3_VERSION VERSION_GREATER_EQUAL 3.37)
+    set(_network-ns3_teshfile         ${CMAKE_HOME_DIRECTORY}/examples/cpp/network-ns3/s4u-network-ns3-timed.tesh)
+    set(tesh_files    ${tesh_files}   ${CMAKE_HOME_DIRECTORY}/examples/cpp/network-ns3/s4u-network-ns3-notime.tesh)
+  else()
+    set(_network-ns3_teshfile         ${CMAKE_HOME_DIRECTORY}/examples/cpp/network-ns3/s4u-network-ns3-notime.tesh)
+    set(tesh_files    ${tesh_files}   ${CMAKE_HOME_DIRECTORY}/examples/cpp/network-ns3/s4u-network-ns3-timed.tesh)
+  endif()
+
+foreach (example network-ns3 network-ns3-wifi)
+  add_dependencies(tests-ns3 s4u-${example})
+endforeach()
+
+else()
+  # Even if ns3 is not found, we need to override the teshfile name and make sure that everything gets included in the archive
+  set(_network-ns3_teshfile         ${CMAKE_HOME_DIRECTORY}/examples/cpp/network-ns3/s4u-network-ns3-notime.tesh)
+  set(tesh_files    ${tesh_files}   ${CMAKE_HOME_DIRECTORY}/examples/cpp/network-ns3/s4u-network-ns3-timed.tesh)
+
   foreach (example network-ns3 network-ns3-wifi)
     set(_${example}_disable 1)
   endforeach()
@@ -112,25 +92,30 @@ endif()
 
 # Deal with each example
 
-foreach (example activity-testany activity-waitany
+foreach (example activityset-testany activityset-waitany activityset-waitall activityset-waitallfor
                  actor-create actor-daemon actor-exiting actor-join actor-kill
                  actor-lifetime actor-migrate actor-suspend actor-yield actor-stacksize
                  app-bittorrent app-chainsend app-token-ring
-                 comm-pingpong comm-ready comm-suspend comm-testany comm-wait comm-waitany comm-waitall comm-waituntil
+                 battery-chiller-solar battery-connector battery-degradation battery-simple battery-energy
+                 chiller-simple
+                 comm-pingpong comm-ready comm-suspend comm-wait comm-waituntil
                  comm-dependent comm-host2host comm-failure comm-throttling
                  cloud-capping cloud-migration cloud-simple
-                 dag-comm dag-from-dax dag-from-dot dag-failure dag-io dag-scheduling dag-simple
+                 dag-comm dag-from-json-simple dag-from-dax-simple dag-from-dax dag-from-dot-simple dag-from-dot dag-failure dag-io dag-scheduling dag-simple dag-tuto
                  dht-chord dht-kademlia
                  energy-exec energy-boot energy-link energy-vm energy-exec-ptask energy-wifi
                  engine-filtering engine-run-partial
-                 exec-async exec-basic exec-dvfs exec-remote exec-waitany exec-waitfor exec-dependent exec-unassigned
+                 exec-async exec-basic exec-dvfs exec-remote exec-waitfor exec-dependent exec-unassigned
                  exec-ptask-multicore exec-ptask-multicore-latency exec-cpu-nonlinear exec-cpu-factors exec-failure exec-threads
                  maestro-set
-                 mc-bugged1 mc-bugged1-liveness mc-bugged2 mc-bugged2-liveness mc-centralized-mutex mc-electric-fence mc-failing-assert
+                 mc-bugged1 mc-bugged2 mc-centralized-mutex mc-electric-fence mc-failing-assert
+                 mess-wait
                  network-ns3 network-ns3-wifi network-wifi
                  io-async io-priority io-degradation io-file-system io-file-remote io-disk-raw io-dependent
+                 task-dispatch task-io task-microservice task-parallelism task-simple task-storm task-switch-host task-variable-load
+                 solar-panel-simple
                  platform-comm-serialize platform-failures platform-profile platform-properties
-                 plugin-host-load plugin-link-load plugin-prodcons
+                 plugin-host-load plugin-jbod plugin-link-load plugin-prodcons
                  replay-comm replay-io
                  routing-get-clusters
                  synchro-barrier synchro-condition-variable synchro-condition-variable-waituntil synchro-mutex synchro-semaphore
@@ -141,6 +126,11 @@ foreach (example activity-testany activity-waitany
     set(_${example}_sources ${example}/s4u-${example}.cpp)
   endif()
 
+  # Use default tesh file unless specified otherwise
+  if(NOT DEFINED _${example}_teshfile)
+    set(_${example}_teshfile ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}.tesh)
+  endif()
+
   if(NOT DEFINED _${example}_disable)
     add_executable       (s4u-${example} EXCLUDE_FROM_ALL ${_${example}_sources})
     add_dependencies     (tests s4u-${example})
@@ -160,19 +150,20 @@ foreach (example activity-testany activity-waitany
                                       --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}.tesh)
+                                      ${_${example}_teshfile})
   else()
     message(STATUS "Example ${example} disabled, thus not compiled.")
     unset(_${example}_disable)
   endif()
 
-  set(tesh_files    ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/${example}/s4u-${example}.tesh)
+  set(tesh_files    ${tesh_files}    ${_${example}_teshfile})
   foreach(file ${_${example}_sources})
     set(examples_src  ${examples_src} ${CMAKE_CURRENT_SOURCE_DIR}/${file})
   endforeach()
 
   unset(_${example}_factories)
   unset(_${example}_sources)
+  unset(_${example}_teshfile)
 endforeach()
 
 
@@ -212,18 +203,8 @@ 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)
 
+  if(SIMGRID_HAVE_MC)
     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
@@ -231,7 +212,6 @@ foreach(example mc-failing-assert)
                                       --cd ${CMAKE_CURRENT_SOURCE_DIR}/${example}
                                       ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}-nodpor.tesh)
   endif()
-  set(tesh_files    ${tesh_files}   ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}-statequality.tesh)
   set(tesh_files    ${tesh_files}   ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}-nodpor.tesh)
 endforeach()
 
@@ -263,10 +243,8 @@ endif()
 
 # Add all extra files to the archive
 ####################################
-set(examples_src  ${examples_src} ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp        PARENT_SCOPE)
-set(tesh_files    ${tesh_files}   ${CMAKE_CURRENT_SOURCE_DIR}/comm-pingpong/debug-breakpoint.tesh
-                                  ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh
-                                  ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh  PARENT_SCOPE)
+set(examples_src  ${examples_src}    PARENT_SCOPE)
+set(tesh_files    ${tesh_files}   ${CMAKE_CURRENT_SOURCE_DIR}/comm-pingpong/debug-breakpoint.tesh  PARENT_SCOPE)
 set(xml_files     ${xml_files}    ${CMAKE_CURRENT_SOURCE_DIR}/actor-create/s4u-actor-create_d.xml
                                   ${CMAKE_CURRENT_SOURCE_DIR}/actor-lifetime/s4u-actor-lifetime_d.xml
                                   ${CMAKE_CURRENT_SOURCE_DIR}/app-bittorrent/s4u-app-bittorrent_d.xml
@@ -286,14 +264,15 @@ set(xml_files     ${xml_files}    ${CMAKE_CURRENT_SOURCE_DIR}/actor-create/s4u-a
                                   ${CMAKE_CURRENT_SOURCE_DIR}/network-ns3/dogbone_d.xml
                                   ${CMAKE_CURRENT_SOURCE_DIR}/network-ns3/onelink_d.xml
                                   ${CMAKE_CURRENT_SOURCE_DIR}/network-ns3/one_cluster_d.xml                PARENT_SCOPE)
-set(bin_files     ${bin_files}    ${CMAKE_CURRENT_SOURCE_DIR}/dht-kademlia/generate.py
-                                  ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner
-                                  ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/promela_bugged1_liveness
-                                  ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged2-liveness/promela_bugged2_liveness PARENT_SCOPE)
+set(bin_files     ${bin_files}    ${CMAKE_CURRENT_SOURCE_DIR}/battery-degradation/plot_battery_degradation.py
+                                  ${CMAKE_CURRENT_SOURCE_DIR}/dht-kademlia/generate.py  PARENT_SCOPE)
 set(txt_files     ${txt_files}    ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dax/simple_dax_with_cycle.xml
                                   ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dax/smalldax.xml
+                                  ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dax-simple/dag.xml
                                   ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dot/dag.dot
+                                  ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dot-simple/dag.dot
                                   ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dot/dag_with_cycle.dot
+                                  ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-json-simple/dag.json
                                   ${CMAKE_CURRENT_SOURCE_DIR}/replay-comm/s4u-replay-comm-split-p0.txt
                                   ${CMAKE_CURRENT_SOURCE_DIR}/replay-comm/s4u-replay-comm-split-p1.txt
                                   ${CMAKE_CURRENT_SOURCE_DIR}/replay-comm/s4u-replay-comm.txt
@@ -7,47 +7,49 @@
 #include <cstdlib>
 #include <iostream>
 #include <string>
+
 namespace sg4 = simgrid::s4u;
 
 XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_testany, "Messages specific for this s4u example");
 
 static void bob()
 {
-  sg4::Mailbox* mbox    = sg4::Mailbox::by_name("mbox");
-  const sg4::Disk* disk = sg4::Host::current()->get_disks().front();
+  sg4::Mailbox* mbox        = sg4::Mailbox::by_name("mbox");
+  sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("mqueue");
+  const sg4::Disk* disk     = sg4::Host::current()->get_disks().front();
   std::string* payload;
+  std::string* message;
 
   XBT_INFO("Create my asynchronous activities");
   auto exec = sg4::this_actor::exec_async(5e9);
   auto comm = mbox->get_async(&payload);
+  auto mess = mqueue->get_async(&message);
   auto io   = disk->read_async(3e8);
 
-  std::vector<sg4::ActivityPtr> pending_activities = {boost::dynamic_pointer_cast<sg4::Activity>(exec),
-                                                      boost::dynamic_pointer_cast<sg4::Activity>(comm),
-                                                      boost::dynamic_pointer_cast<sg4::Activity>(io)};
-
+  sg4::ActivitySet pending_activities({exec, comm, mess, io});
   XBT_INFO("Sleep_for a while");
   sg4::this_actor::sleep_for(1);
 
   XBT_INFO("Test for completed activities");
   while (not pending_activities.empty()) {
-    ssize_t changed_pos = sg4::Activity::test_any(pending_activities);
-    if (changed_pos != -1) {
-      auto* completed_one = pending_activities[changed_pos].get();
-      if (dynamic_cast<sg4::Comm*>(completed_one))
+    auto completed_one = pending_activities.test_any();
+    if (completed_one != nullptr) {
+      if (boost::dynamic_pointer_cast<sg4::Comm>(completed_one))
         XBT_INFO("Completed a Comm");
-      if (dynamic_cast<sg4::Exec*>(completed_one))
+      if (boost::dynamic_pointer_cast<sg4::Mess>(completed_one))
+        XBT_INFO("Completed a Mess");
+      if (boost::dynamic_pointer_cast<sg4::Exec>(completed_one))
         XBT_INFO("Completed an Exec");
-      if (dynamic_cast<sg4::Io*>(completed_one))
+      if (boost::dynamic_pointer_cast<sg4::Io>(completed_one))
         XBT_INFO("Completed an I/O");
-      pending_activities.erase(pending_activities.begin() + changed_pos);
-    } else { // nothing matches, wait for a little bit
+    } else {
       XBT_INFO("Nothing matches, test again in 0.5s");
       sg4::this_actor::sleep_for(.5);
     }
   }
   XBT_INFO("Last activity is complete");
   delete payload;
+  delete message;
 }
 
 static void alice()
@@ -57,6 +59,14 @@ static void alice()
   sg4::Mailbox::by_name("mbox")->put(payload, 6e8);
 }
 
+static void carl()
+{
+  sg4::this_actor::sleep_for(1.99);
+  auto* payload = new std::string("Control Message");
+  XBT_INFO("Send '%s'", payload->c_str());
+  sg4::MessageQueue::by_name("mqueue")->put(payload);
+}
+
 int main(int argc, char* argv[])
 {
   sg4::Engine e(&argc, argv);
@@ -65,6 +75,7 @@ int main(int argc, char* argv[])
 
   sg4::Actor::create("bob", e.host_by_name("bob"), bob);
   sg4::Actor::create("alice", e.host_by_name("alice"), alice);
+  sg4::Actor::create("carl", e.host_by_name("carl"), carl);
 
   e.run();
 
diff --git a/examples/cpp/activityset-testany/s4u-activityset-testany.tesh b/examples/cpp/activityset-testany/s4u-activityset-testany.tesh
new file mode 100644 (file)
index 0000000..029e90b
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-activityset-testany ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%4.2r]%e[%5a]%e%m%n"
+> [0.00] [alice] Send 'Message'
+> [0.00] [  bob] Create my asynchronous activities
+> [0.00] [  bob] Sleep_for a while
+> [1.00] [  bob] Test for completed activities
+> [1.00] [  bob] Nothing matches, test again in 0.5s
+> [1.50] [  bob] Nothing matches, test again in 0.5s
+> [1.99] [ carl] Send 'Control Message'
+> [2.00] [  bob] Completed a Mess
+> [2.00] [  bob] Nothing matches, test again in 0.5s
+> [2.50] [  bob] Nothing matches, test again in 0.5s
+> [3.00] [  bob] Completed an I/O
+> [3.00] [  bob] Nothing matches, test again in 0.5s
+> [3.50] [  bob] Nothing matches, test again in 0.5s
+> [4.00] [  bob] Nothing matches, test again in 0.5s
+> [4.50] [  bob] Nothing matches, test again in 0.5s
+> [5.00] [  bob] Completed an Exec
+> [5.00] [  bob] Nothing matches, test again in 0.5s
+> [5.50] [  bob] Completed a Comm
+> [5.50] [  bob] Last activity is complete
diff --git a/examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp b/examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp
new file mode 100644 (file)
index 0000000..2c9cf1a
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/s4u.hpp"
+#include <cstdlib>
+#include <iostream>
+#include <string>
+namespace sg4 = simgrid::s4u;
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waitall, "Messages specific for this s4u example");
+
+static void bob()
+{
+  sg4::Mailbox* mbox    = sg4::Mailbox::by_name("mbox");
+  sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("mqueue");
+  const sg4::Disk* disk = sg4::Host::current()->get_disks().front();
+  std::string* payload;
+  std::string* message;
+
+  XBT_INFO("Create my asynchronous activities");
+  auto exec = sg4::this_actor::exec_async(5e9);
+  auto comm = mbox->get_async(&payload);
+  auto io   = disk->read_async(3e8);
+  auto mess = mqueue->get_async(&message);
+
+  sg4::ActivitySet pending_activities({exec, comm, io, mess});
+
+  XBT_INFO("Wait for asynchronous activities to complete, all in one shot.");
+  pending_activities.wait_all();
+
+  XBT_INFO("All activities are completed.");
+  delete payload;
+  delete message;
+}
+
+static void alice()
+{
+  auto* payload = new std::string("Message");
+  XBT_INFO("Send '%s'", payload->c_str());
+  sg4::Mailbox::by_name("mbox")->put(payload, 6e8);
+}
+
+static void carl()
+{
+  auto* payload = new std::string("Control Message");
+  sg4::MessageQueue::by_name("mqueue")->put(payload);
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+
+  e.load_platform(argv[1]);
+
+  sg4::Actor::create("bob", e.host_by_name("bob"), bob);
+  sg4::Actor::create("alice", e.host_by_name("alice"), alice);
+  sg4::Actor::create("carl", e.host_by_name("carl"), carl);
+
+  e.run();
+
+  return 0;
+}
diff --git a/examples/cpp/activityset-waitall/s4u-activityset-waitall.tesh b/examples/cpp/activityset-waitall/s4u-activityset-waitall.tesh
new file mode 100644 (file)
index 0000000..889b405
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-activityset-waitall ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%7.6r]%e[%5a]%e%m%n"
+> [0.000000] [alice] Send 'Message'
+> [0.000000] [  bob] Create my asynchronous activities
+> [0.000000] [  bob] Wait for asynchronous activities to complete, all in one shot.
+> [5.197828] [  bob] All activities are completed.
diff --git a/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp b/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp
new file mode 100644 (file)
index 0000000..a322cc4
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/s4u.hpp"
+#include <cstdlib>
+#include <iostream>
+#include <string>
+namespace sg4 = simgrid::s4u;
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waitallfor, "Messages specific for this s4u example");
+
+static void bob()
+{
+  sg4::Mailbox* mbox    = sg4::Mailbox::by_name("mbox");
+  sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("mqueue");
+  const sg4::Disk* disk = sg4::Host::current()->get_disks().front();
+  std::string* payload;
+  std::string* message;
+
+  XBT_INFO("Create my asynchronous activities");
+  auto exec = sg4::this_actor::exec_async(5e9);
+  auto comm = mbox->get_async(&payload);
+  auto io   = disk->read_async(3e8);
+  auto mess = mqueue->get_async(&message);
+
+  sg4::ActivitySet pending_activities({exec, comm, io, mess});
+
+  XBT_INFO("Wait for asynchronous activities to complete");
+  while (not pending_activities.empty()) {
+    try {
+      pending_activities.wait_all_for(1);
+    } catch (simgrid::TimeoutException& e) {
+      XBT_INFO("Not all activities are terminated yet.");
+    }
+    while (auto completed_one = pending_activities.test_any()) {
+      if (boost::dynamic_pointer_cast<sg4::Comm>(completed_one))
+        XBT_INFO("Completed a Comm");
+      if (boost::dynamic_pointer_cast<sg4::Mess>(completed_one))
+        XBT_INFO("Completed a Mess");
+      if (boost::dynamic_pointer_cast<sg4::Exec>(completed_one))
+        XBT_INFO("Completed an Exec");
+      if (boost::dynamic_pointer_cast<sg4::Io>(completed_one))
+        XBT_INFO("Completed an I/O");
+    }
+  }
+  XBT_INFO("Last activity is complete");
+  delete payload;
+  delete message;
+}
+
+static void alice()
+{
+  auto* payload = new std::string("Message");
+  XBT_INFO("Send '%s'", payload->c_str());
+  sg4::Mailbox::by_name("mbox")->put(payload, 6e8);
+}
+
+static void carl()
+{
+  sg4::this_actor::sleep_for(1.99);
+  auto* payload = new std::string("Control Message");
+  XBT_INFO("Send '%s'", payload->c_str());
+  sg4::MessageQueue::by_name("mqueue")->put(payload);
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+
+  e.load_platform(argv[1]);
+
+  sg4::Actor::create("bob", e.host_by_name("bob"), bob);
+  sg4::Actor::create("alice", e.host_by_name("alice"), alice);
+  sg4::Actor::create("carl", e.host_by_name("carl"), carl);
+
+  e.run();
+
+  return 0;
+}
diff --git a/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.tesh b/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.tesh
new file mode 100644 (file)
index 0000000..ce8db4a
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-activityset-waitallfor ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%7.6r]%e[%5a]%e%m%n"
+> [0.000000] [alice] Send 'Message'
+> [0.000000] [  bob] Create my asynchronous activities
+> [0.000000] [  bob] Wait for asynchronous activities to complete
+> [1.000000] [  bob] Not all activities are terminated yet.
+> [1.990000] [ carl] Send 'Control Message'
+> [2.000000] [  bob] Not all activities are terminated yet.
+> [2.000000] [  bob] Completed a Mess
+> [3.000000] [  bob] Not all activities are terminated yet.
+> [3.000000] [  bob] Completed an I/O
+> [4.000000] [  bob] Not all activities are terminated yet.
+> [5.000000] [  bob] Not all activities are terminated yet.
+> [5.000000] [  bob] Completed an Exec
+> [5.197828] [  bob] Completed a Comm
+> [5.197828] [  bob] Last activity is complete
@@ -9,39 +9,41 @@
 #include <string>
 namespace sg4 = simgrid::s4u;
 
-XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waittany, "Messages specific for this s4u example");
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waitany, "Messages specific for this s4u example");
 
 static void bob()
 {
   sg4::Mailbox* mbox    = sg4::Mailbox::by_name("mbox");
+  sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("mqueue");
   const sg4::Disk* disk = sg4::Host::current()->get_disks().front();
   std::string* payload;
+  std::string* message;
 
   XBT_INFO("Create my asynchronous activities");
   auto exec = sg4::this_actor::exec_async(5e9);
   auto comm = mbox->get_async(&payload);
   auto io   = disk->read_async(3e8);
+  auto mess = mqueue->get_async(&message);
 
-  std::vector<sg4::ActivityPtr> pending_activities = {boost::dynamic_pointer_cast<sg4::Activity>(exec),
-                                                      boost::dynamic_pointer_cast<sg4::Activity>(comm),
-                                                      boost::dynamic_pointer_cast<sg4::Activity>(io)};
+  sg4::ActivitySet pending_activities({exec, comm, io, mess});
 
-  XBT_INFO("Wait for asynchrounous activities to complete");
+  XBT_INFO("Wait for asynchronous activities to complete");
   while (not pending_activities.empty()) {
-    ssize_t changed_pos = sg4::Activity::wait_any(pending_activities);
-    if (changed_pos != -1) {
-      auto* completed_one = pending_activities[changed_pos].get();
-      if (dynamic_cast<sg4::Comm*>(completed_one))
+    auto completed_one = pending_activities.wait_any();
+    if (completed_one != nullptr) {
+      if (boost::dynamic_pointer_cast<sg4::Comm>(completed_one))
         XBT_INFO("Completed a Comm");
-      if (dynamic_cast<sg4::Exec*>(completed_one))
+      if (boost::dynamic_pointer_cast<sg4::Mess>(completed_one))
+        XBT_INFO("Completed a Mess");
+      if (boost::dynamic_pointer_cast<sg4::Exec>(completed_one))
         XBT_INFO("Completed an Exec");
-      if (dynamic_cast<sg4::Io*>(completed_one))
+      if (boost::dynamic_pointer_cast<sg4::Io>(completed_one))
         XBT_INFO("Completed an I/O");
-      pending_activities.erase(pending_activities.begin() + changed_pos);
     }
   }
   XBT_INFO("Last activity is complete");
   delete payload;
+  delete message;
 }
 
 static void alice()
@@ -51,6 +53,14 @@ static void alice()
   sg4::Mailbox::by_name("mbox")->put(payload, 6e8);
 }
 
+static void carl()
+{
+  sg4::this_actor::sleep_for(2);
+  auto* payload = new std::string("Control Message");
+  XBT_INFO("Send '%s'", payload->c_str());
+  sg4::MessageQueue::by_name("mqueue")->put(payload);
+}
+
 int main(int argc, char* argv[])
 {
   sg4::Engine e(&argc, argv);
@@ -59,6 +69,7 @@ int main(int argc, char* argv[])
 
   sg4::Actor::create("bob", e.host_by_name("bob"), bob);
   sg4::Actor::create("alice", e.host_by_name("alice"), alice);
+  sg4::Actor::create("carl", e.host_by_name("carl"), carl);
 
   e.run();
 
diff --git a/examples/cpp/activityset-waitany/s4u-activityset-waitany.tesh b/examples/cpp/activityset-waitany/s4u-activityset-waitany.tesh
new file mode 100644 (file)
index 0000000..e665de5
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-activityset-waitany ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%7.6r]%e[%5a]%e%m%n"
+> [0.000000] [alice] Send 'Message'
+> [0.000000] [  bob] Create my asynchronous activities
+> [0.000000] [  bob] Wait for asynchronous activities to complete
+> [2.000000] [ carl] Send 'Control Message'
+> [2.000000] [  bob] Completed a Mess
+> [3.000000] [  bob] Completed an I/O
+> [5.000000] [  bob] Completed an Exec
+> [5.197828] [  bob] Completed a Comm
+> [5.197828] [  bob] Last activity is complete
index 2ba057c..bd7e25d 100644 (file)
@@ -34,8 +34,8 @@ public:
   sg4::Mailbox* prev = nullptr;
   sg4::Mailbox* next = nullptr;
   sg4::Mailbox* me   = nullptr;
-  std::vector<sg4::CommPtr> pending_recvs;
-  std::vector<sg4::CommPtr> pending_sends;
+  sg4::ActivitySet pending_recvs;
+  sg4::ActivitySet pending_sends;
 
   unsigned long long received_bytes = 0;
   unsigned int received_pieces      = 0;
@@ -60,17 +60,16 @@ public:
 
     while (not done) {
       sg4::CommPtr comm = me->get_async<FilePiece>(&received);
-      pending_recvs.push_back(comm);
+      pending_recvs.push(comm);
 
-      ssize_t idx = sg4::Comm::wait_any(pending_recvs);
-      if (idx != -1) {
-        comm = pending_recvs.at(idx);
+      auto completed_one = pending_recvs.wait_any();
+      if (completed_one != nullptr) {
+        comm = boost::dynamic_pointer_cast<sg4::Comm>(completed_one);
         XBT_DEBUG("Peer %s got a 'SEND_DATA' message", me->get_cname());
-        pending_recvs.erase(pending_recvs.begin() + idx);
         if (next != nullptr) {
           XBT_DEBUG("Sending (asynchronously) from %s to %s", me->get_cname(), next->get_cname());
           sg4::CommPtr send = next->put_async(received, MESSAGE_SEND_DATA_HEADER_SIZE + PIECE_SIZE);
-          pending_sends.push_back(send);
+          pending_sends.push(send);
         } else
           delete received;
 
@@ -110,14 +109,14 @@ public:
 
   void sendFile()
   {
-    std::vector<sg4::CommPtr> pending_sends;
+    sg4::ActivitySet pending_sends;
     for (unsigned int current_piece = 0; current_piece < piece_count; current_piece++) {
       XBT_DEBUG("Sending (send) piece %u from %s into mailbox %s", current_piece, sg4::Host::current()->get_cname(),
                 first->get_cname());
       sg4::CommPtr comm = first->put_async(new FilePiece(), MESSAGE_SEND_DATA_HEADER_SIZE + PIECE_SIZE);
-      pending_sends.push_back(comm);
+      pending_sends.push(comm);
     }
-    sg4::Comm::wait_all(pending_sends);
+    pending_sends.wait_all();
   }
 
   Broadcaster(int hostcount, unsigned int piece_count) : piece_count(piece_count)
@@ -140,7 +139,7 @@ static void peer()
   p.joinChain();
   p.forwardFile();
 
-  sg4::Comm::wait_all(p.pending_sends);
+  p.pending_sends.wait_all();
   double end_time = sg4::Engine::get_clock();
 
   XBT_INFO("### %f %llu bytes (Avg %f MB/s); copy finished (simulated).", end_time - start_time, p.received_bytes,
diff --git a/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp
new file mode 100644 (file)
index 0000000..00fff06
--- /dev/null
@@ -0,0 +1,124 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example combine the battery plugin, the chiller plugin and the solar
+   panel plugin. It illustrates how to use them together to evaluate the amount
+   of brown energy (from the electrical grid) and green energy (from the solar
+   panel) consumed by several machines.
+
+   In this scenario we have two host placed in a room.
+   The room is maintained at 24°C by a chiller, powered by the electrical grid
+   and consumes brown energy.
+   The two hosts are powered by a battery when available, and the electrical
+   grid otherwise. The battery is charged by a solar panel.
+
+   We simulate two days from 00h00 to 00h00.
+   The solar panel generates power from 8h to 20h with a peak at 14h.
+   During the simulation, when the charge of the battery goes:
+    - below 75% the solar panel is connected to the battery
+    - above 80% the solar panel is disconnected from the battery
+    - below 20% the hosts are disconnected from the battery
+    - above 25% the hosts are connected to the battery
+
+   The two hosts are always idle, except from 12h to 16h on the first day.
+*/
+
+#include "simgrid/plugins/battery.hpp"
+#include "simgrid/plugins/chiller.hpp"
+#include "simgrid/plugins/energy.h"
+#include "simgrid/plugins/solar_panel.hpp"
+#include "simgrid/s4u.hpp"
+#include <math.h>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+namespace sp  = simgrid::plugins;
+
+static void irradiance_manager(sp::SolarPanelPtr solar_panel)
+{
+  int time         = 0;
+  int time_step    = 10;
+  double amplitude = 1000 / 2.0;
+  double period    = 24 * 60 * 60;
+  double shift     = 16 * 60 * 60;
+  double irradiance;
+  while (true) {
+    irradiance = amplitude * sin(2 * M_PI * (time + shift) / period);
+    irradiance = irradiance < 0 ? 0 : irradiance;
+    solar_panel->set_solar_irradiance(irradiance);
+    sg4::this_actor::sleep_for(time_step);
+    time += time_step;
+  }
+}
+
+static void host_job_manager(double start, double duration)
+{
+  sg4::this_actor::sleep_until(start);
+  sg4::this_actor::get_host()->execute(duration * sg4::this_actor::get_host()->get_speed());
+}
+
+static void end_manager(sp::BatteryPtr b)
+{
+  sg4::this_actor::sleep_until(86400 * 2);
+  for (auto& handler : b->get_handlers())
+    b->delete_handler(handler);
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+  sg_host_energy_plugin_init();
+
+  auto myhost1 = e.host_by_name("MyHost1");
+  auto myhost2 = e.host_by_name("MyHost2");
+
+  auto battery     = sp::Battery::init("Battery", 0.2, -1e3, 1e3, 0.9, 0.9, 2000, 1000);
+  auto chiller     = sp::Chiller::init("Chiller", 50, 1006, 0.2, 0.9, 24, 24, 1e3);
+  auto solar_panel = sp::SolarPanel::init("Solar Panel", 1.1, 0.9, 0, 0, 1e3);
+  chiller->add_host(myhost1);
+  chiller->add_host(myhost2);
+  solar_panel->on_this_power_change_cb(
+      [battery](sp::SolarPanel* s) { battery->set_load("Solar Panel", s->get_power() * -1); });
+
+  // These handlers connect/disconnect the solar panel and the hosts depending on the state of charge of the battery
+  battery->schedule_handler(0.8, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT,
+                            [battery]() { battery->set_load("Solar Panel", false); });
+  battery->schedule_handler(0.75, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT,
+                            [battery]() { battery->set_load("Solar Panel", true); });
+  battery->schedule_handler(0.2, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT,
+                            [battery, &myhost1, &myhost2]() {
+                              battery->connect_host(myhost1, false);
+                              battery->connect_host(myhost2, false);
+                            });
+  battery->schedule_handler(0.25, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT,
+                            [battery, &myhost1, &myhost2]() {
+                              battery->connect_host(myhost1);
+                              battery->connect_host(myhost2);
+                            });
+
+  /* Handlers create simulation events preventing the simulation from finishing
+     To avoid this behaviour this actor sleeps for 2 days and then delete all handlers
+  */
+  sg4::Actor::create("end_manager", myhost1, end_manager, battery);
+
+  // This actor updates the solar irradiance of the solar panel
+  sg4::Actor::create("irradiance_manager", myhost1, irradiance_manager, solar_panel)->daemonize();
+
+  // These actors start a job on a host for a specific duration
+  sg4::Actor::create("host_job_manager", myhost1, host_job_manager, 12 * 60 * 60, 4 * 60 * 60);
+  sg4::Actor::create("host_job_manager", myhost2, host_job_manager, 12 * 60 * 60, 4 * 60 * 60);
+
+  e.run();
+  XBT_INFO("State of charge of the battery: %0.1f%%", battery->get_state_of_charge() * 100);
+  XBT_INFO(
+      "Energy consumed by the hosts (green / brown): %.2fMJ "
+      "/ %.2fMJ",
+      battery->get_energy_provided() / 1e6,
+      (sg_host_get_consumed_energy(myhost1) + sg_host_get_consumed_energy(myhost2) - battery->get_energy_provided()) /
+          1e6);
+  XBT_INFO("Energy consumed by the chiller (brown): %.2fMJ", chiller->get_energy_consumed() / 1e6);
+  return 0;
+}
diff --git a/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh
new file mode 100644 (file)
index 0000000..f2cddf4
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-battery-chiller-solar ${platfdir}/energy_platform.xml
+> [172800.000000] [host_energy/INFO] Total energy consumption: 53568000.000000 Joules (used hosts: 36288000.000000 Joules; unused/idle hosts: 17280000.000000)
+> [172800.000000] [battery_chiller_solar/INFO] State of charge of the battery: 20.4%
+> [172800.000000] [battery_chiller_solar/INFO] Energy consumed by the hosts (green / brown): 21.60MJ / 14.69MJ
+> [172800.000000] [battery_chiller_solar/INFO] Energy consumed by the chiller (brown): 48.38MJ
+> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost1: 17568000.000000 Joules
+> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost2: 18720000.000000 Joules
+> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost3: 17280000.000000 Joules
\ No newline at end of file
diff --git a/examples/cpp/battery-connector/s4u-battery-connector.cpp b/examples/cpp/battery-connector/s4u-battery-connector.cpp
new file mode 100644 (file)
index 0000000..b3a8588
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example shows how to use the battery as a connector.
+   A connector has no capacity and only delivers as much power as it receives
+   with a transfer efficiency of 100%.
+   A solar panel is connected to the connector and power a host.
+*/
+
+#include "simgrid/plugins/battery.hpp"
+#include "simgrid/plugins/chiller.hpp"
+#include "simgrid/plugins/energy.h"
+#include "simgrid/plugins/solar_panel.hpp"
+#include "simgrid/s4u.hpp"
+#include <math.h>
+#include <simgrid/s4u/Actor.hpp>
+#include <xbt/log.h>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+namespace sp  = simgrid::plugins;
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+  sg_host_energy_plugin_init();
+
+  auto myhost1 = e.host_by_name("MyHost1");
+
+  auto connector     = sp::Battery::init();
+  auto solar_panel = sp::SolarPanel::init("Solar Panel", 1, 1, 200, 0, 1e3);
+
+  connector->set_load("Solar Panel", solar_panel->get_power() * -1);
+  connector->connect_host(myhost1);
+
+  solar_panel->on_this_power_change_cb([connector](sp::SolarPanel *s) {
+    connector->set_load("Solar Panel", s->get_power() * -1);
+  });
+
+  sg4::Actor::create("manager", myhost1, [&myhost1, & solar_panel, &connector]{
+    XBT_INFO("Solar Panel power = %.2fW, MyHost1 power = %.2fW. The Solar Panel provides more than needed.", solar_panel->get_power(), sg_host_get_current_consumption(myhost1));
+    simgrid::s4u::this_actor::sleep_for(100);
+    XBT_INFO("Energy consumption MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", sg_host_get_consumed_energy(myhost1) / 1e3, connector->get_energy_provided() / 1e3);
+
+    solar_panel->set_solar_irradiance(100);
+    XBT_INFO("Solar Panel power = %.2fW, MyHost1 power = %.2fW. The Solar Panel provides exactly what is needed.", solar_panel->get_power(), sg_host_get_current_consumption(myhost1));
+    double last_measure_host_energy = sg_host_get_consumed_energy(myhost1);
+    double last_measure_connector_energy = connector->get_energy_provided();
+
+    simgrid::s4u::this_actor::sleep_for(100);
+    XBT_INFO("Energy consumption MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", (sg_host_get_consumed_energy(myhost1) - last_measure_host_energy) / 1e3, (connector->get_energy_provided() - last_measure_connector_energy) / 1e3);
+
+    XBT_INFO("MyHost1 executes something for 100s. The Solar Panel does not provide enough energy.");
+    last_measure_host_energy = sg_host_get_consumed_energy(myhost1);
+    last_measure_connector_energy = connector->get_energy_provided();
+    myhost1->execute(100 * myhost1->get_speed());
+    XBT_INFO("Energy MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", (sg_host_get_consumed_energy(myhost1) - last_measure_host_energy) / 1e3, (connector->get_energy_provided() - last_measure_connector_energy) / 1e3);
+  });
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/battery-connector/s4u-battery-connector.tesh b/examples/cpp/battery-connector/s4u-battery-connector.tesh
new file mode 100644 (file)
index 0000000..2dd264d
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-battery-connector ${platfdir}/energy_platform.xml
+> [MyHost1:manager:(1) 0.000000] [battery_chiller_solar/INFO] Solar Panel power = 200.00W, MyHost1 power = 100.00W. The Solar Panel provides more than needed.
+> [MyHost1:manager:(1) 100.000000] [battery_chiller_solar/INFO] Energy consumption MyHost1: 10.00kJ, Energy from the Solar Panel 10.00kJ
+> [MyHost1:manager:(1) 100.000000] [battery_chiller_solar/INFO] Solar Panel power = 100.00W, MyHost1 power = 100.00W. The Solar Panel provides exactly what is needed.
+> [MyHost1:manager:(1) 200.000000] [battery_chiller_solar/INFO] Energy consumption MyHost1: 10.00kJ, Energy from the Solar Panel 10.00kJ
+> [MyHost1:manager:(1) 200.000000] [battery_chiller_solar/INFO] MyHost1 executes something for 100s. The Solar Panel does not provide enough energy.
+> [MyHost1:manager:(1) 300.000000] [battery_chiller_solar/INFO] Energy MyHost1: 12.00kJ, Energy from the Solar Panel 10.00kJ
+> [300.000000] [host_energy/INFO] Total energy consumption: 92000.000000 Joules (used hosts: 32000.000000 Joules; unused/idle hosts: 60000.000000)
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost1: 32000.000000 Joules
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost2: 30000.000000 Joules
+> [300.000000] [host_energy/INFO] Energy consumption of host MyHost3: 30000.000000 Joules
\ No newline at end of file
diff --git a/examples/cpp/battery-degradation/plot_battery_degradation.py b/examples/cpp/battery-degradation/plot_battery_degradation.py
new file mode 100644 (file)
index 0000000..6863832
--- /dev/null
@@ -0,0 +1,16 @@
+# Copyright (c) 2003-2023. The SimGrid Team.
+# All rights reserved.
+
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+import sys
+import pandas as pd
+import seaborn as sns 
+
+df = pd.read_csv(sys.argv[1], names=['Time','Value', 'SoC - SoH'])
+df['Time'] = df['Time'].apply(lambda x: float(x.split(" ")[-1]))
+sns.set_theme()
+sns.set(rc={'figure.figsize':(16,8)})
+g = sns.lineplot(data=df, x='Time', y='Value', hue='SoC - SoH')
+g.get_figure().savefig('battery_degradation.svg')
\ No newline at end of file
diff --git a/examples/cpp/battery-degradation/s4u-battery-degradation.cpp b/examples/cpp/battery-degradation/s4u-battery-degradation.cpp
new file mode 100644 (file)
index 0000000..4973587
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (c) 2003-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/plugins/battery.hpp"
+#include "simgrid/s4u.hpp"
+#include <memory>
+#include <simgrid/s4u/Actor.hpp>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_degradation, "Messages specific for this s4u example");
+
+int main(int argc, char* argv[])
+{
+  simgrid::s4u::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  auto battery = simgrid::plugins::Battery::init("Battery", 0.8, -200, 200, 0.9, 0.9, 10, 100);
+
+  battery->set_load("load", 100.0);
+
+  auto handler1 = battery->schedule_handler(
+      0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [&battery]() {
+        XBT_INFO("%f,%f,SoC", simgrid::s4u::Engine::get_clock(), battery->get_state_of_charge());
+        XBT_INFO("%f,%f,SoH", simgrid::s4u::Engine::get_clock(), battery->get_state_of_health());
+        battery->set_load("load", -100.0);
+      });
+
+  std::shared_ptr<simgrid::plugins::Battery::Handler> handler2;
+  handler2 = battery->schedule_handler(
+      0.8, simgrid::plugins::Battery::CHARGE, simgrid::plugins::Battery::Handler::PERSISTANT,
+      [&battery, &handler1, &handler2]() {
+        XBT_INFO("%f,%f,SoC", simgrid::s4u::Engine::get_clock(), battery->get_state_of_charge());
+        XBT_INFO("%f,%f,SoH", simgrid::s4u::Engine::get_clock(), battery->get_state_of_health());
+        if (battery->get_state_of_health() < 0.1) {
+          battery->delete_handler(handler1);
+          battery->delete_handler(handler2);
+        }
+        battery->set_load("load", 100.0);
+      });
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/battery-degradation/s4u-battery-degradation.tesh b/examples/cpp/battery-degradation/s4u-battery-degradation.tesh
new file mode 100644 (file)
index 0000000..5af4728
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/env tesh
+
+! output ignore 
+
+$ ${bindir:=.}/s4u-battery-degradation ${platfdir}/energy_platform.xml
diff --git a/examples/cpp/battery-energy/s4u-battery-energy.cpp b/examples/cpp/battery-energy/s4u-battery-energy.cpp
new file mode 100644 (file)
index 0000000..6db8812
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright (c) 2003-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/plugins/battery.hpp"
+#include "simgrid/plugins/energy.h"
+#include "simgrid/s4u.hpp"
+#include <simgrid/s4u/Actor.hpp>
+#include <simgrid/s4u/Engine.hpp>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_energy, "Messages specific for this s4u example");
+
+static void manager()
+{
+  auto battery = simgrid::plugins::Battery::init("Battery", 0.8, -300, 300, 0.9, 0.9, 10, 1000);
+
+  auto* host1 = simgrid::s4u::Engine::get_instance()->host_by_name("MyHost1");
+  auto* host2 = simgrid::s4u::Engine::get_instance()->host_by_name("MyHost2");
+  auto* host3 = simgrid::s4u::Engine::get_instance()->host_by_name("MyHost3");
+
+  battery->schedule_handler(
+      0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT,
+      [&battery, &host1, &host2, &host3]() {
+        XBT_INFO("Handler -> Battery low: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ",
+                 battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(),
+                 battery->get_energy_provided(), battery->get_energy_consumed());
+        XBT_INFO("Disconnecting hosts %s and %s", host1->get_cname(), host2->get_cname());
+        battery->connect_host(host1, false);
+        battery->connect_host(host2, false);
+        XBT_INFO("Energy consumed this far by: %s: %fJ, %s: %fJ, %s: %fJ", host1->get_cname(),
+                 sg_host_get_consumed_energy(host1), host2->get_cname(), sg_host_get_consumed_energy(host2),
+                 host3->get_cname(), sg_host_get_consumed_energy(host3));
+      });
+
+  XBT_INFO("Battery state: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ",
+           battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(),
+           battery->get_energy_provided(), battery->get_energy_consumed());
+  XBT_INFO("Connecting hosts %s and %s to the battery", host1->get_cname(), host2->get_cname());
+  battery->connect_host(host1);
+  battery->connect_host(host2);
+
+  double flops = 1e9;
+  XBT_INFO("Host %s will now execute %f flops", host1->get_cname(), flops);
+  host2->execute(flops);
+
+  simgrid::s4u::this_actor::sleep_until(200);
+  XBT_INFO("Battery state: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ",
+           battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(),
+           battery->get_energy_provided(), battery->get_energy_consumed());
+}
+
+int main(int argc, char* argv[])
+{
+  simgrid::s4u::Engine e(&argc, argv);
+  // if you plan to use Battery::connect_host you have to init the energy plugin at start.
+  sg_host_energy_plugin_init();
+  e.load_platform(argv[1]);
+
+  simgrid::s4u::Actor::create("manager", e.host_by_name("MyHost1"), manager);
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/battery-energy/s4u-battery-energy.tesh b/examples/cpp/battery-energy/s4u-battery-energy.tesh
new file mode 100644 (file)
index 0000000..ee9b4a7
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-battery-energy ${platfdir}/energy_platform.xml
+> [MyHost1:manager:(1) 0.000000] [battery_energy/INFO] Battery state: SoC: 0.800000 SoH: 1.000000 Energy stored: 28800.000000J Energy provided: 0.000000J Energy consumed 0.000000J
+> [MyHost1:manager:(1) 0.000000] [battery_energy/INFO] Connecting hosts MyHost1 and MyHost2 to the battery
+> [MyHost1:manager:(1) 0.000000] [battery_energy/INFO] Host MyHost1 will now execute 1000000000.000000 flops
+> [93.709721] [battery_energy/INFO] Handler -> Battery low: SoC: 0.200000 SoH: 0.999700 Energy stored: 7197.839784J Energy provided: 19441.944194J Energy consumed 0.000000J
+> [93.709721] [battery_energy/INFO] Disconnecting hosts MyHost1 and MyHost2
+> [93.709721] [battery_energy/INFO] Energy consumed this far by: MyHost1: 9370.972097J, MyHost2: 10370.972097J, MyHost3: 9370.972097J
+> [MyHost1:manager:(1) 200.000000] [battery_energy/INFO] Battery state: SoC: 0.200000 SoH: 0.999700 Energy stored: 7197.839784J Energy provided: 19441.944194J Energy consumed 0.000000J
+> [200.000000] [host_energy/INFO] Total energy consumption: 61000.000000 Joules (used hosts: 21000.000000 Joules; unused/idle hosts: 40000.000000)
+> [200.000000] [host_energy/INFO] Energy consumption of host MyHost1: 20000.000000 Joules
+> [200.000000] [host_energy/INFO] Energy consumption of host MyHost2: 21000.000000 Joules
+> [200.000000] [host_energy/INFO] Energy consumption of host MyHost3: 20000.000000 Joules
diff --git a/examples/cpp/battery-simple/s4u-battery-simple.cpp b/examples/cpp/battery-simple/s4u-battery-simple.cpp
new file mode 100644 (file)
index 0000000..61a4186
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (c) 2003-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/plugins/battery.hpp"
+#include "simgrid/s4u.hpp"
+#include <simgrid/s4u/Actor.hpp>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(battery_simple, "Messages specific for this s4u example");
+
+int main(int argc, char* argv[])
+{
+  simgrid::s4u::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  auto battery = simgrid::plugins::Battery::init("Battery", 0.8, -100, 100, 0.9, 0.9, 10, 1000);
+
+  XBT_INFO("Initial state: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ",
+           battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(),
+           battery->get_energy_provided(), battery->get_energy_consumed());
+
+  /* This power is beyond the nominal values of the battery
+   * see documentation for more info
+   */
+  double load_w = 150;
+  battery->set_load("load", load_w);
+  XBT_INFO("Set load to %fW", load_w);
+
+  battery->schedule_handler(
+      0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [&battery, &load_w]() {
+        XBT_INFO("Discharged state: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ",
+                 battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(),
+                 battery->get_energy_provided(), battery->get_energy_consumed());
+        battery->set_load("load", -load_w);
+        XBT_INFO("Set load to %fW", -load_w);
+      });
+
+  battery->schedule_handler(
+      0.8, simgrid::plugins::Battery::CHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [&battery]() {
+        XBT_INFO("Charged state: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ",
+                 battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(),
+                 battery->get_energy_provided(), battery->get_energy_consumed());
+        XBT_INFO("Set load to %fW", 0.0);
+      });
+
+  e.run();
+
+  return 0;
+}
\ No newline at end of file
diff --git a/examples/cpp/battery-simple/s4u-battery-simple.tesh b/examples/cpp/battery-simple/s4u-battery-simple.tesh
new file mode 100644 (file)
index 0000000..3674d1f
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-battery-simple ${platfdir}/energy_platform.xml
+> [0.000000] [battery_simple/INFO] Initial state: SoC: 0.800000 SoH: 1.000000 Energy stored: 28800.000000J Energy provided: 0.000000J Energy consumed 0.000000J
+> [0.000000] [battery_simple/INFO] Set load to 150.000000W
+> [216.021602] [battery_simple/INFO] Discharged state: SoC: 0.200000 SoH: 0.999700 Energy stored: 7197.839784J Energy provided: 19441.944194J Energy consumed 0.000000J
+> [216.021602] [battery_simple/INFO] Set load to -150.000000W
+> [455.853662] [battery_simple/INFO] Charged state: SoC: 0.800000 SoH: 0.999400 Energy stored: 28782.725182J Energy provided: 19441.944194J Energy consumed 23983.205998J
+> [455.853662] [battery_simple/INFO] Set load to 0.000000W
+
diff --git a/examples/cpp/chiller-simple/s4u-chiller-simple.cpp b/examples/cpp/chiller-simple/s4u-chiller-simple.cpp
new file mode 100644 (file)
index 0000000..db48b65
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/plugins/chiller.hpp"
+#include "simgrid/plugins/energy.h"
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(chiller_simple, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+
+static void display_chiller(simgrid::plugins::ChillerPtr c)
+{
+  XBT_INFO("%s: Power: %.2fW T_in: %.2f°C Energy consumed: %.2fJ", c->get_cname(), c->get_power(), c->get_temp_in(),
+           c->get_energy_consumed());
+}
+
+static void manager(simgrid::plugins::ChillerPtr c)
+{
+  display_chiller(c);
+
+  simgrid::s4u::this_actor::sleep_for(c->get_time_to_goal_temp());
+  XBT_INFO("The input temperature is now equal to the goal temperature. After this point the Chiller will compensate "
+           "heat with electrical power.");
+  display_chiller(c);
+
+  simgrid::s4u::this_actor::sleep_for(1);
+  display_chiller(c);
+
+  XBT_INFO("Let's compute something.");
+  sg4::this_actor::execute(1e10);
+  XBT_INFO("Computation done.");
+  display_chiller(c);
+  XBT_INFO("Now let's stress the chiller by decreasing the goal temperature to 23°C.");
+  c->set_goal_temp(23);
+
+  simgrid::s4u::this_actor::sleep_for(1);
+  display_chiller(c);
+
+  simgrid::s4u::this_actor::sleep_for(c->get_time_to_goal_temp());
+  XBT_INFO("The input temperature is back to the goal temperature.");
+  display_chiller(c);
+
+  simgrid::s4u::this_actor::sleep_for(1);
+  display_chiller(c);
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+  sg_host_energy_plugin_init();
+
+  auto chiller = simgrid::plugins::Chiller::init("Chiller", 294, 1006, 0.2, 0.9, 23, 24, 1000);
+  chiller->add_host(e.host_by_name("MyHost1"));
+  chiller->add_host(e.host_by_name("MyHost2"));
+  chiller->add_host(e.host_by_name("MyHost3"));
+  sg4::Actor::create("manager", e.host_by_name("MyHost1"), manager, chiller);
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/chiller-simple/s4u-chiller-simple.tesh b/examples/cpp/chiller-simple/s4u-chiller-simple.tesh
new file mode 100644 (file)
index 0000000..33e196f
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-chiller-simple ${platfdir}/energy_platform.xml
+> [MyHost1:manager:(1) 0.000000] [chiller_simple/INFO] Chiller: Power: 0.00W T_in: 23.00°C Energy consumed: 0.00J
+> [MyHost1:manager:(1) 821.566667] [chiller_simple/INFO] The input temperature is now equal to the goal temperature. After this point the Chiller will compensate heat with electrical power.
+> [MyHost1:manager:(1) 821.566667] [chiller_simple/INFO] Chiller: Power: 0.00W T_in: 24.00°C Energy consumed: 0.00J
+> [MyHost1:manager:(1) 822.566667] [chiller_simple/INFO] Chiller: Power: 400.00W T_in: 24.00°C Energy consumed: 400.00J
+> [MyHost1:manager:(1) 822.566667] [chiller_simple/INFO] Let's compute something.
+> [MyHost1:manager:(1) 922.566667] [chiller_simple/INFO] Computation done.
+> [MyHost1:manager:(1) 922.566667] [chiller_simple/INFO] Chiller: Power: 426.67W T_in: 24.00°C Energy consumed: 43066.67J
+> [MyHost1:manager:(1) 922.566667] [chiller_simple/INFO] Now let's stress the chiller by decreasing the goal temperature to 23°C.
+> [MyHost1:manager:(1) 923.566667] [chiller_simple/INFO] Chiller: Power: 1000.00W T_in: 24.00°C Energy consumed: 44066.67J
+> [MyHost1:manager:(1) 1470.277778] [chiller_simple/INFO] The input temperature is back to the goal temperature.
+> [MyHost1:manager:(1) 1470.277778] [chiller_simple/INFO] Chiller: Power: 1000.00W T_in: 23.00°C Energy consumed: 590777.78J
+> [MyHost1:manager:(1) 1471.277778] [chiller_simple/INFO] Chiller: Power: 400.00W T_in: 23.00°C Energy consumed: 591177.78J
+> [1471.277778] [host_energy/INFO] Total energy consumption: 443383.333333 Joules (used hosts: 149127.777778 Joules; unused/idle hosts: 294255.555556)
+> [1471.277778] [host_energy/INFO] Energy consumption of host MyHost1: 149127.777778 Joules
+> [1471.277778] [host_energy/INFO] Energy consumption of host MyHost2: 147127.777778 Joules
+> [1471.277778] [host_energy/INFO] Energy consumption of host MyHost3: 147127.777778 Joules
\ No newline at end of file
index f0c2b7e..b2ca2e7 100644 (file)
@@ -24,7 +24,7 @@ public:
   void operator()() const
   {
     /* Vector in which we store all ongoing communications */
-    std::vector<sg4::CommPtr> pending_comms;
+    sg4::ActivitySet pending_comms;
 
     /* Make a vector of the mailboxes to use */
     std::vector<sg4::Mailbox*> mboxes;
@@ -37,16 +37,16 @@ public:
       auto* payload = new std::string(msg_content);
 
       /* Create a communication representing the ongoing communication, and store it in pending_comms */
-      auto mbox = sg4::Mailbox::by_name(host->get_name());
+      auto* mbox = sg4::Mailbox::by_name(host->get_name());
       mboxes.push_back(mbox);
       sg4::CommPtr comm = mbox->put_async(payload, msg_size);
-      pending_comms.push_back(comm);
+      pending_comms.push(comm);
     }
 
     XBT_INFO("Done dispatching all messages");
 
     /* Now that all message exchanges were initiated, wait for their completion in one single call */
-    sg4::Comm::wait_all(pending_comms);
+    pending_comms.wait_all();
 
     XBT_INFO("Goodbye now!");
   }
@@ -57,7 +57,7 @@ class Receiver {
 public:
   void operator()() const
   {
-    auto mbox     = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
+    auto* mbox    = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
     auto received = mbox->get_unique<std::string>();
     XBT_INFO("I got a '%s'.", received->c_str());
   }
@@ -87,8 +87,7 @@ public:
  * @param id Internal identifier in the torus (for information)
  * @return netpoint, gateway: the netpoint to the StarZone and CPU0 as gateway
  */
-static std::pair<simgrid::kernel::routing::NetPoint*, simgrid::kernel::routing::NetPoint*>
-create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned long>& /*coord*/, unsigned long id)
+static sg4::NetZone* create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned long>& /*coord*/, unsigned long id)
 {
   constexpr int num_cpus    = 8;     //!< Number of CPUs in the zone
   constexpr double speed    = 1e9;   //!< Speed of each CPU
@@ -101,24 +100,21 @@ create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned long>& /*co
   /* setting my Torus parent zone */
   host_zone->set_parent(zone);
 
-  simgrid::kernel::routing::NetPoint* gateway = nullptr;
   /* create CPUs */
   for (int i = 0; i < num_cpus; i++) {
     std::string cpu_name  = hostname + "-cpu" + std::to_string(i);
-    const sg4::Host* host = host_zone->create_host(cpu_name, speed)->seal();
+    const sg4::Host* host = host_zone->create_host(cpu_name, speed);
     /* the first CPU is the gateway */
     if (i == 0)
-      gateway = host->get_netpoint();
+      host_zone->set_gateway(host->get_netpoint());
     /* create split-duplex link */
-    sg4::SplitDuplexLink* link = host_zone->create_split_duplex_link("link-" + cpu_name, link_bw);
-    link->set_latency(link_lat)->seal();
+    auto* link = host_zone->create_split_duplex_link("link-" + cpu_name, link_bw)->set_latency(link_lat);
     /* connecting CPU to outer world */
-    host_zone->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, {{link, sg4::LinkInRoute::Direction::UP}},
-                         true);
+    host_zone->add_route(host, nullptr, {{link, sg4::LinkInRoute::Direction::UP}}, true);
   }
   /* seal newly created netzone */
   host_zone->seal();
-  return std::make_pair(host_zone->get_netpoint(), gateway);
+  return host_zone;
 }
 
 /*************************************************************************************************/
index c278fac..33c7729 100644 (file)
@@ -24,8 +24,8 @@ public:
 
   void operator()() const
   {
-    auto mailbox1 = sg4::Mailbox::by_name(mailbox1_name);
-    auto mailbox2 = sg4::Mailbox::by_name(mailbox2_name);
+    auto* mailbox1 = sg4::Mailbox::by_name(mailbox1_name);
+    auto* mailbox2 = sg4::Mailbox::by_name(mailbox2_name);
 
     XBT_INFO("Initiating asynchronous send to %s", mailbox1->get_cname());
     auto comm1 = mailbox1->put_async((void*)666, 5);
@@ -33,12 +33,12 @@ public:
     auto comm2 = mailbox2->put_async((void*)666, 2);
 
     XBT_INFO("Calling wait_any..");
-    std::vector<sg4::CommPtr> pending_comms;
-    pending_comms.push_back(comm1);
-    pending_comms.push_back(comm2);
+    sg4::ActivitySet pending_comms;
+    pending_comms.push(comm1);
+    pending_comms.push(comm2);
     try {
-      long index = sg4::Comm::wait_any(pending_comms);
-      XBT_INFO("Wait any returned index %ld (comm to %s)", index, pending_comms.at(index)->get_mailbox()->get_cname());
+      auto* acti = pending_comms.wait_any().get();
+      XBT_INFO("Wait any returned comm to %s", dynamic_cast<sg4::Comm*>(acti)->get_mailbox()->get_cname());
     } catch (const simgrid::NetworkFailureException&) {
       XBT_INFO("Sender has experienced a network failure exception, so it knows that something went wrong");
       XBT_INFO("Now it needs to figure out which of the two comms failed by looking at their state:");
@@ -52,8 +52,7 @@ public:
       XBT_INFO("Waiting on a FAILED comm raises an exception: '%s'", e.what());
     }
     XBT_INFO("Wait for remaining comm, just to be nice");
-    pending_comms.erase(pending_comms.begin());
-    sg4::Comm::wait_any(pending_comms);
+    pending_comms.wait_all();
   }
 };
 
@@ -82,18 +81,17 @@ int main(int argc, char** argv)
   auto* host1 = zone->create_host("Host1", "1f");
   auto* host2 = zone->create_host("Host2", "1f");
   auto* host3 = zone->create_host("Host3", "1f");
+  auto* link2 = zone->create_link("linkto2", "1bps")->seal();
+  auto* link3 = zone->create_link("linkto3", "1bps")->seal();
 
-  sg4::LinkInRoute linkto2{zone->create_link("linkto2", "1bps")->seal()};
-  sg4::LinkInRoute linkto3{zone->create_link("linkto3", "1bps")->seal()};
-
-  zone->add_route(host1->get_netpoint(), host2->get_netpoint(), nullptr, nullptr, {linkto2}, false);
-  zone->add_route(host1->get_netpoint(), host3->get_netpoint(), nullptr, nullptr, {linkto3}, false);
+  zone->add_route(host1, host2, {link2});
+  zone->add_route(host1, host3, {link3});
   zone->seal();
 
   sg4::Actor::create("Sender", host1, Sender("mailbox2", "mailbox3"));
   sg4::Actor::create("Receiver", host2, Receiver("mailbox2"));
   sg4::Actor::create("Receiver", host3, Receiver("mailbox3"));
-  
+
   sg4::Actor::create("LinkKiller", host1, [](){
     sg4::this_actor::sleep_for(10.0);
     XBT_INFO("Turning off link 'linkto2'");
index f3dcc62..8a58871 100644 (file)
@@ -14,4 +14,4 @@ $ ${bindir:=.}/s4u-comm-failure "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
 > [ 10.000000] (1:Sender@Host1)   Comm to mailbox3 has state: STARTED
 > [ 10.000000] (1:Sender@Host1) Waiting on a FAILED comm raises an exception: 'Cannot wait for a failed communication'
 > [ 10.000000] (1:Sender@Host1) Wait for remaining comm, just to be nice
-> [ 16.494845] (3:Receiver@Host3) Receiver has received successfully!
+> [ 17.319588] (3:Receiver@Host3) Receiver has received successfully!
index 6897298..f46ee8d 100644 (file)
@@ -33,7 +33,7 @@ static void peer(int my_id, int messages_count, size_t payload_size, int peers_c
   sg4::Mailbox* my_mbox = sg4::Mailbox::by_name("peer-" + std::to_string(my_id));
   my_mbox->set_receiver(sg4::Actor::self());
 
-  std::vector<sg4::CommPtr> pending_comms;
+  sg4::ActivitySet pending_comms;
 
   /* Start dispatching all messages to peers others that myself */
   for (int i = 0; i < messages_count; i++) {
@@ -45,7 +45,7 @@ static void peer(int my_id, int messages_count, size_t payload_size, int peers_c
         // 'message' is not a stable storage location
         XBT_INFO("Send '%s' to '%s'", message.c_str(), mbox->get_cname());
         /* Create a communication representing the ongoing communication */
-        pending_comms.push_back(mbox->put_async(payload, payload_size));
+        pending_comms.push(mbox->put_async(payload, payload_size));
       }
     }
   }
@@ -55,7 +55,7 @@ static void peer(int my_id, int messages_count, size_t payload_size, int peers_c
     if (peer_id != my_id) {
       sg4::Mailbox* mbox = sg4::Mailbox::by_name("peer-" + std::to_string(peer_id));
       auto* payload      = new std::string("finalize"); // Make a copy of the data we will send
-      pending_comms.push_back(mbox->put_async(payload, payload_size));
+      pending_comms.push(mbox->put_async(payload, payload_size));
       XBT_INFO("Send 'finalize' to 'peer-%d'", peer_id);
     }
   }
@@ -84,7 +84,7 @@ static void peer(int my_id, int messages_count, size_t payload_size, int peers_c
   }
 
   XBT_INFO("I'm done, just waiting for my peers to receive the messages before exiting");
-  sg4::Comm::wait_all(pending_comms);
+  pending_comms.wait_all();
 
   XBT_INFO("Goodbye now!");
 }
diff --git a/examples/cpp/comm-testany/s4u-comm-testany.cpp b/examples/cpp/comm-testany/s4u-comm-testany.cpp
deleted file mode 100644 (file)
index f06cb16..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "simgrid/s4u.hpp"
-#include <cstdlib>
-#include <iostream>
-#include <string>
-namespace sg4 = simgrid::s4u;
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_testany, "Messages specific for this s4u example");
-
-static void rank0()
-{
-  sg4::Mailbox* mbox = sg4::Mailbox::by_name("rank0");
-  std::string* msg1;
-  std::string* msg2;
-  std::string* msg3;
-
-  XBT_INFO("Post my asynchronous receives");
-  auto comm1                              = mbox->get_async(&msg1);
-  auto comm2                              = mbox->get_async(&msg2);
-  auto comm3                              = mbox->get_async(&msg3);
-  std::vector<sg4::CommPtr> pending_comms = {comm1, comm2, comm3};
-
-  XBT_INFO("Send some data to rank-1");
-  for (int i = 0; i < 3; i++)
-    sg4::Mailbox::by_name("rank1")->put(new int(i), 1);
-
-  XBT_INFO("Test for completed comms");
-  while (not pending_comms.empty()) {
-    ssize_t flag = sg4::Comm::test_any(pending_comms);
-    if (flag != -1) {
-      pending_comms.erase(pending_comms.begin() + flag);
-      XBT_INFO("Remove a pending comm.");
-    } else // nothing matches, wait for a little bit
-      sg4::this_actor::sleep_for(0.1);
-  }
-  XBT_INFO("Last comm is complete");
-  delete msg1;
-  delete msg2;
-  delete msg3;
-}
-
-static void rank1()
-{
-  sg4::Mailbox* rank0_mbox = sg4::Mailbox::by_name("rank0");
-  sg4::Mailbox* rank1_mbox = sg4::Mailbox::by_name("rank1");
-
-  for (int i = 0; i < 3; i++) {
-    auto res = rank1_mbox->get_unique<int>();
-    XBT_INFO("Received %d", *res);
-    std::string msg_content = "Message " + std::to_string(i);
-    auto* payload           = new std::string(msg_content);
-    XBT_INFO("Send '%s'", msg_content.c_str());
-    rank0_mbox->put(payload, 1e6);
-  }
-}
-
-int main(int argc, char* argv[])
-{
-  sg4::Engine e(&argc, argv);
-
-  e.load_platform(argv[1]);
-
-  sg4::Actor::create("rank-0", e.host_by_name("Tremblay"), rank0);
-  sg4::Actor::create("rank-1", e.host_by_name("Fafard"), rank1);
-
-  e.run();
-
-  return 0;
-}
diff --git a/examples/cpp/comm-testany/s4u-comm-testany.tesh b/examples/cpp/comm-testany/s4u-comm-testany.tesh
deleted file mode 100644 (file)
index 0f19916..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env tesh
-
-$ ${bindir:=.}/s4u-comm-testany ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e[%8h]%e[%a]%e%m%n"
-> [  0.000000] [Tremblay] [rank-0] Post my asynchronous receives
-> [  0.000000] [Tremblay] [rank-0] Send some data to rank-1
-> [  0.025708] [  Fafard] [rank-1] Received 0
-> [  0.025708] [  Fafard] [rank-1] Send 'Message 0'
-> [  0.209813] [  Fafard] [rank-1] Received 1
-> [  0.209813] [  Fafard] [rank-1] Send 'Message 1'
-> [  0.393918] [Tremblay] [rank-0] Test for completed comms
-> [  0.393918] [  Fafard] [rank-1] Received 2
-> [  0.393918] [  Fafard] [rank-1] Send 'Message 2'
-> [  0.393918] [Tremblay] [rank-0] Remove a pending comm.
-> [  0.393918] [Tremblay] [rank-0] Remove a pending comm.
-> [  0.593918] [Tremblay] [rank-0] Remove a pending comm.
-> [  0.593918] [Tremblay] [rank-0] Last comm is complete
diff --git a/examples/cpp/comm-waitall/s4u-comm-waitall.cpp b/examples/cpp/comm-waitall/s4u-comm-waitall.cpp
deleted file mode 100644 (file)
index 5c3f863..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* This example shows how to block on the completion of a set of communications.
- *
- * As for the other asynchronous examples, the sender initiate all the messages it wants to send and
- * pack the resulting simgrid::s4u::CommPtr objects in a vector. All messages thus occur concurrently.
- *
- * The sender then blocks until all ongoing communication terminate, using simgrid::s4u::Comm::wait_all()
- *
- */
-
-#include "simgrid/s4u.hpp"
-#include <cstdlib>
-#include <iostream>
-#include <string>
-namespace sg4 = simgrid::s4u;
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_async_waitall, "Messages specific for this s4u example");
-
-static void sender(unsigned int messages_count, unsigned int receivers_count, long msg_size)
-{
-  if (messages_count == 0 || receivers_count == 0) {
-    XBT_WARN("Sender has nothing to do. Bail out!");
-    return;
-  }
-  // sphinx-doc: init-begin (this line helps the doc to build; ignore it)
-  /* Vector in which we store all ongoing communications */
-  std::vector<sg4::CommPtr> pending_comms;
-
-  /* Make a vector of the mailboxes to use */
-  std::vector<sg4::Mailbox*> mboxes;
-  for (unsigned int i = 0; i < receivers_count; i++)
-    mboxes.push_back(sg4::Mailbox::by_name("receiver-" + std::to_string(i)));
-  // sphinx-doc: init-end
-
-  /* Start dispatching all messages to receivers, in a round robin fashion */
-  for (unsigned int i = 0; i < messages_count; i++) {
-    std::string msg_content = "Message " + std::to_string(i);
-    // Copy the data we send: the 'msg_content' variable is not a stable storage location.
-    // It will be destroyed when this actor leaves the loop, ie before the receiver gets it
-    auto* payload = new std::string(msg_content);
-
-    XBT_INFO("Send '%s' to '%s'", msg_content.c_str(), mboxes[i % receivers_count]->get_cname());
-
-    /* Create a communication representing the ongoing communication, and store it in pending_comms */
-    sg4::CommPtr comm = mboxes[i % receivers_count]->put_async(payload, msg_size);
-    pending_comms.push_back(comm);
-  }
-
-  /* Start sending messages to let the workers know that they should stop */ // sphinx-doc: put-begin
-  for (unsigned int i = 0; i < receivers_count; i++) {
-    XBT_INFO("Send 'finalize' to 'receiver-%u'", i);
-    sg4::CommPtr comm = mboxes[i]->put_async(new std::string("finalize"), 0);
-    pending_comms.push_back(comm);
-  }
-  XBT_INFO("Done dispatching all messages");
-
-  /* Now that all message exchanges were initiated, wait for their completion in one single call */
-  sg4::Comm::wait_all(pending_comms);
-  // sphinx-doc: put-end
-
-  XBT_INFO("Goodbye now!");
-}
-
-/* Receiver actor expects 1 argument: its ID */
-static void receiver(int id)
-{
-  sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver-" + std::to_string(id));
-  XBT_INFO("Wait for my first message");
-  for (bool cont = true; cont;) {
-    auto received = mbox->get_unique<std::string>();
-    XBT_INFO("I got a '%s'.", received->c_str());
-    cont = (*received != "finalize"); // If it's a finalize message, we're done
-    // Receiving the message was all we were supposed to do
-  }
-}
-
-int main(int argc, char* argv[])
-{
-  sg4::Engine e(&argc, argv);
-
-  e.load_platform(argv[1]);
-
-  sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender, 5, 2, 1e6);
-  sg4::Actor::create("receiver", e.host_by_name("Ruby"), receiver, 0);
-  sg4::Actor::create("receiver", e.host_by_name("Perl"), receiver, 1);
-
-  e.run();
-
-  return 0;
-}
diff --git a/examples/cpp/comm-waitall/s4u-comm-waitall.tesh b/examples/cpp/comm-waitall/s4u-comm-waitall.tesh
deleted file mode 100644 (file)
index cdf7365..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env tesh
-
-$ ${bindir:=.}/s4u-comm-waitall ${platfdir}/small_platform_fatpipe.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (2:receiver@Ruby) Wait for my first message
-> [  0.000000] (3:receiver@Perl) Wait for my first message
-> [  0.000000] (1:sender@Tremblay) Send 'Message 0' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 1' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 2' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 3' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 4' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Done dispatching all messages
-> [  0.004022] (2:receiver@Ruby) I got a 'Message 0'.
-> [  0.004022] (3:receiver@Perl) I got a 'Message 1'.
-> [  0.008043] (2:receiver@Ruby) I got a 'Message 2'.
-> [  0.008043] (3:receiver@Perl) I got a 'Message 3'.
-> [  0.009995] (3:receiver@Perl) I got a 'finalize'.
-> [  0.012065] (2:receiver@Ruby) I got a 'Message 4'.
-> [  0.014016] (2:receiver@Ruby) I got a 'finalize'.
-> [  0.014016] (1:sender@Tremblay) Goodbye now!
diff --git a/examples/cpp/comm-waitany/s4u-comm-waitany.cpp b/examples/cpp/comm-waitany/s4u-comm-waitany.cpp
deleted file mode 100644 (file)
index 802a4fc..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* This example shows how to use simgrid::s4u::this_actor::wait_any() to wait for the first occurring event.
- *
- * As for the other asynchronous examples, the sender initiate all the messages it wants to send and
- * pack the resulting simgrid::s4u::CommPtr objects in a vector. All messages thus occur concurrently.
- *
- * The sender then loops until there is no ongoing communication. Using wait_any() ensures that the sender
- * will notice events as soon as they occur even if it does not follow the order of the container.
- *
- * Here, finalize messages will terminate earlier because their size is 0, so they travel faster than the
- * other messages of this application.  As expected, the trace shows that the finalize of worker 1 is
- * processed before 'Message 5' that is sent to worker 0.
- *
- */
-
-#include "simgrid/s4u.hpp"
-#include <cstdlib>
-#include <iostream>
-#include <string>
-namespace sg4 = simgrid::s4u;
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_comm_waitall, "Messages specific for this s4u example");
-
-static void sender(unsigned int messages_count, unsigned int receivers_count, long msg_size)
-{
-  if (messages_count == 0 || receivers_count == 0) {
-    XBT_WARN("Sender has nothing to do. Bail out!");
-    return;
-  }
-  /* Vector in which we store all ongoing communications */
-  std::vector<sg4::CommPtr> pending_comms;
-
-  /* Make a vector of the mailboxes to use */
-  std::vector<sg4::Mailbox*> mboxes;
-  for (unsigned int i = 0; i < receivers_count; i++)
-    mboxes.push_back(sg4::Mailbox::by_name("receiver-" + std::to_string(i)));
-
-  /* Start dispatching all messages to receivers, in a round robin fashion */
-  for (unsigned int i = 0; i < messages_count; i++) {
-    std::string msg_content = "Message " + std::to_string(i);
-    // Copy the data we send: the 'msg_content' variable is not a stable storage location.
-    // It will be destroyed when this actor leaves the loop, ie before the receiver gets it
-    auto* payload = new std::string(msg_content);
-
-    XBT_INFO("Send '%s' to '%s'", msg_content.c_str(), mboxes[i % receivers_count]->get_cname());
-
-    /* Create a communication representing the ongoing communication, and store it in pending_comms */
-    sg4::CommPtr comm = mboxes[i % receivers_count]->put_async(payload, msg_size);
-    pending_comms.push_back(comm);
-  }
-
-  /* Start sending messages to let the workers know that they should stop */
-  for (unsigned int i = 0; i < receivers_count; i++) {
-    XBT_INFO("Send 'finalize' to 'receiver-%u'", i);
-    sg4::CommPtr comm = mboxes[i]->put_async(new std::string("finalize"), 0);
-    pending_comms.push_back(comm);
-  }
-  XBT_INFO("Done dispatching all messages");
-
-  /* Now that all message exchanges were initiated, wait for their completion, in order of termination.
-   *
-   * This loop waits for first terminating message with wait_any() and remove it with erase(), until all comms are
-   * terminated
-   * Even in this simple example, the pending comms do not terminate in the exact same order of creation.
-   */
-  while (not pending_comms.empty()) {
-    ssize_t changed_pos = sg4::Comm::wait_any(pending_comms);
-    pending_comms.erase(pending_comms.begin() + changed_pos);
-    if (changed_pos != 0)
-      XBT_INFO("Remove the %zdth pending comm: it terminated earlier than another comm that was initiated first.",
-               changed_pos);
-  }
-
-  XBT_INFO("Goodbye now!");
-}
-
-/* Receiver actor expects 1 argument: its ID */
-static void receiver(int id)
-{
-  sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver-" + std::to_string(id));
-  XBT_INFO("Wait for my first message");
-  for (bool cont = true; cont;) {
-    auto received = mbox->get_unique<std::string>();
-    XBT_INFO("I got a '%s'.", received->c_str());
-    cont = (*received != "finalize"); // If it's a finalize message, we're done
-    // Receiving the message was all we were supposed to do
-  }
-}
-
-int main(int argc, char* argv[])
-{
-  sg4::Engine e(&argc, argv);
-
-  e.load_platform(argv[1]);
-
-  sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender, 6, 2, 1e6);
-  sg4::Actor::create("receiver", e.host_by_name("Fafard"), receiver, 0);
-  sg4::Actor::create("receiver", e.host_by_name("Jupiter"), receiver, 1);
-
-  e.run();
-
-  return 0;
-}
diff --git a/examples/cpp/comm-waitany/s4u-comm-waitany.tesh b/examples/cpp/comm-waitany/s4u-comm-waitany.tesh
deleted file mode 100644 (file)
index 5fe9dc9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env tesh
-
-p Testing this_actor->wait_any()
-
-! output sort 19
-$ ${bindir:=.}/s4u-comm-waitany ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (1:sender@Tremblay) Send 'Message 0' to 'receiver-0'
-> [  0.000000] (2:receiver@Fafard) Wait for my first message
-> [  0.000000] (3:receiver@Jupiter) Wait for my first message
-> [  0.000000] (1:sender@Tremblay) Send 'Message 1' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 2' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 3' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 4' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 5' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'receiver-0'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'receiver-1'
-> [  0.000000] (1:sender@Tremblay) Done dispatching all messages
-> [  0.158397] (2:receiver@Fafard) I got a 'Message 0'.
-> [  0.169155] (3:receiver@Jupiter) I got a 'Message 1'.
-> [  0.316794] (2:receiver@Fafard) I got a 'Message 2'.
-> [  0.338309] (3:receiver@Jupiter) I got a 'Message 3'.
-> [  0.475190] (2:receiver@Fafard) I got a 'Message 4'.
-> [  0.500898] (2:receiver@Fafard) I got a 'finalize'.
-> [  0.500898] (1:sender@Tremblay) Remove the 1th pending comm: it terminated earlier than another comm that was initiated first.
-> [  0.507464] (3:receiver@Jupiter) I got a 'Message 5'.
-> [  0.526478] (3:receiver@Jupiter) I got a 'finalize'.
-> [  0.526478] (1:sender@Tremblay) Goodbye now!
index 9e671b4..77cb31d 100644 (file)
@@ -13,24 +13,27 @@ namespace sg4 = simgrid::s4u;
 int main(int argc, char* argv[])
 {
   sg4::Engine e(&argc, argv);
-  sg_storage_file_system_init();
   e.load_platform(argv[1]);
 
-  auto tremblay = e.host_by_name("Tremblay");
-  auto jupiter  = e.host_by_name("Jupiter");
+  auto* tremblay = e.host_by_name("Tremblay");
+  auto* jupiter  = e.host_by_name("Jupiter");
 
   // Display the details on vetoed activities
-  sg4::Activity::on_veto_cb([](const sg4::Activity& a) {
-    XBT_INFO("Activity '%s' vetoed. Dependencies: %s; Ressources: %s", a.get_cname(),
-             (a.dependencies_solved() ? "solved" : "NOT solved"), (a.is_assigned() ? "assigned" : "NOT assigned"));
+  sg4::Exec::on_veto_cb([](sg4::Exec const& exec) {
+    XBT_INFO("Execution '%s' vetoed. Dependencies: %s; Ressources: %s", exec.get_cname(),
+             (exec.dependencies_solved() ? "solved" : "NOT solved"), (exec.is_assigned() ? "assigned" : "NOT assigned"));
+  });
+  sg4::Comm::on_veto_cb([](sg4::Comm const& comm) {
+    XBT_INFO("Communication '%s' vetoed. Dependencies: %s; Ressources: %s", comm.get_cname(),
+             (comm.dependencies_solved() ? "solved" : "NOT solved"), (comm.is_assigned() ? "assigned" : "NOT assigned"));
   });
 
-  sg4::Activity::on_completion_cb([](sg4::Activity const& activity) {
-    if (const auto* exec = dynamic_cast<sg4::Exec const*>(&activity))
-      XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", exec->get_cname(), exec->get_start_time(),
-               exec->get_finish_time());
-    if (const auto* comm = dynamic_cast<sg4::Comm const*>(&activity))
-      XBT_INFO("Activity '%s' is complete", comm->get_cname());
+  sg4::Exec::on_completion_cb([](sg4::Exec const& exec) {
+    XBT_INFO("Exec '%s' is complete (start time: %f, finish time: %f)", exec.get_cname(), exec.get_start_time(),
+             exec.get_finish_time());
+  });
+  sg4::Comm::on_completion_cb([](sg4::Comm const& comm) {
+    XBT_INFO("Comm '%s' is complete", comm.get_cname());
   });
 
   // Create a small DAG: parent->transfer->child
index 2d000a0..abe40f4 100644 (file)
@@ -1,18 +1,18 @@
 #!/usr/bin/env tesh
 
 $ ${bindir:=.}/s4u-dag-comm ${platfdir}/two_hosts.xml --log=s4u_activity.t:verbose "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (0:maestro@) Activity 'parent' vetoed. Dependencies: solved; Ressources: NOT assigned
-> [  0.000000] (0:maestro@) Activity 'transfer' vetoed. Dependencies: NOT solved; Ressources: NOT assigned
-> [  0.000000] (0:maestro@) Activity 'child' vetoed. Dependencies: NOT solved; Ressources: NOT assigned
+> [  0.000000] (0:maestro@) Execution 'parent' vetoed. Dependencies: solved; Ressources: NOT assigned
+> [  0.000000] (0:maestro@) Communication 'transfer' vetoed. Dependencies: NOT solved; Ressources: NOT assigned
+> [  0.000000] (0:maestro@) Execution 'child' vetoed. Dependencies: NOT solved; Ressources: NOT assigned
 > [  0.000000] (0:maestro@) 'parent' is assigned to a resource and all dependencies are solved. Let's start
-> [  0.000000] (0:maestro@) Activity 'transfer' vetoed. Dependencies: NOT solved; Ressources: NOT assigned
-> [  0.000000] (0:maestro@) Activity 'child' vetoed. Dependencies: NOT solved; Ressources: assigned
-> [  0.000000] (0:maestro@) Activity 'transfer' vetoed. Dependencies: NOT solved; Ressources: assigned
-> [  1.000000] (0:maestro@) Activity 'parent' is complete (start time: 0.000000, finish time: 1.000000)
+> [  0.000000] (0:maestro@) Communication 'transfer' vetoed. Dependencies: NOT solved; Ressources: NOT assigned
+> [  0.000000] (0:maestro@) Execution 'child' vetoed. Dependencies: NOT solved; Ressources: assigned
+> [  0.000000] (0:maestro@) Communication 'transfer' vetoed. Dependencies: NOT solved; Ressources: assigned
+> [  1.000000] (0:maestro@) Exec 'parent' is complete (start time: 0.000000, finish time: 1.000000)
 > [  1.000000] (0:maestro@) Remove a dependency from 'parent' on 'transfer'
 > [  1.000000] (0:maestro@) 'transfer' is assigned to a resource and all dependencies are solved. Let's start
-> [  2.083775] (0:maestro@) Activity 'transfer' is complete
 > [  2.083775] (0:maestro@) Remove a dependency from 'transfer' on 'child'
 > [  2.083775] (0:maestro@) 'child' is assigned to a resource and all dependencies are solved. Let's start
-> [  3.083775] (0:maestro@) Activity 'child' is complete (start time: 2.083775, finish time: 3.083775)
+> [  2.083775] (0:maestro@) Comm 'transfer' is complete
+> [  3.083775] (0:maestro@) Exec 'child' is complete (start time: 2.083775, finish time: 3.083775)
 > [  3.083775] (0:maestro@) Simulation time 3.08378
index 631b24c..c2ab8d5 100644 (file)
@@ -18,19 +18,16 @@ int main(int argc, char** argv)
 
   auto* faulty = e.host_by_name("Faulty Host");
   auto* safe   = e.host_by_name("Safe Host");
-  sg4::Activity::on_completion_cb([](sg4::Activity const& activity) {
-    const auto* exec = dynamic_cast<sg4::Exec const*>(&activity);
-    if (exec == nullptr) // Only Execs are concerned here
-      return;
-    if (exec->get_state() == sg4::Activity::State::FINISHED)
-      XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", exec->get_cname(), exec->get_start_time(),
-               exec->get_finish_time());
-    if (exec->get_state() == sg4::Activity::State::FAILED) {
-      if (exec->is_parallel())
-        XBT_INFO("Activity '%s' has failed. %.f %% remain to be done", exec->get_cname(),
-                 100 * exec->get_remaining_ratio());
+  sg4::Exec::on_completion_cb([](sg4::Exec const& exec) {
+    if (exec.get_state() == sg4::Activity::State::FINISHED)
+      XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", exec.get_cname(), exec.get_start_time(),
+               exec.get_finish_time());
+    if (exec.get_state() == sg4::Activity::State::FAILED) {
+      if (exec.is_parallel())
+        XBT_INFO("Activity '%s' has failed. %.f %% remain to be done", exec.get_cname(),
+                 100 * exec.get_remaining_ratio());
       else
-        XBT_INFO("Activity '%s' has failed. %.f flops remain to be done", exec->get_cname(), exec->get_remaining());
+        XBT_INFO("Activity '%s' has failed. %.f flops remain to be done", exec.get_cname(), exec.get_remaining());
     }
   });
 
diff --git a/examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.cpp b/examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.cpp
new file mode 100644 (file)
index 0000000..aa8e17d
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (c) 2003-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(dag_from_dax_simple, "Messages specific for this s4u example");
+
+int main(int argc, char* argv[])
+{
+  simgrid::s4u::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_DAX(argv[2]);
+
+  simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
+  simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
+  simgrid::s4u::Host* fafard   = e.host_by_name("Fafard");
+
+  dynamic_cast<simgrid::s4u::Exec*>(dag[0].get())->set_host(fafard);
+  dynamic_cast<simgrid::s4u::Exec*>(dag[1].get())->set_host(tremblay);
+  dynamic_cast<simgrid::s4u::Exec*>(dag[2].get())->set_host(jupiter);
+  dynamic_cast<simgrid::s4u::Exec*>(dag[3].get())->set_host(jupiter);
+  dynamic_cast<simgrid::s4u::Exec*>(dag[8].get())->set_host(jupiter);
+
+  for (const auto& a : dag) {
+    if (auto* comm = dynamic_cast<simgrid::s4u::Comm*>(a.get())) {
+      const auto* pred = dynamic_cast<simgrid::s4u::Exec*>((*comm->get_dependencies().begin()).get());
+      const auto* succ = dynamic_cast<simgrid::s4u::Exec*>(comm->get_successors().front().get());
+      comm->set_source(pred->get_host())->set_destination(succ->get_host());
+    }
+  }
+
+  simgrid::s4u::Exec::on_completion_cb([](simgrid::s4u::Exec const& exec) {
+    XBT_INFO("Exec '%s' is complete (start time: %f, finish time: %f)", exec.get_cname(),
+             exec.get_start_time(), exec.get_finish_time());
+  });
+
+  simgrid::s4u::Comm::on_completion_cb([](simgrid::s4u::Comm const& comm) {
+    XBT_INFO("Comm '%s' is complete (start time: %f, finish time: %f)", comm.get_cname(),
+             comm.get_start_time(), comm.get_finish_time());
+  });
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.tesh b/examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.tesh
new file mode 100644 (file)
index 0000000..af5a6f2
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-dag-from-dax-simple --log=no_loc ${platfdir}/small_platform.xml ${srcdir:=.}/dag.xml
+> [0.000000] [dag_from_dax_simple/INFO] Exec 'root' is complete (start time: 0.000000, finish time: 0.000000)
+> [33.394394] [dag_from_dax_simple/INFO] Comm 'root_i2_2@c2' is complete (start time: 0.000000, finish time: 33.394394)
+> [39.832311] [dag_from_dax_simple/INFO] Comm 'root_i1_1@c1' is complete (start time: 0.000000, finish time: 39.832311)
+> [467.988690] [dag_from_dax_simple/INFO] Exec '1@c1' is complete (start time: 39.832311, finish time: 467.988690)
+> [543.077868] [dag_from_dax_simple/INFO] Comm '1@c1_o1_3@c3' is complete (start time: 467.988690, finish time: 543.077868)
+> [2785.832267] [dag_from_dax_simple/INFO] Exec '2@c2' is complete (start time: 33.394394, finish time: 2785.832267)
+> [3886.807417] [dag_from_dax_simple/INFO] Exec '3@c3' is complete (start time: 2785.832267, finish time: 3886.807417)
+> [3887.221639] [dag_from_dax_simple/INFO] Comm '3@c3_o3_end' is complete (start time: 3886.807417, finish time: 3887.221639)
+> [3887.221639] [dag_from_dax_simple/INFO] Exec 'end' is complete (start time: 3887.221639, finish time: 3887.221639)
\ No newline at end of file
index 3bae907..9c62ac8 100644 (file)
@@ -51,8 +51,8 @@ int main(int argc, char** argv)
       cursor++;
     }
     if (auto* comm = dynamic_cast<sg4::Comm*>(a.get())) {
-      auto pred = dynamic_cast<sg4::Exec*>((*comm->get_dependencies().begin()).get());
-      auto succ = dynamic_cast<sg4::Exec*>(comm->get_successors().front().get());
+      const auto* pred = dynamic_cast<sg4::Exec*>((*comm->get_dependencies().begin()).get());
+      const auto* succ = dynamic_cast<sg4::Exec*>(comm->get_successors().front().get());
       comm->set_source(pred->get_host())->set_destination(succ->get_host());
     }
   }
diff --git a/examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.cpp b/examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.cpp
new file mode 100644 (file)
index 0000000..a6972b0
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (c) 2003-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(dag_from_dot_simple, "Messages specific for this s4u example");
+
+int main(int argc, char* argv[])
+{
+  simgrid::s4u::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_dot(argv[2]);
+
+  simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
+  simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
+  simgrid::s4u::Host* fafard   = e.host_by_name("Fafard");
+
+  dynamic_cast<simgrid::s4u::Exec*>(dag[0].get())->set_host(fafard);
+  dynamic_cast<simgrid::s4u::Exec*>(dag[1].get())->set_host(tremblay);
+  dynamic_cast<simgrid::s4u::Exec*>(dag[2].get())->set_host(jupiter);
+  dynamic_cast<simgrid::s4u::Exec*>(dag[3].get())->set_host(jupiter);
+  dynamic_cast<simgrid::s4u::Exec*>(dag[8].get())->set_host(jupiter);
+
+  for (const auto& a : dag) {
+    if (auto* comm = dynamic_cast<simgrid::s4u::Comm*>(a.get())) {
+      const auto* pred = dynamic_cast<simgrid::s4u::Exec*>((*comm->get_dependencies().begin()).get());
+      const auto* succ = dynamic_cast<simgrid::s4u::Exec*>(comm->get_successors().front().get());
+      comm->set_source(pred->get_host())->set_destination(succ->get_host());
+    }
+  }
+
+  simgrid::s4u::Exec::on_completion_cb([](simgrid::s4u::Exec const& exec) {
+    XBT_INFO("Exec '%s' is complete (start time: %f, finish time: %f)", exec.get_cname(),
+             exec.get_start_time(), exec.get_finish_time());
+  });
+
+  simgrid::s4u::Comm::on_completion_cb([](simgrid::s4u::Comm const& comm) {
+    XBT_INFO("Comm '%s' is complete (start time: %f, finish time: %f)", comm.get_cname(),
+             comm.get_start_time(), comm.get_finish_time());
+  });
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.tesh b/examples/cpp/dag-from-dot-simple/s4u-dag-from-dot-simple.tesh
new file mode 100644 (file)
index 0000000..6133b1b
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-dag-from-dot-simple --log=no_loc ${platfdir}/small_platform.xml ${srcdir:=.}/dag.dot
+> [0.000000] [dag_from_dot_simple/INFO] Exec 'root' is complete (start time: 0.000000, finish time: 0.000000)
+> [33.394394] [dag_from_dot_simple/INFO] Comm 'root->c2' is complete (start time: 0.000000, finish time: 33.394394)
+> [39.832311] [dag_from_dot_simple/INFO] Comm 'root->c1' is complete (start time: 0.000000, finish time: 39.832311)
+> [50.026511] [dag_from_dot_simple/INFO] Exec 'c1' is complete (start time: 39.832311, finish time: 50.026511)
+> [98.928629] [dag_from_dot_simple/INFO] Exec 'c2' is complete (start time: 33.394394, finish time: 98.928629)
+> [125.115689] [dag_from_dot_simple/INFO] Comm 'c1->c3' is complete (start time: 50.026511, finish time: 125.115689)
+> [151.329383] [dag_from_dot_simple/INFO] Exec 'c3' is complete (start time: 125.115689, finish time: 151.329383)
+> [151.743605] [dag_from_dot_simple/INFO] Comm 'c3->end' is complete (start time: 151.329383, finish time: 151.743605)
+> [151.743605] [dag_from_dot_simple/INFO] Exec 'end' is complete (start time: 151.743605, finish time: 151.743605)
\ No newline at end of file
index 079e323..30d2b75 100644 (file)
@@ -49,8 +49,8 @@ int main(int argc, char** argv)
       cursor++;
     }
     if (auto* comm = dynamic_cast<sg4::Comm*>(a.get())) {
-      auto pred = dynamic_cast<sg4::Exec*>((*comm->get_dependencies().begin()).get());
-      auto succ = dynamic_cast<sg4::Exec*>(comm->get_successors().front().get());
+      const auto* pred = dynamic_cast<sg4::Exec*>((*comm->get_dependencies().begin()).get());
+      const auto* succ = dynamic_cast<sg4::Exec*>(comm->get_successors().front().get());
       comm->set_source(pred->get_host())->set_destination(succ->get_host());
     }
   }
similarity index 81%
rename from docs/source/tuto_dag/simple_json.json
rename to examples/cpp/dag-from-json-simple/dag.json
index ea77850..fecb6e4 100644 (file)
@@ -2,35 +2,35 @@
   "name": "simple_json",
   "schemaVersion": "1.0",
   "workflow": {
-    "makespan": 0,
+    "makespanInSeconds": 0,
     "executedAt": "2023-03-09T00:00:00-00:00",
     "tasks": [
       {
         "name": "c1",
         "type": "compute",
         "parents": [],
-        "runtime": 1e9,
+        "runtimeInSeconds": 1e9,
         "machine": "Tremblay"
       },
       {
         "name": "t1",
         "type": "transfer",
         "parents": ["c1"],
-        "bytesWritten": 5e8,
+        "writtenBytes": 5e8,
         "machine": "Jupiter"
       },
       {
         "name": "c2",
         "type": "compute",
         "parents": [],
-        "runtime": 5e9,
+        "runtimeInSeconds": 5e9,
         "machine": "Jupiter"
       },
       {
         "name": "c3",
         "type": "compute",
         "parents": ["t1","c2"],
-        "runtime": 2e9,
+        "runtimeInSeconds": 2e9,
         "machine": "Jupiter"
       }
     ],
diff --git a/examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.cpp b/examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.cpp
new file mode 100644 (file)
index 0000000..bf87897
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (c) 2003-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(dag_from_json_simple, "Messages specific for this s4u example");
+
+int main(int argc, char* argv[])
+{
+  simgrid::s4u::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  std::vector<simgrid::s4u::ActivityPtr> dag = simgrid::s4u::create_DAG_from_json(argv[2]);
+
+   simgrid::s4u::Exec::on_completion_cb([](simgrid::s4u::Exec const& exec) {
+    XBT_INFO("Exec '%s' is complete (start time: %f, finish time: %f)", exec.get_cname(),
+             exec.get_start_time(), exec.get_finish_time());
+  });
+
+  simgrid::s4u::Comm::on_completion_cb([](simgrid::s4u::Comm const& comm) {
+    XBT_INFO("Comm '%s' is complete (start time: %f, finish time: %f)", comm.get_cname(),
+             comm.get_start_time(), comm.get_finish_time());
+  });
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.tesh b/examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple.tesh
new file mode 100644 (file)
index 0000000..cd41320
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-dag-from-json-simple --log=no_loc ${platfdir}/small_platform.xml ${srcdir:=.}/dag.json
+> [10.194200] [dag_from_json_simple/INFO] Exec 'c1' is complete (start time: 0.000000, finish time: 10.194200)
+> [65.534235] [dag_from_json_simple/INFO] Exec 'c2' is complete (start time: 0.000000, finish time: 65.534235)
+> [85.283378] [dag_from_json_simple/INFO] Comm 't1' is complete (start time: 10.194200, finish time: 85.283378)
+> [111.497072] [dag_from_json_simple/INFO] Exec 'c3' is complete (start time: 85.283378, finish time: 111.497072)
\ No newline at end of file
index ee00eb0..738f356 100644 (file)
@@ -13,24 +13,24 @@ namespace sg4 = simgrid::s4u;
 int main(int argc, char* argv[])
 {
   sg4::Engine e(&argc, argv);
-  sg_storage_file_system_init();
   e.load_platform(argv[1]);
 
-  auto bob  = e.host_by_name("bob");
-  auto carl = e.host_by_name("carl");
+  auto* bob  = e.host_by_name("bob");
+  auto* carl = e.host_by_name("carl");
 
   // Display the details on vetoed activities
-  sg4::Activity::on_veto_cb([](const sg4::Activity& a) {
-    XBT_INFO("Activity '%s' vetoed. Dependencies: %s; Ressources: %s", a.get_cname(),
-             (a.dependencies_solved() ? "solved" : "NOT solved"), (a.is_assigned() ? "assigned" : "NOT assigned"));
+  sg4::Exec::on_veto_cb([](sg4::Exec const& exec) {
+    XBT_INFO("Exec '%s' vetoed. Dependencies: %s; Ressources: %s", exec.get_cname(),
+             (exec.dependencies_solved() ? "solved" : "NOT solved"), (exec.is_assigned() ? "assigned" : "NOT assigned"));
+  });
+  sg4::Io::on_veto_cb([](sg4::Io const& io) {
+    XBT_INFO("Io '%s' vetoed. Dependencies: %s; Ressources: %s", io.get_cname(),
+             (io.dependencies_solved() ? "solved" : "NOT solved"), (io.is_assigned() ? "assigned" : "NOT assigned"));
   });
 
-  sg4::Activity::on_completion_cb([](sg4::Activity const& activity) {
-    const auto* exec = dynamic_cast<sg4::Exec const*>(&activity);
-    if (exec == nullptr) // Only Execs are concerned here
-      return;
-    XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", exec->get_cname(), exec->get_start_time(),
-             exec->get_finish_time());
+  sg4::Exec::on_completion_cb([](sg4::Exec const& exec) {
+    XBT_INFO("Exec '%s' is complete (start time: %f, finish time: %f)", exec.get_cname(), exec.get_start_time(),
+             exec.get_finish_time());
   });
 
   // Create a small DAG: parent->write_output->read_input->child
index 186126b..8c1c3ca 100644 (file)
@@ -2,15 +2,15 @@
 
 $ ${bindir:=.}/s4u-dag-io ${platfdir}/hosts_with_disks.xml --log=s4u_activity.t:verbose "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
 > [  0.000000] (0:maestro@) 'parent' is assigned to a resource and all dependencies are solved. Let's start
-> [  0.000000] (0:maestro@) Activity 'write' vetoed. Dependencies: NOT solved; Ressources: assigned
-> [  0.000000] (0:maestro@) Activity 'read' vetoed. Dependencies: NOT solved; Ressources: assigned
-> [  0.000000] (0:maestro@) Activity 'child' vetoed. Dependencies: NOT solved; Ressources: assigned
-> [  1.000000] (0:maestro@) Activity 'parent' is complete (start time: 0.000000, finish time: 1.000000)
+> [  0.000000] (0:maestro@) Io 'write' vetoed. Dependencies: NOT solved; Ressources: assigned
+> [  0.000000] (0:maestro@) Io 'read' vetoed. Dependencies: NOT solved; Ressources: assigned
+> [  0.000000] (0:maestro@) Exec 'child' vetoed. Dependencies: NOT solved; Ressources: assigned
+> [  1.000000] (0:maestro@) Exec 'parent' is complete (start time: 0.000000, finish time: 1.000000)
 > [  1.000000] (0:maestro@) Remove a dependency from 'parent' on 'write'
 > [  1.000000] (0:maestro@) 'write' is assigned to a resource and all dependencies are solved. Let's start
 > [ 26.000000] (0:maestro@) Remove a dependency from 'write' on 'read'
 > [ 26.000000] (0:maestro@) 'read' is assigned to a resource and all dependencies are solved. Let's start
 > [ 36.000000] (0:maestro@) Remove a dependency from 'read' on 'child'
 > [ 36.000000] (0:maestro@) 'child' is assigned to a resource and all dependencies are solved. Let's start
-> [ 37.000000] (0:maestro@) Activity 'child' is complete (start time: 36.000000, finish time: 37.000000)
+> [ 37.000000] (0:maestro@) Exec 'child' is complete (start time: 36.000000, finish time: 37.000000)
 > [ 37.000000] (0:maestro@) Simulation time 37
index d20de08..51dde09 100644 (file)
 XBT_LOG_NEW_DEFAULT_CATEGORY(dag_scheduling, "Logging specific to this example");
 namespace sg4 = simgrid::s4u;
 
-struct HostAttribute {
-  /* Earliest time at which a host is ready to execute a task */
-  double available_at                     = 0.0;
-  sg4::Exec* last_scheduled_task          = nullptr;
-};
-
-static double sg_host_get_available_at(const sg4::Host* host)
-{
-  return host->get_data<HostAttribute>()->available_at;
-}
-
-static void sg_host_set_available_at(const sg4::Host* host, double time)
-{
-  host->get_data<HostAttribute>()->available_at = time;
-}
-
-static sg4::Exec* sg_host_get_last_scheduled_task(const sg4::Host* host)
-{
-  return host->get_data<HostAttribute>()->last_scheduled_task;
-}
-
-static void sg_host_set_last_scheduled_task(const sg4::Host* host, sg4::ExecPtr task)
-{
-  host->get_data<HostAttribute>()->last_scheduled_task = task.get();
-}
-
-static bool dependency_exists(const sg4::Exec* src, sg4::Exec* dst)
-{
-  const auto& dependencies = src->get_dependencies();
-  const auto& successors   = src->get_successors();
-  return (std::find(successors.begin(), successors.end(), dst) != successors.end() ||
-          dependencies.find(dst) != dependencies.end());
-}
-
 static std::vector<sg4::Exec*> get_ready_tasks(const std::vector<sg4::ActivityPtr>& dax)
 {
   std::vector<sg4::Exec*> ready_tasks;
   std::map<sg4::Exec*, unsigned int> candidate_execs;
 
-  for (auto& a : dax) {
+  for (const auto& a : dax) {
     // Only look at activity that have their dependencies solved but are not assigned
     if (a->dependencies_solved() && not a->is_assigned()) {
       // if it is an exec, it's ready
@@ -71,61 +37,65 @@ static std::vector<sg4::Exec*> get_ready_tasks(const std::vector<sg4::ActivityPt
   return ready_tasks;
 }
 
-static double finish_on_at(const sg4::ExecPtr task, const sg4::Host* host)
+static sg4::Host* get_best_host(const sg4::ExecPtr exec, double* min_finish_time)
 {
-  double data_available      = 0.;
-  double last_data_available = -1.0;
-  /* compute last_data_available */
-  for (const auto& parent : task->get_dependencies()) {
-    /* normal case */
-    if (const auto* comm = dynamic_cast<sg4::Comm*>(parent.get())) {
-      auto source = comm->get_source();
-      XBT_DEBUG("transfer from %s to %s", source->get_cname(), host->get_cname());
-      /* Estimate the redistribution time from this parent */
-      double redist_time;
-      if (comm->get_remaining() <= 1e-6) {
-        redist_time = 0;
-      } else {
-        redist_time =
-            sg_host_get_route_latency(source, host) + comm->get_remaining() / sg_host_get_route_bandwidth(source, host);
+  sg4::Host* best_host = nullptr;
+  *min_finish_time = std::numeric_limits<double>::max();
+
+  for (const auto& host : sg4::Engine::get_instance()->get_all_hosts()) {
+    double data_available      = 0.;
+    double last_data_available = -1.0;
+    /* compute last_data_available */
+    for (const auto& parent : exec->get_dependencies()) {
+      /* normal case */
+      if (const auto* comm = dynamic_cast<sg4::Comm*>(parent.get())) {
+        const auto* source = comm->get_source();
+        XBT_DEBUG("transfer from %s to %s", source->get_cname(), host->get_cname());
+        /* Estimate the redistribution time from this parent */
+        double redist_time;
+        if (comm->get_remaining() <= 1e-6) {
+          redist_time = 0;
+        } else {
+          double bandwidth      = std::numeric_limits<double>::max();
+          auto [links, latency] = source->route_to(host);
+          for (auto const& link : links)
+            bandwidth = std::min(bandwidth, link->get_bandwidth());
+
+          redist_time = latency + comm->get_remaining() / bandwidth;
+        }
+        // We use the user data field to store the finish time of the predecessor of the comm, i.e., its potential
+        // start time
+        data_available = *comm->get_data<double>() + redist_time;
       }
-      // We use the user data field to store the finish time of the predecessor of the comm, i.e., its potential start
-      // time
-      data_available = *comm->get_data<double>() + redist_time;
-    }
 
-    /* no transfer, control dependency */
-    if (const auto* exec = dynamic_cast<sg4::Exec*>(parent.get()))
-      data_available = exec->get_finish_time();
-
-    if (last_data_available < data_available)
-      last_data_available = data_available;
-  }
+      /* no transfer, control dependency */
+      if (const auto* parent_exec = dynamic_cast<sg4::Exec*>(parent.get()))
+        data_available = parent_exec->get_finish_time();
 
-  return std::max(sg_host_get_available_at(host), last_data_available) + task->get_remaining() / host->get_speed();
-}
+      if (last_data_available < data_available)
+        last_data_available = data_available;
+    }
 
-static sg4::Host* get_best_host(const sg4::ExecPtr exec)
-{
-  std::vector<sg4::Host*> hosts          = sg4::Engine::get_instance()->get_all_hosts();
-  auto best_host                         = hosts.front();
-  double min_EFT                         = finish_on_at(exec, best_host);
+    double finish_time = std::max(*host->get_data<double>(), last_data_available) +
+                         exec->get_remaining() / host->get_speed();
 
-  for (const auto& h : hosts) {
-    double EFT = finish_on_at(exec, h);
-    XBT_DEBUG("%s finishes on %s at %f", exec->get_cname(), h->get_cname(), EFT);
+    XBT_DEBUG("%s finishes on %s at %f", exec->get_cname(), host->get_cname(), finish_time);
 
-    if (EFT < min_EFT) {
-      min_EFT   = EFT;
-      best_host = h;
+    if (finish_time < *min_finish_time) {
+      *min_finish_time = finish_time;
+      best_host        = host;
     }
   }
+
   return best_host;
 }
 
-static void schedule_on(sg4::ExecPtr exec, sg4::Host* host)
+static void schedule_on(sg4::ExecPtr exec, sg4::Host* host, double busy_until = 0.0)
 {
   exec->set_host(host);
+  // We use the user data field to store up to when the host is busy
+  delete host->get_data<double>(); // In case we're erasing a previous value
+  host->set_data(new double(busy_until));
   // we can also set the destination of all the input comms of this exec
   for (const auto& pred : exec->get_dependencies()) {
     auto* comm = dynamic_cast<sg4::Comm*>(pred.get());
@@ -148,15 +118,12 @@ int main(int argc, char** argv)
   std::set<sg4::Activity*> vetoed;
   e.track_vetoed_activities(&vetoed);
 
-  sg4::Activity::on_completion_cb([](sg4::Activity const& activity) {
+  sg4::Exec::on_completion_cb([](sg4::Exec const& exec) {
     // when an Exec completes, we need to set the potential start time of all its ouput comms
-    const auto* exec = dynamic_cast<sg4::Exec const*>(&activity);
-    if (exec == nullptr) // Only Execs are concerned here
-      return;
-    for (const auto& succ : exec->get_successors()) {
+    for (const auto& succ : exec.get_successors()) {
       auto* comm = dynamic_cast<sg4::Comm*>(succ.get());
       if (comm != nullptr) {
-        auto* finish_time = new double(exec->get_finish_time());
+        auto* finish_time = new double(exec.get_finish_time());
         // We use the user data field to store the finish time of the predecessor of the comm, i.e., its potential start
         // time
         comm->set_data(finish_time);
@@ -166,19 +133,21 @@ int main(int argc, char** argv)
 
   e.load_platform(argv[1]);
 
-  /*  Allocating the host attribute */
-  unsigned long total_nhosts = e.get_host_count();
-  const auto hosts          = e.get_all_hosts();
-  std::vector<HostAttribute> host_attributes(total_nhosts);
-  for (unsigned long i = 0; i < total_nhosts; i++)
-    hosts[i]->set_data(&host_attributes[i]);
-
+  /* Mark all hosts as sequential, as it ought to be in such a scheduling example.
+   *
+   * It means that the hosts can only compute one thing at a given time. If an execution already takes place on a given
+   * host, any subsequently started execution will be queued until after the first execution terminates */
+  for (auto const& host : e.get_all_hosts()) {
+    host->set_concurrency_limit(1);
+    host->set_data(new double(0.0));
+  }
   /* load the DAX file */
   auto dax = sg4::create_DAG_from_DAX(argv[2]);
 
   /* Schedule the root first */
+  double root_finish_time;
   auto* root = static_cast<sg4::Exec*>(dax.front().get());
-  auto host  = get_best_host(root);
+  auto* host = get_best_host(root, &root_finish_time);
   schedule_on(root, host);
 
   e.run();
@@ -190,54 +159,40 @@ int main(int argc, char** argv)
     vetoed.clear();
 
     if (ready_tasks.empty()) {
-      /* there is no ready task, let advance the simulation */
+      /* there is no ready exec, let advance the simulation */
       e.run();
       continue;
     }
-    /* For each ready task:
+    /* For each ready exec:
      * get the host that minimizes the completion time.
-     * select the task that has the minimum completion time on its best host.
+     * select the exec that has the minimum completion time on its best host.
      */
-    double min_finish_time            = -1.0;
-    sg4::Exec* selected_task          = nullptr;
-    sg4::Host* selected_host          = nullptr;
-
-    for (auto task : ready_tasks) {
-      XBT_DEBUG("%s is ready", task->get_cname());
-      host               = get_best_host(task);
-      double finish_time = finish_on_at(task, host);
-      if (min_finish_time < 0 || finish_time < min_finish_time) {
+    double min_finish_time   = std::numeric_limits<double>::max();
+    sg4::Exec* selected_task = nullptr;
+    sg4::Host* selected_host = nullptr;
+
+    for (auto* exec : ready_tasks) {
+      XBT_DEBUG("%s is ready", exec->get_cname());
+      double finish_time;
+      host = get_best_host(exec, &finish_time);
+      if (finish_time < min_finish_time) {
         min_finish_time = finish_time;
-        selected_task   = task;
+        selected_task   = exec;
         selected_host   = host;
       }
     }
 
     XBT_INFO("Schedule %s on %s", selected_task->get_cname(), selected_host->get_cname());
-    schedule_on(selected_task, selected_host);
-
-    /*
-     * tasks can be executed concurrently when they can by default.
-     * Yet schedulers take decisions assuming that tasks wait for resource availability to start.
-     * The solution (well crude hack is to keep track of the last task scheduled on a host and add a special type of
-     * dependency if needed to force the sequential execution meant by the scheduler.
-     * If the last scheduled task is already done, has failed or is a predecessor of the current task, no need for a
-     * new dependency
-     */
-
-    if (auto last_scheduled_task = sg_host_get_last_scheduled_task(selected_host);
-        last_scheduled_task && (last_scheduled_task->get_state() != sg4::Activity::State::FINISHED) &&
-        (last_scheduled_task->get_state() != sg4::Activity::State::FAILED) &&
-        not dependency_exists(sg_host_get_last_scheduled_task(selected_host), selected_task))
-      last_scheduled_task->add_successor(selected_task);
-
-    sg_host_set_last_scheduled_task(selected_host, selected_task);
-    sg_host_set_available_at(selected_host, min_finish_time);
+    schedule_on(selected_task, selected_host, min_finish_time);
 
     ready_tasks.clear();
     e.run();
   }
 
+  /* Cleanup memory */
+  for (auto const* h : e.get_all_hosts())
+    delete h->get_data<double>();
+
   XBT_INFO("Simulation Time: %f", simgrid_get_clock());
 
   return 0;
index aae95e7..6f60e2e 100644 (file)
@@ -16,23 +16,18 @@ int main(int argc, char* argv[])
   std::set<sg4::Activity*> vetoed;
   e.track_vetoed_activities(&vetoed);
 
-  auto fafard = e.host_by_name("Fafard");
+  auto* fafard = e.host_by_name("Fafard");
 
   // Display the details on vetoed activities
-  sg4::Activity::on_veto_cb([](const sg4::Activity& a) {
-    const auto& exec = static_cast<const sg4::Exec&>(a); // all activities are execs in this example
-
-    XBT_INFO("Activity '%s' vetoed. Dependencies: %s; Ressources: %s", exec.get_cname(),
+  sg4::Exec::on_veto_cb([](sg4::Exec const& exec) {
+    XBT_INFO("Execution '%s' vetoed. Dependencies: %s; Ressources: %s", exec.get_cname(),
              (exec.dependencies_solved() ? "solved" : "NOT solved"),
              (exec.is_assigned() ? "assigned" : "NOT assigned"));
   });
 
-  sg4::Activity::on_completion_cb([](sg4::Activity const& activity) {
-    const auto* exec = dynamic_cast<sg4::Exec const*>(&activity);
-    if (exec == nullptr) // Only Execs are concerned here
-      return;
-    XBT_INFO("Activity '%s' is complete (start time: %f, finish time: %f)", exec->get_cname(), exec->get_start_time(),
-             exec->get_finish_time());
+  sg4::Exec::on_completion_cb([](sg4::Exec const& exec) {
+    XBT_INFO("Execution '%s' is complete (start time: %f, finish time: %f)", exec.get_cname(), exec.get_start_time(),
+             exec.get_finish_time());
   });
 
   // Define an amount of work that should take 1 second to execute.
index e41d10e..18b0d0b 100644 (file)
@@ -3,14 +3,14 @@
 $ ${bindir:=.}/s4u-dag-simple ${platfdir}/small_platform.xml --log=s4u_activity.t:verbose "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
 > [  0.000000] (0:maestro@) 'parent 1' is assigned to a resource and all dependencies are solved. Let's start
 > [  0.000000] (0:maestro@) 'parent 2' is assigned to a resource and all dependencies are solved. Let's start
-> [  0.000000] (0:maestro@) Activity 'child' vetoed. Dependencies: NOT solved; Ressources: NOT assigned
-> [  2.000000] (0:maestro@) Activity 'parent 1' is complete (start time: 0.000000, finish time: 2.000000)
+> [  0.000000] (0:maestro@) Execution 'child' vetoed. Dependencies: NOT solved; Ressources: NOT assigned
+> [  2.000000] (0:maestro@) Execution 'parent 1' is complete (start time: 0.000000, finish time: 2.000000)
 > [  2.000000] (0:maestro@) Remove a dependency from 'parent 1' on 'child'
 > [  2.000000] (0:maestro@) Activity child not ready.
-> [  3.000000] (0:maestro@) Activity 'parent 2' is complete (start time: 0.000000, finish time: 3.000000)
+> [  3.000000] (0:maestro@) Execution 'parent 2' is complete (start time: 0.000000, finish time: 3.000000)
 > [  3.000000] (0:maestro@) Remove a dependency from 'parent 2' on 'child'
-> [  3.000000] (0:maestro@) Activity 'child' vetoed. Dependencies: solved; Ressources: NOT assigned
+> [  3.000000] (0:maestro@) Execution 'child' vetoed. Dependencies: solved; Ressources: NOT assigned
 > [  3.000000] (0:maestro@) Activity child's dependencies are resolved. Let's assign it to Fafard.
 > [  3.000000] (0:maestro@) 'child' is assigned to a resource and all dependencies are solved. Let's start
-> [  4.000000] (0:maestro@) Activity 'child' is complete (start time: 3.000000, finish time: 4.000000)
+> [  4.000000] (0:maestro@) Execution 'child' is complete (start time: 3.000000, finish time: 4.000000)
 > [  4.000000] (0:maestro@) Simulation time 4
diff --git a/examples/cpp/dag-tuto/s4u-dag-tuto.cpp b/examples/cpp/dag-tuto/s4u-dag-tuto.cpp
new file mode 100644 (file)
index 0000000..f90c9f9
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (c) 2003-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(dag_tuto, "Messages specific for this s4u tutorial");
+
+int main(int argc, char* argv[])
+{
+  simgrid::s4u::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  simgrid::s4u::Host* tremblay = e.host_by_name("Tremblay");
+  simgrid::s4u::Host* jupiter  = e.host_by_name("Jupiter");
+
+  simgrid::s4u::ExecPtr c1 = simgrid::s4u::Exec::init();
+  simgrid::s4u::ExecPtr c2 = simgrid::s4u::Exec::init();
+  simgrid::s4u::ExecPtr c3 = simgrid::s4u::Exec::init();
+  simgrid::s4u::CommPtr t1 = simgrid::s4u::Comm::sendto_init();
+
+  c1->set_name("c1");
+  c2->set_name("c2");
+  c3->set_name("c3");
+  t1->set_name("t1");
+
+  c1->set_flops_amount(1e9);
+  c2->set_flops_amount(5e9);
+  c3->set_flops_amount(2e9);
+  t1->set_payload_size(5e8);
+
+  c1->add_successor(t1);
+  t1->add_successor(c3);
+  c2->add_successor(c3);
+
+  c1->set_host(tremblay);
+  c2->set_host(jupiter);
+  c3->set_host(jupiter);
+  t1->set_source(tremblay);
+  t1->set_destination(jupiter);
+
+  c1->start();
+  c2->start();
+
+  simgrid::s4u::Exec::on_completion_cb([](simgrid::s4u::Exec const& exec) {
+    XBT_INFO("Exec '%s' is complete (start time: %f, finish time: %f)", exec.get_cname(),
+             exec.get_start_time(), exec.get_finish_time());
+  });
+ simgrid::s4u::Comm::on_completion_cb([](simgrid::s4u::Comm const& comm) {
+    XBT_INFO("Comm '%s' is complete (start time: %f, finish time: %f)", comm.get_cname(),
+             comm.get_start_time(), comm.get_finish_time());
+  });
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/dag-tuto/s4u-dag-tuto.tesh b/examples/cpp/dag-tuto/s4u-dag-tuto.tesh
new file mode 100644 (file)
index 0000000..f5b8b15
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-dag-tuto --log=no_loc ${platfdir}/small_platform.xml
+> [10.194200] [dag_tuto/INFO] Exec 'c1' is complete (start time: 0.000000, finish time: 10.194200)
+> [65.534235] [dag_tuto/INFO] Exec 'c2' is complete (start time: 0.000000, finish time: 65.534235)
+> [85.283378] [dag_tuto/INFO] Comm 't1' is complete (start time: 10.194200, finish time: 85.283378)
+> [111.497072] [dag_tuto/INFO] Exec 'c3' is complete (start time: 85.283378, finish time: 111.497072)
\ No newline at end of file
index 926b692..4840f29 100644 (file)
@@ -6,6 +6,7 @@
 
 #ifndef _KADEMLIA_TASK_HPP_
 #define _KADEMLIA_TASK_HPP_
+#include "answer.hpp"
 #include "s4u-dht-kademlia.hpp"
 #include "simgrid/s4u.hpp"
 
index e019ddd..0ef4253 100644 (file)
@@ -141,10 +141,10 @@ static void runner()
 
   // ========= A new ptask with computation and a timeout =========
   start = sg4::Engine::get_clock();
-  std::vector<double> cpu_amounts5{flopAmount, flopAmount};
-  std::vector<double> com_amounts5{0, 0, 0, 0};
   XBT_INFO("Run a task with computation on two hosts and a timeout of 20s.");
   try {
+    std::vector<double> cpu_amounts5{flopAmount, flopAmount};
+    std::vector<double> com_amounts5{0, 0, 0, 0};
     sg4::this_actor::exec_init(hosts, cpu_amounts5, com_amounts5)->wait_for(20);
   } catch (const simgrid::TimeoutException &){
     XBT_INFO("Finished WITH timeout");
index 093f5ab..b20ad0a 100644 (file)
@@ -33,10 +33,10 @@ static void sender(std::vector<std::string> args)
     mailbox->put(payload, comm_size);
   } else {
     // Start all comms in parallel, and wait for all completions in one shot
-    std::vector<sg4::CommPtr> comms;
+    sg4::ActivitySet comms;
     for (int i = 0; i < flow_amount; i++)
-      comms.push_back(mailbox->put_async(bprintf("%d", i), comm_size));
-    sg4::Comm::wait_all(comms);
+      comms.push(mailbox->put_async(bprintf("%d", i), comm_size));
+    comms.wait_all();
   }
   XBT_INFO("sender done.");
 }
@@ -56,11 +56,11 @@ static void receiver(std::vector<std::string> args)
     std::vector<char*> data(flow_amount);
 
     // Start all comms in parallel, and wait for their completion in one shot
-    std::vector<sg4::CommPtr> comms;
+    sg4::ActivitySet comms;
     for (int i = 0; i < flow_amount; i++)
-      comms.push_back(mailbox->get_async<char>(&data[i]));
+      comms.push(mailbox->get_async<char>(&data[i]));
 
-    sg4::Comm::wait_all(comms);
+    comms.wait_all();
     for (int i = 0; i < flow_amount; i++)
       xbt_free(data[i]);
   }
index a62cfd0..08129e4 100644 (file)
@@ -14,16 +14,14 @@ static void worker()
   // Define an amount of work that should take 1 second to execute.
   double computation_amount = sg4::this_actor::get_host()->get_speed();
 
-  std::vector<sg4::ExecPtr> pending_execs;
   // Create a small DAG
   // + Two parents and a child
   // + First parent ends after 1 second and the Second parent after 2 seconds.
   sg4::ExecPtr first_parent = sg4::this_actor::exec_init(computation_amount);
-  pending_execs.push_back(first_parent);
   sg4::ExecPtr second_parent = sg4::this_actor::exec_init(2 * computation_amount);
-  pending_execs.push_back(second_parent);
   sg4::ExecPtr child = sg4::Exec::init()->set_flops_amount(computation_amount);
-  pending_execs.push_back(child);
+
+  sg4::ActivitySet pending_execs ({first_parent, second_parent, child});
 
   // Name the activities (for logging purposes only)
   first_parent->set_name("parent 1");
@@ -41,9 +39,9 @@ static void worker()
 
   // wait for the completion of all activities
   while (not pending_execs.empty()) {
-    ssize_t changed_pos = sg4::Exec::wait_any_for(pending_execs, -1);
-    XBT_INFO("Exec '%s' is complete", pending_execs[changed_pos]->get_cname());
-    pending_execs.erase(pending_execs.begin() + changed_pos);
+    auto completed_one = pending_execs.wait_any();
+    if (completed_one != nullptr)
+      XBT_INFO("Exec '%s' is complete", completed_one->get_cname());
   }
 }
 
@@ -54,9 +52,7 @@ int main(int argc, char* argv[])
 
   sg4::Actor::create("worker", e.host_by_name("Fafard"), worker);
 
-  sg4::Activity::on_veto_cb([&e](sg4::Activity& a) {
-    auto& exec = static_cast<sg4::Exec&>(a);
-
+  sg4::Exec::on_veto_cb([&e](sg4::Exec& exec) {
     // First display the situation
     XBT_INFO("Activity '%s' vetoed. Dependencies: %s; Ressources: %s", exec.get_cname(),
              (exec.dependencies_solved() ? "solved" : "NOT solved"),
index 545b4f5..4a4063b 100644 (file)
@@ -80,7 +80,7 @@ int main(int argc, char** argv)
 
   auto* zone  = sg4::create_full_zone("world");
   std::vector<sg4::Host*> hosts;
-  for (auto name : {"Host1", "Host2", "Host3"}) {
+  for (const auto* name : {"Host1", "Host2", "Host3"}) {
     auto* host = zone->create_host(name, "1f");
     hosts.push_back(host);
   }
index a8926c1..e4ec699 100644 (file)
@@ -11,7 +11,7 @@ namespace sg4 = simgrid::s4u;
 
 static void runner()
 {
-  auto e = sg4::Engine::get_instance();
+  const auto* e = sg4::Engine::get_instance();
   std::vector<double> comp(2, 1e9);
   std::vector<double> comm(4, 0.0);
   // Different hosts.
index 75f9701..e7a17cb 100644 (file)
@@ -10,7 +10,7 @@ namespace sg4 = simgrid::s4u;
 
 static void runner()
 {
-  auto e = sg4::Engine::get_instance();
+  const auto* e = sg4::Engine::get_instance();
   std::vector<double> comp(2, 1e9);
   std::vector<double> comm(4, 0.0);
   // Different hosts.
@@ -60,7 +60,7 @@ static void runner()
   XBT_INFO("Computed 2-core activity on two different hosts. Took %g s", e->get_clock() - start_time);
 
   // Add a background task and change ptask on the fly
-  auto MyHost1                          = e->host_by_name("MyHost1");
+  auto* MyHost1                         = e->host_by_name("MyHost1");
   sg4::ExecPtr background_task          = MyHost1->exec_async(5e9);
   XBT_INFO("Start a 1-core background task on the 4-core host.");
 
index 6230a14..1de40a2 100644 (file)
@@ -11,7 +11,7 @@ namespace sg4 = simgrid::s4u;
 
 static void runner()
 {
-  auto e                    = sg4::Engine::get_instance();
+  const auto* e             = sg4::Engine::get_instance();
   sg4::Host* multicore_host = e->host_by_name("MyHost1");
   // First test with less than, same number as, and more threads than cores
   double start_time = sg4::Engine::get_clock();
diff --git a/examples/cpp/exec-waitany/s4u-exec-waitany.cpp b/examples/cpp/exec-waitany/s4u-exec-waitany.cpp
deleted file mode 100644 (file)
index c30dd31..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Copyright (c) 2019-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "simgrid/s4u.hpp"
-#include <cstdlib>
-#include <iostream>
-#include <string>
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_exec_waitany, "Messages specific for this s4u example");
-namespace sg4 = simgrid::s4u;
-
-static void worker(bool with_timeout)
-{
-  /* Vector in which we store all pending executions*/
-  std::vector<sg4::ExecPtr> pending_executions;
-
-  for (int i = 0; i < 3; i++) {
-    std::string name = "Exec-" + std::to_string(i);
-    double amount    = (6 * (i % 2) + i + 1) * sg4::this_actor::get_host()->get_speed();
-
-    sg4::ExecPtr exec = sg4::this_actor::exec_init(amount)->set_name(name);
-    pending_executions.push_back(exec);
-    exec->start();
-
-    XBT_INFO("Activity %s has started for %.0f seconds", name.c_str(),
-             amount / sg4::this_actor::get_host()->get_speed());
-  }
-
-  /* Now that executions were initiated, wait for their completion, in order of termination.
-   *
-   * This loop waits for first terminating execution with wait_any() and remove it with erase(), until all execs are
-   * terminated.
-   */
-  while (not pending_executions.empty()) {
-    ssize_t pos;
-    if (with_timeout)
-      pos = sg4::Exec::wait_any_for(pending_executions, 4);
-    else
-      pos = sg4::Exec::wait_any(pending_executions);
-
-    if (pos < 0) {
-      XBT_INFO("Do not wait any longer for an activity");
-      pending_executions.clear();
-    } else {
-      XBT_INFO("Activity '%s' (at position %zd) is complete", pending_executions[pos]->get_cname(), pos);
-      pending_executions.erase(pending_executions.begin() + pos);
-    }
-    XBT_INFO("%zu activities remain pending", pending_executions.size());
-  }
-}
-
-int main(int argc, char* argv[])
-{
-  sg4::Engine e(&argc, argv);
-  e.load_platform(argv[1]);
-  sg4::Actor::create("worker", e.host_by_name("Tremblay"), worker, false);
-  sg4::Actor::create("worker_timeout", e.host_by_name("Tremblay"), worker, true);
-  e.run();
-
-  return 0;
-}
diff --git a/examples/cpp/exec-waitany/s4u-exec-waitany.tesh b/examples/cpp/exec-waitany/s4u-exec-waitany.tesh
deleted file mode 100644 (file)
index 072cab5..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env tesh
-
-! output sort 19
-$ ${bindir:=.}/s4u-exec-waitany ${platfdir}/multicore_machine.xml "--log=root.fmt:[%10.6r]%e[%14P]%e%m%n"
-> [  0.000000] [        worker] Activity Exec-0 has started for 1 seconds
-> [  0.000000] [worker_timeout] Activity Exec-0 has started for 1 seconds
-> [  0.000000] [        worker] Activity Exec-1 has started for 8 seconds
-> [  0.000000] [worker_timeout] Activity Exec-1 has started for 8 seconds
-> [  0.000000] [        worker] Activity Exec-2 has started for 3 seconds
-> [  0.000000] [worker_timeout] Activity Exec-2 has started for 3 seconds
-> [  1.000000] [worker_timeout] Activity 'Exec-0' (at position 0) is complete
-> [  1.000000] [worker_timeout] 2 activities remain pending
-> [  1.000000] [        worker] Activity 'Exec-0' (at position 0) is complete
-> [  1.000000] [        worker] 2 activities remain pending
-> [  3.000000] [worker_timeout] Activity 'Exec-2' (at position 1) is complete
-> [  3.000000] [worker_timeout] 1 activities remain pending
-> [  3.000000] [        worker] Activity 'Exec-2' (at position 1) is complete
-> [  3.000000] [        worker] 1 activities remain pending
-> [  7.000000] [worker_timeout] Do not wait any longer for an activity
-> [  7.000000] [worker_timeout] 0 activities remain pending
-> [  8.000000] [        worker] Activity 'Exec-1' (at position 0) is complete
-> [  8.000000] [        worker] 0 activities remain pending
index 8788e10..f64c4c2 100644 (file)
@@ -12,16 +12,12 @@ namespace sg4 = simgrid::s4u;
 
 static void test()
 {
-  std::vector<sg4::ActivityPtr> pending_activities;
-
   sg4::ExecPtr bob_compute = sg4::this_actor::exec_init(1e9);
-  pending_activities.push_back(boost::dynamic_pointer_cast<sg4::Activity>(bob_compute));
   sg4::IoPtr bob_write = sg4::Host::current()->get_disks().front()->io_init(4000000, sg4::Io::OpType::WRITE);
-  pending_activities.push_back(boost::dynamic_pointer_cast<sg4::Activity>(bob_write));
   sg4::IoPtr carl_read = sg4::Host::by_name("carl")->get_disks().front()->io_init(4000000, sg4::Io::OpType::READ);
-  pending_activities.push_back(boost::dynamic_pointer_cast<sg4::Activity>(carl_read));
   sg4::ExecPtr carl_compute = sg4::Host::by_name("carl")->exec_init(1e9);
-  pending_activities.push_back(boost::dynamic_pointer_cast<sg4::Activity>(carl_compute));
+
+  sg4::ActivitySet pending_activities ({bob_compute, bob_write, carl_read, carl_compute});
 
   // Name the activities (for logging purposes only)
   bob_compute->set_name("bob compute");
@@ -45,16 +41,15 @@ static void test()
 
   // wait for the completion of all activities
   while (not pending_activities.empty()) {
-    ssize_t changed_pos = sg4::Activity::wait_any(pending_activities);
-    XBT_INFO("Activity '%s' is complete", pending_activities[changed_pos]->get_cname());
-    pending_activities.erase(pending_activities.begin() + changed_pos);
+    auto completed_one = pending_activities.wait_any();
+    if (completed_one != nullptr)
+      XBT_INFO("Activity '%s' is complete", completed_one->get_cname());
   }
 }
 
 int main(int argc, char* argv[])
 {
   sg4::Engine e(&argc, argv);
-  sg_storage_file_system_init();
   e.load_platform(argv[1]);
 
   sg4::Actor::create("bob", e.host_by_name("bob"), test);
index 8f2fc22..3c50a7b 100644 (file)
@@ -43,14 +43,13 @@ static void host()
   /* - Attach some user data to disk1 */
   XBT_INFO("*** Get/set data for storage element: Disk1 ***");
 
-  const auto* data = disk->get_data<std::string>();
+  auto data = disk->get_unique_data<std::string>();
 
   XBT_INFO("Get storage data: '%s'", data ? data->c_str() : "No user data");
 
   disk->set_data(new std::string("Some user data"));
-  data = disk->get_data<std::string>();
+  data = disk->get_unique_data<std::string>();
   XBT_INFO("Set and get data: '%s'", data->c_str());
-  delete data;
 }
 
 int main(int argc, char** argv)
index ef57282..40e0048 100644 (file)
@@ -58,9 +58,8 @@ public:
 
     // Test attaching some user data to the file
     file->set_data(new std::string("777"));
-    const auto* file_data = file->get_data<std::string>();
+    auto file_data = file->get_unique_data<std::string>();
     XBT_INFO("User data attached to the file: %s", file_data->c_str());
-    delete file_data;
 
     // Close the file
     file->close();
index f55da7f..8b92c0b 100644 (file)
@@ -77,7 +77,7 @@ int main(int argc, char* argv[])
   /* Become one of the simulated actors (must be done after the platform creation, or the host won't exist). */
   sg_actor_attach("sender", nullptr, e.host_by_name("Tremblay"), nullptr);
 
-  ensure_root_tid(); // Only useful in this test: we ensure that simgrid is not broken and that this code is executed in
+  ensure_root_tid(); // Only useful in this test: we ensure that SimGrid is not broken and that this code is executed in
                      // the correct system thread
 
   // Execute the sender code. The root thread was actually turned into a regular actor
diff --git a/examples/cpp/mc-bugged1-liveness/promela_bugged1_liveness b/examples/cpp/mc-bugged1-liveness/promela_bugged1_liveness
deleted file mode 100644 (file)
index 96b491d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-never { /* !G(r->Fcs) */
-T0_init :    /* init */
-       if
-       :: (1) -> goto T0_init
-       :: (!cs && r) -> goto accept_S2
-       fi;
-accept_S2 :    /* 1 */
-       if
-       :: (!cs) -> goto accept_S2
-       fi;
-}
diff --git a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner b/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner
deleted file mode 100755 (executable)
index 0552ca2..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env sh
-# Run the same test compiled with -fstack-cleaner / f-no-stack-cleaner
-# and compare the output.
-
-srcdir="$1"
-bindir="$2"
-
-cd "$srcdir"
-
-die() {
-  echo "$@" >&2
-  exit 1
-}
-
-assert() {
-  if ! eval "$1"; then
-    die "Assertion failed: $*"
-  fi
-}
-
-# If we don't have timeout, fake it:
-if ! which timeout > /dev/null; then
-  timeout() {
-    shift
-    "$@"
-  }
-fi
-
-run() {
-  state=$1
-  shift
-  timeout 30s ${bindir:=.}/bugged1_liveness_cleaner_$state \
-    ${srcdir:=.}/../../platforms/platform.xml \
-    ${srcdir:=.}/deploy_bugged1_liveness.xml \
-    "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" \
-    --cfg=contexts/factory:ucontext \
-    --cfg=contexts/stack-size:256
-  assert 'test $? = 134'
-}
-
-get_states() {
-  echo "$1" | grep "Expanded pairs = " | sed "s/^.*Expanded pairs = //" | head -n1
-}
-
-RES_ON="$(run on 2>&1 1>/dev/null)"
-RES_OFF="$(run off 2>&1 1>/dev/null)"
-
-STATES_ON=$(get_states "$RES_ON")
-STATES_OFF=$(get_states "$RES_OFF")
-
-# Both runs finished:
-assert 'test -n "$STATES_ON"'
-assert 'test -n "$STATES_OFF"'
-
-# We expect 21 visited pairs with the stack cleaner:
-assert 'test "$STATES_ON" = 21'
-
-# We expect more states without the stack cleaner:
-assert 'test "$STATES_ON" -lt "$STATES_OFF"'
diff --git a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh b/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh
deleted file mode 100644 (file)
index cffdd1c..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env tesh
-
-! expect return 2
-! timeout 30
-! output display
-$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true ${bindir:=.}/s4u-mc-bugged1-liveness ${platfdir:=.}/small_platform.xml 1 --log=xbt_cfg.thresh:warning "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=model-check/visited:100 --cfg=contexts/stack-size:256  --cfg=model-check/property:promela_bugged1_liveness
-> [  0.000000] (0:maestro@) Check the liveness property promela_bugged1_liveness
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (3:client@Fafard) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. resource now idle
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. resource now idle
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. resource now idle
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. resource now idle
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (1:coordinator@Tremblay) CS already used. Queue the request.
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1)
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. resource now idle
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (1:coordinator@Tremblay) CS already used. Queue the request.
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1)
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. resource now idle
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (1:coordinator@Tremblay) CS already used. Queue the request.
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1)
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. resource now idle
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (1:coordinator@Tremblay) CS already used. Queue the request.
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1)
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (3:client@Fafard) Propositions changed : r=1, cs=0
-> [  0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1)
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (0:maestro@) Pair 58 already reached (equal to pair 46) !
-> [  0.000000] (0:maestro@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
-> [  0.000000] (0:maestro@) |             ACCEPTANCE CYCLE            |
-> [  0.000000] (0:maestro@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
-> [  0.000000] (0:maestro@) Counter-example that violates formula :
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) Expanded pairs = 58
-> [  0.000000] (0:maestro@) Visited pairs = 202
-> [  0.000000] (0:maestro@) Executed transitions = 208
-> [  0.000000] (0:maestro@) Counter-example depth : 51
diff --git a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp b/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp
deleted file mode 100644 (file)
index ad4d30a..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Copyright (c) 2012-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/***************** Centralized Mutual Exclusion Algorithm *******************/
-/* This example implements a centralized mutual exclusion algorithm.        */
-/* Bug : CS requests of client 1 not satisfied                              */
-/* LTL property checked : G(r->F(cs)); (r=request of CS, cs=CS ok)          */
-/****************************************************************************/
-
-#ifdef GARBAGE_STACK
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
-#include <simgrid/modelchecker.h>
-#include <simgrid/s4u.hpp>
-#include <xbt/dynar.h>
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(bugged1_liveness, "my log messages");
-namespace sg4 = simgrid::s4u;
-
-class Message {
-public:
-  enum class Kind { GRANT, REQUEST, RELEASE };
-  Kind kind                             = Kind::GRANT;
-  sg4::Mailbox* return_mailbox          = nullptr;
-  explicit Message(Message::Kind kind, sg4::Mailbox* mbox) : kind(kind), return_mailbox(mbox) {}
-};
-
-int r  = 0;
-int cs = 0;
-
-#ifdef GARBAGE_STACK
-/** Do not use a clean stack */
-static void garbage_stack(void)
-{
-  const size_t size = 256;
-  int fd            = open("/dev/urandom", O_RDONLY);
-  char foo[size];
-  read(fd, foo, size);
-  close(fd);
-}
-#endif
-
-static void coordinator()
-{
-  bool CS_used = false;
-  std::queue<sg4::Mailbox*> requests;
-
-  sg4::Mailbox* mbox = sg4::Mailbox::by_name("coordinator");
-
-  while (true) {
-    auto m = mbox->get_unique<Message>();
-    if (m->kind == Message::Kind::REQUEST) {
-      if (CS_used) {
-        XBT_INFO("CS already used. Queue the request.");
-        requests.push(m->return_mailbox);
-      } else {
-        if (m->return_mailbox->get_name() != "1") {
-          XBT_INFO("CS idle. Grant immediately");
-          m->return_mailbox->put(new Message(Message::Kind::GRANT, mbox), 1000);
-          CS_used = true;
-        }
-      }
-    } else {
-      if (not requests.empty()) {
-        XBT_INFO("CS release. Grant to queued requests (queue size: %zu)", requests.size());
-        sg4::Mailbox* req = requests.front();
-        requests.pop();
-        if (req->get_name() != "1") {
-          req->put(new Message(Message::Kind::GRANT, mbox), 1000);
-        } else {
-          requests.push(req);
-          CS_used = false;
-        }
-      } else {
-        XBT_INFO("CS release. resource now idle");
-        CS_used = false;
-      }
-    }
-  }
-}
-
-static void client(int id)
-{
-  aid_t my_pid = sg4::this_actor::get_pid();
-
-  sg4::Mailbox* my_mailbox = sg4::Mailbox::by_name(std::to_string(id));
-
-  while (true) {
-    XBT_INFO("Ask the request");
-    sg4::Mailbox::by_name("coordinator")->put(new Message(Message::Kind::REQUEST, my_mailbox), 1000);
-
-    if (id == 1) {
-      r  = 1;
-      cs = 0;
-      XBT_INFO("Propositions changed : r=1, cs=0");
-    }
-
-    auto grant = my_mailbox->get_unique<Message>();
-    xbt_assert(grant->kind == Message::Kind::GRANT);
-
-    if (id == 1) {
-      cs = 1;
-      r  = 0;
-      XBT_INFO("Propositions changed : r=0, cs=1");
-    }
-
-    XBT_INFO("%d got the answer. Sleep a bit and release it", id);
-
-    sg4::this_actor::sleep_for(1);
-
-    sg4::Mailbox::by_name("coordinator")->put(new Message(Message::Kind::RELEASE, my_mailbox), 1000);
-
-    sg4::this_actor::sleep_for(static_cast<double>(my_pid));
-
-    if (id == 1) {
-      cs = 0;
-      r  = 0;
-      XBT_INFO("Propositions changed : r=0, cs=0");
-    }
-  }
-}
-
-static void raw_client(int id)
-{
-#ifdef GARBAGE_STACK
-  // At this point the stack of the callee (client) is probably filled with
-  // zeros and uninitialized variables will contain 0. This call will place
-  // random byes in the stack of the callee:
-  garbage_stack();
-#endif
-  client(id);
-}
-
-int main(int argc, char* argv[])
-{
-  sg4::Engine e(&argc, argv);
-
-  MC_automaton_new_propositional_symbol_pointer("r", &r);
-  MC_automaton_new_propositional_symbol_pointer("cs", &cs);
-
-  e.load_platform(argv[1]);
-
-  sg4::Actor::create("coordinator", e.host_by_name("Tremblay"), coordinator)
-      ->set_kill_time(argc > 3 ? std::stod(argv[3]) : -1.0);
-  if (std::stod(argv[2]) == 0) {
-    sg4::Actor::create("client", e.host_by_name("Boivin"), raw_client, 1);
-    sg4::Actor::create("client", e.host_by_name("Fafard"), raw_client, 2);
-  } else { // "Visited" case
-    sg4::Actor::create("client", e.host_by_name("Boivin"), raw_client, 2);
-    sg4::Actor::create("client", e.host_by_name("Fafard"), raw_client, 1);
-  }
-  e.run();
-
-  return 0;
-}
diff --git a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh b/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh
deleted file mode 100644 (file)
index 14da430..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env tesh
-
-! expect return 2
-! timeout 20
-! output display
-$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true ${bindir:=.}/s4u-mc-bugged1-liveness ${platfdir:=.}/small_platform.xml 0 --log=xbt_cfg.thresh:warning "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=contexts/stack-size:256 --cfg=model-check/property:promela_bugged1_liveness
-> [  0.000000] (0:maestro@) Check the liveness property promela_bugged1_liveness
-> [  0.000000] (2:client@Boivin) Ask the request
-> [  0.000000] (3:client@Fafard) Ask the request
-> [  0.000000] (2:client@Boivin) Propositions changed : r=1, cs=0
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (3:client@Fafard) 2 got the answer. Sleep a bit and release it
-> [  0.000000] (1:coordinator@Tremblay) CS release. resource now idle
-> [  0.000000] (3:client@Fafard) Ask the request
-> [  0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately
-> [  0.000000] (0:maestro@) Pair 22 already reached (equal to pair 10) !
-> [  0.000000] (0:maestro@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
-> [  0.000000] (0:maestro@) |             ACCEPTANCE CYCLE            |
-> [  0.000000] (0:maestro@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
-> [  0.000000] (0:maestro@) Counter-example that violates formula :
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] iRecv(dst=(3)Fafard (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (3)Fafard (client)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (3)Fafard (client)])
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only))
-> [  0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [  0.000000] (0:maestro@) Expanded pairs = 22
-> [  0.000000] (0:maestro@) Visited pairs = 20
-> [  0.000000] (0:maestro@) Executed transitions = 20
-> [  0.000000] (0:maestro@) Counter-example depth : 21
index adbd452..022c225 100644 (file)
@@ -2,78 +2,28 @@
 
 ! expect return 1
 ! timeout 20
-$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-bugged1 ${platfdir:=.}/model_checker_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning --cfg=contexts/stack-size:256
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-bugged1 ${platfdir:=.}/model_checker_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning --cfg=contexts/stack-size:256
 > [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (2:client@HostB) Sent!
 > [  0.000000] (3:client@HostC) Sent!
 > [  0.000000] (1:server@HostA) OK
 > [  0.000000] (4:client@HostD) Sent!
 > [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (1:server@HostA) OK
 > [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (4:client@HostD) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (2:client@HostB) Sent!
-> [  0.000000] (3:client@HostC) Sent!
-> [  0.000000] (1:server@HostA) OK
-> [  0.000000] (4:client@HostD) Sent!
 > [  0.000000] (2:client@HostB) Sent!
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) *** PROPERTY NOT VALID ***
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) Counter-example execution trace:
-> [  0.000000] (0:maestro@)   1: iRecv(mbox=0)
-> [  0.000000] (0:maestro@)   2: iSend(mbox=0)
-> [  0.000000] (0:maestro@)   1: WaitComm(from 2 to 1, mbox=0, no timeout)
-> [  0.000000] (0:maestro@)   1: iRecv(mbox=0)
-> [  0.000000] (0:maestro@)   2: WaitComm(from 2 to 1, mbox=0, no timeout)
-> [  0.000000] (0:maestro@)   4: iSend(mbox=0)
-> [  0.000000] (0:maestro@)   1: WaitComm(from 4 to 1, mbox=0, no timeout)
-> [  0.000000] (0:maestro@)   1: iRecv(mbox=0)
-> [  0.000000] (0:maestro@)   3: iSend(mbox=0)
-> [  0.000000] (0:maestro@)   1: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 2 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 2 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 2 in Wait ==> simcall: WaitComm(from 2 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 4 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 4 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
 > [  0.000000] (0:maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;2;1;1;2;4;1;1;3;1'
-> [  0.000000] (0:maestro@) DFS exploration ended. 59 unique states visited; 14 backtracks (192 transition replays, 119 states visited overall)
\ No newline at end of file
+> [  0.000000] (0:maestro@) DFS exploration ended. 19 unique states visited; 2 backtracks (12 transition replays, 33 states visited overall)
diff --git a/examples/cpp/mc-bugged2-liveness/promela_bugged2_liveness b/examples/cpp/mc-bugged2-liveness/promela_bugged2_liveness
deleted file mode 100644 (file)
index 5361f88..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-never { /* !(!(GFcs)) */
-T0_init :    /* init */
-       if
-       :: (cs) -> goto accept_S1
-       :: (1) -> goto T0_init
-       fi;
-accept_S1 :    /* 1 */
-       if
-       :: (cs) -> goto accept_S1
-       :: (1) -> goto T0_init
-       fi;
-}
diff --git a/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.cpp b/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.cpp
deleted file mode 100644 (file)
index fcc6878..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Copyright (c) 2012-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/***************************** Bugged2 ****************************************/
-/* This example implements a centralized mutual exclusion algorithm.          */
-/* One client stay always in critical section                                 */
-/* LTL property checked : !(GFcs)                                             */
-/******************************************************************************/
-
-#include <simgrid/modelchecker.h>
-#include <simgrid/s4u.hpp>
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(bugged2_liveness, "my log messages");
-namespace sg4 = simgrid::s4u;
-
-class Message {
-public:
-  enum class Kind { GRANT, NOT_GRANT, REQUEST };
-  Kind kind                             = Kind::GRANT;
-  sg4::Mailbox* return_mailbox          = nullptr;
-  explicit Message(Message::Kind kind, sg4::Mailbox* mbox) : kind(kind), return_mailbox(mbox) {}
-};
-
-int cs = 0;
-
-static void coordinator()
-{
-  bool CS_used = false; // initially the CS is idle
-  std::queue<sg4::Mailbox*> requests;
-
-  sg4::Mailbox* mbox = sg4::Mailbox::by_name("coordinator");
-
-  while (true) {
-    auto m = mbox->get_unique<Message>();
-    if (m->kind == Message::Kind::REQUEST) {
-      if (CS_used) {
-        XBT_INFO("CS already used.");
-        m->return_mailbox->put(new Message(Message::Kind::NOT_GRANT, mbox), 1000);
-      } else { // can serve it immediately
-        XBT_INFO("CS idle. Grant immediately");
-        m->return_mailbox->put(new Message(Message::Kind::GRANT, mbox), 1000);
-        CS_used = true;
-      }
-    } else { // that's a release. Check if someone was waiting for the lock
-      XBT_INFO("CS release. resource now idle");
-      CS_used = false;
-    }
-  }
-}
-
-static void client(int id)
-{
-  aid_t my_pid = sg4::this_actor::get_pid();
-
-  sg4::Mailbox* my_mailbox = sg4::Mailbox::by_name(std::to_string(id));
-
-  while (true) {
-    XBT_INFO("Client (%d) asks the request", id);
-    sg4::Mailbox::by_name("coordinator")->put(new Message(Message::Kind::REQUEST, my_mailbox), 1000);
-
-    auto grant = my_mailbox->get_unique<Message>();
-
-    if (grant->kind == Message::Kind::GRANT) {
-      XBT_INFO("Client (%d) got the answer (grant). Sleep a bit and release it", id);
-      if (id == 1)
-        cs = 1;
-    } else {
-      XBT_INFO("Client (%d) got the answer (not grant). Try again", id);
-    }
-
-    sg4::this_actor::sleep_for(my_pid);
-  }
-}
-
-int main(int argc, char* argv[])
-{
-  sg4::Engine e(&argc, argv);
-
-  MC_automaton_new_propositional_symbol_pointer("cs", &cs);
-
-  e.load_platform(argv[1]);
-
-  sg4::Actor::create("coordinator", e.host_by_name("Tremblay"), coordinator);
-  sg4::Actor::create("client", e.host_by_name("Fafard"), client, 1);
-  sg4::Actor::create("client", e.host_by_name("Boivin"), client, 2);
-
-  e.run();
-
-  return 0;
-}
diff --git a/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.tesh b/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.tesh
deleted file mode 100644 (file)
index a48a2ab..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env tesh
-
-! expect return 2
-! timeout 20
-! output ignore
-$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-bugged2-liveness ${platfdir:=.}/small_platform.xml --log=xbt_cfg.thresh:warning "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=contexts/stack-size:256 --cfg=model-check/property:promela_bugged2_liveness
index a104fb8..83991da 100644 (file)
@@ -2,18 +2,55 @@
 
 ! expect return 1
 ! timeout 20
-$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true ${bindir:=.}/s4u-mc-bugged2 ${platfdir:=.}/model_checker_platform.xml  --log=root.thresh:critical --log=mc.thresh:info
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-bugged2 ${platfdir:=.}/model_checker_platform.xml  --log=root.thresh:critical --log=mc.thresh:info
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > [0.000000] [mc_explo/INFO] **************************
 > [0.000000] [mc_explo/INFO] *** PROPERTY NOT VALID ***
 > [0.000000] [mc_explo/INFO] **************************
 > [0.000000] [mc_explo/INFO] Counter-example execution trace:
-> [0.000000] [mc_explo/INFO]   1: iRecv(mbox=0)
-> [0.000000] [mc_explo/INFO]   3: iSend(mbox=0)
-> [0.000000] [mc_explo/INFO]   1: WaitComm(from 3 to 1, mbox=0, no timeout)
-> [0.000000] [mc_explo/INFO]   1: iRecv(mbox=0)
-> [0.000000] [mc_explo/INFO]   3: WaitComm(from 3 to 1, mbox=0, no timeout)
-> [0.000000] [mc_explo/INFO]   3: iSend(mbox=0)
-> [0.000000] [mc_explo/INFO]   1: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
 > [0.000000] [mc_explo/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;1;1;3;3;1'
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 2091 unique states visited; 529 backtracks (8359 transition replays, 5739 states visited overall)
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 98 unique states visited; 21 backtracks (153 transition replays, 272 states visited overall)
+
+! expect return 1
+! timeout 20
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/strategy:min_match_comm ${bindir:=.}/s4u-mc-bugged2 ${platfdir:=.}/model_checker_platform.xml  --log=root.thresh:critical --log=mc.thresh:info
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
+> [0.000000] [mc_explo/INFO] **************************
+> [0.000000] [mc_explo/INFO] *** PROPERTY NOT VALID ***
+> [0.000000] [mc_explo/INFO] **************************
+> [0.000000] [mc_explo/INFO] Counter-example execution trace:
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 2 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;1;1;3;3;2;1'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 83 unique states visited; 12 backtracks (65 transition replays, 160 states visited overall)
+
+! expect return 1
+! timeout 20
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/strategy:max_match_comm ${bindir:=.}/s4u-mc-bugged2 ${platfdir:=.}/model_checker_platform.xml  --log=root.thresh:critical --log=mc.thresh:info
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
+> [0.000000] [mc_explo/INFO] **************************
+> [0.000000] [mc_explo/INFO] *** PROPERTY NOT VALID ***
+> [0.000000] [mc_explo/INFO] **************************
+> [0.000000] [mc_explo/INFO] Counter-example execution trace:
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;1;3;1;3;1'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 44 unique states visited; 3 backtracks (11 transition replays, 58 states visited overall)
index ba390d6..8516a98 100644 (file)
@@ -1,6 +1,6 @@
 #!/usr/bin/env tesh
 
-$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-electric-fence ${platfdir}/model_checker_platform.xml
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-electric-fence ${platfdir}/model_checker_platform.xml
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
 > [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
@@ -9,84 +9,6 @@ $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-electric-fence ${plat
 > [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
 > [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
 > [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
 > [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
 > [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostC:client:(3) 0.000000] [electric_fence/INFO] Sent!
-> [HostA:server:(1) 0.000000] [electric_fence/INFO] OK
-> [HostB:client:(2) 0.000000] [electric_fence/INFO] Sent!
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 169 unique states visited; 29 backtracks (261 transition replays, 64 states visited overall)
\ No newline at end of file
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 26 unique states visited; 6 backtracks (8 transition replays, 40 states visited overall)
index c0d8fc0..0a7b170 100644 (file)
@@ -2,19 +2,59 @@
 
 ! 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
+$ $VALGRIND_NO_TRACE_CHILDREN ${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_explo/INFO] **************************
 > [0.000000] [mc_explo/INFO] *** PROPERTY NOT VALID ***
 > [0.000000] [mc_explo/INFO] **************************
 > [0.000000] [mc_explo/INFO] Counter-example execution trace:
-> [0.000000] [mc_explo/INFO]   1: iRecv(mbox=0)
-> [0.000000] [mc_explo/INFO]   3: iSend(mbox=0)
-> [0.000000] [mc_explo/INFO]   1: WaitComm(from 3 to 1, mbox=0, no timeout)
-> [0.000000] [mc_explo/INFO]   1: iRecv(mbox=0)
-> [0.000000] [mc_explo/INFO]   2: iSend(mbox=0)
-> [0.000000] [mc_explo/INFO]   1: WaitComm(from 2 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 2 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 2 to 1, mbox=0, no timeout)
 > [0.000000] [mc_explo/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'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)
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 24 unique states visited; 8 backtracks (26 transition replays, 58 states visited overall)
 
+! expect return 1
+! timeout 300
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/reduction:none --cfg=model-check/strategy:max_match_comm -- ${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] [xbt_cfg/INFO] Configuration change: Set 'model-check/strategy' to 'max_match_comm'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: none.
+> [0.000000] [mc_explo/INFO] **************************
+> [0.000000] [mc_explo/INFO] *** PROPERTY NOT VALID ***
+> [0.000000] [mc_explo/INFO] **************************
+> [0.000000] [mc_explo/INFO] Counter-example execution trace:
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 2 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 2 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;1;3;1;2;1'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 14 unique states visited; 1 backtracks (1 transition replays, 16 states visited overall)
+
+
+! expect return 1
+! timeout 300
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/reduction:none --cfg=model-check/strategy:min_match_comm -- ${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] [xbt_cfg/INFO] Configuration change: Set 'model-check/strategy' to 'min_match_comm'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: none.
+> [0.000000] [mc_explo/INFO] **************************
+> [0.000000] [mc_explo/INFO] *** PROPERTY NOT VALID ***
+> [0.000000] [mc_explo/INFO] **************************
+> [0.000000] [mc_explo/INFO] Counter-example execution trace:
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 2 in Isend ==> simcall: iSend(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 3 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [0.000000] [mc_explo/INFO]   Actor 1 in Wait ==> simcall: WaitComm(from 2 to 1, mbox=0, no timeout)
+> [0.000000] [mc_explo/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;2;1;3;1;1'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 29 unique states visited; 10 backtracks (26 transition replays, 65 states visited overall)
\ No newline at end of file
diff --git a/examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh b/examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh
deleted file mode 100644 (file)
index 97c8085..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/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 6d4d6e5..1d5166e 100644 (file)
@@ -2,30 +2,65 @@
 
 ! expect return 1
 ! timeout 20
-$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true ${bindir:=.}/s4u-mc-failing-assert ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-failing-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] (2:client1@Bourassa) Sent!
 > [  0.000000] (1:server@Boivin) OK
 > [  0.000000] (3:client2@Fafard) Sent!
-> [  0.000000] (1:server@Boivin) OK
-> [  0.000000] (3:client2@Fafard) Sent!
+> [  0.000000] (2:client1@Bourassa) Sent!
+> [  0.000000] (0:maestro@) **************************
+> [  0.000000] (0:maestro@) *** PROPERTY NOT VALID ***
+> [  0.000000] (0:maestro@) **************************
+> [  0.000000] (0:maestro@) Counter-example execution trace:
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 2 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 2 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;1;1;2;1'
+> [  0.000000] (0:maestro@) DFS exploration ended. 15 unique states visited; 2 backtracks (4 transition replays, 21 states visited overall)
+
+! expect return 1
+! timeout 20
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/strategy:min_match_comm ${bindir:=.}/s4u-mc-failing-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] (2:client1@Bourassa) Sent!
 > [  0.000000] (1:server@Boivin) OK
 > [  0.000000] (3:client2@Fafard) Sent!
+> [  0.000000] (3:client2@Fafard) Sent!
+> [  0.000000] (0:maestro@) **************************
+> [  0.000000] (0:maestro@) *** PROPERTY NOT VALID ***
+> [  0.000000] (0:maestro@) **************************
+> [  0.000000] (0:maestro@) Counter-example execution trace:
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 2 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 3 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 2 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;2;1;3;1;1'
+> [  0.000000] (0:maestro@) DFS exploration ended. 18 unique states visited; 3 backtracks (1 transition replays, 22 states visited overall)
+
+! expect return 1
+! timeout 20
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/strategy:max_match_comm ${bindir:=.}/s4u-mc-failing-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] (2:client1@Bourassa) Sent!
 > [  0.000000] (1:server@Boivin) OK
 > [  0.000000] (3:client2@Fafard) Sent!
-> [  0.000000] (1:server@Boivin) OK
 > [  0.000000] (3:client2@Fafard) Sent!
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) *** PROPERTY NOT VALID ***
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) Counter-example execution trace:
-> [  0.000000] (0:maestro@)   1: iRecv(mbox=0)
-> [  0.000000] (0:maestro@)   3: iSend(mbox=0)
-> [  0.000000] (0:maestro@)   1: WaitComm(from 3 to 1, mbox=0, no timeout)
-> [  0.000000] (0:maestro@)   1: iRecv(mbox=0)
-> [  0.000000] (0:maestro@)   2: iSend(mbox=0)
-> [  0.000000] (0:maestro@)   1: WaitComm(from 2 to 1, mbox=0, no timeout)
-> [  0.000000] (0:maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;1;1;2;1'
-> [  0.000000] (0:maestro@) DFS exploration ended. 29 unique states visited; 5 backtracks (49 transition replays, 15 states visited overall)
\ No newline at end of file
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 3 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 3 in Wait ==> simcall: WaitComm(from 3 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@)   Actor 1 in Irecv ==> simcall: iRecv(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 2 in Isend ==> simcall: iSend(mbox=0)
+> [  0.000000] (0:maestro@)   Actor 1 in Wait ==> simcall: WaitComm(from 2 to 1, mbox=0, no timeout)
+> [  0.000000] (0:maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;3;1;3;1;2;1'
+> [  0.000000] (0:maestro@) DFS exploration ended. 14 unique states visited; 1 backtracks (1 transition replays, 16 states visited overall)
\ No newline at end of file
diff --git a/examples/cpp/mess-wait/s4u-mess-wait.cpp b/examples/cpp/mess-wait/s4u-mess-wait.cpp
new file mode 100644 (file)
index 0000000..086dc47
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example shows how to use simgrid::s4u::this_actor::wait() to wait for a given communication.
+ *
+ * As for the other asynchronous examples, the sender initiate all the messages it wants to send and
+ * pack the resulting simgrid::s4u::CommPtr objects in a vector. All messages thus occurs concurrently.
+ *
+ * The sender then loops until there is no ongoing communication.
+ */
+
+#include "simgrid/s4u.hpp"
+#include <cstdlib>
+#include <iostream>
+#include <string>
+namespace sg4 = simgrid::s4u;
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_mess_wait, "Messages specific for this s4u example");
+
+static void sender(int messages_count)
+{
+  sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("control");
+
+  sg4::this_actor::sleep_for(0.5);
+
+  for (int i = 0; i < messages_count; i++) {
+    std::string msg_content = "Message " + std::to_string(i);
+    // Copy the data we send: the 'msg_content' variable is not a stable storage location.
+    // It will be destroyed when this actor leaves the loop, ie before the receiver gets the data
+    auto* payload = new std::string(msg_content);
+
+    /* Create a control message and put it in the message queue */
+    sg4::MessPtr mess = mqueue->put_async(payload);
+    XBT_INFO("Send '%s' to '%s'", msg_content.c_str(), mqueue->get_cname());
+    mess->wait();
+  }
+
+  /* Send message to let the receiver know that it should stop */
+  XBT_INFO("Send 'finalize' to 'receiver'");
+  mqueue->put(new std::string("finalize"));
+}
+
+/* Receiver actor expects 1 argument: its ID */
+static void receiver()
+{
+  sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("control");
+
+  sg4::this_actor::sleep_for(1);
+
+  XBT_INFO("Wait for my first message");
+  for (bool cont = true; cont;) {
+    std::string* received;
+    sg4::MessPtr mess = mqueue->get_async<std::string>(&received);
+
+    sg4::this_actor::sleep_for(0.1);
+    mess->wait();
+
+    XBT_INFO("I got a '%s'.", received->c_str());
+    if (*received == "finalize")
+      cont = false; // If it's a finalize message, we're done.
+    delete received;
+  }
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+
+  e.load_platform(argv[1]);
+
+  sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender, 3);
+  sg4::Actor::create("receiver", e.host_by_name("Fafard"), receiver);
+
+  e.run();
+
+  return 0;
+}
diff --git a/examples/cpp/mess-wait/s4u-mess-wait.tesh b/examples/cpp/mess-wait/s4u-mess-wait.tesh
new file mode 100644 (file)
index 0000000..fe7bcee
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-mess-wait ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
+> [  0.500000] (1:sender@Tremblay) Send 'Message 0' to 'control'
+> [  1.000000] (2:receiver@Fafard) Wait for my first message
+> [  1.000000] (1:sender@Tremblay) Send 'Message 1' to 'control'
+> [  1.100000] (2:receiver@Fafard) I got a 'Message 0'.
+> [  1.100000] (1:sender@Tremblay) Send 'Message 2' to 'control'
+> [  1.200000] (2:receiver@Fafard) I got a 'Message 1'.
+> [  1.200000] (1:sender@Tremblay) Send 'finalize' to 'receiver'
+> [  1.300000] (2:receiver@Fafard) I got a 'Message 2'.
+> [  1.400000] (2:receiver@Fafard) I got a 'finalize'.
\ No newline at end of file
index 9721efa..83b9cf2 100644 (file)
@@ -71,15 +71,15 @@ static void load_platform()
   for (int id = 0; id < 32; id++) {
     std::string hostname = prefix + std::to_string(id) + suffix;
     /* create host */
-    const sg4::Host* host = root->create_host(hostname, 1)->set_core_count(32)->seal();
+    const sg4::Host* host = root->create_host(hostname, 1)->set_core_count(32);
     /* create UP/DOWN link */
-    const sg4::Link* l = root->create_split_duplex_link(hostname, BW_REMOTE)->set_latency(LATENCY)->seal();
+    const sg4::Link* l = root->create_split_duplex_link(hostname, BW_REMOTE)->set_latency(LATENCY);
 
     /* add link UP/DOWN for communications from the host */
-    root->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, {{l, sg4::LinkInRoute::Direction::UP}}, true);
+    root->add_route(host, nullptr, {{l, sg4::LinkInRoute::Direction::UP}}, true);
 
-    const sg4::Link* loopback = root->create_link(hostname + "_loopback", BW_LOCAL)->set_latency(LATENCY)->seal();
-    root->add_route(host->get_netpoint(), host->get_netpoint(), nullptr, nullptr, {sg4::LinkInRoute(loopback)});
+    sg4::Link* loopback = root->create_link(hostname + "_loopback", BW_LOCAL)->set_latency(LATENCY);
+    root->add_route(host, host, {loopback});
   }
 
   root->seal();
@@ -183,7 +183,7 @@ public:
         }
 
         /* Create a communication representing the ongoing communication */
-        auto mbox     = sg4::Mailbox::by_name(host->get_name());
+        auto* mbox    = sg4::Mailbox::by_name(host->get_name());
         auto* payload = new std::string(msg);
         mbox->put(payload, static_cast<uint64_t>(size));
       }
@@ -192,7 +192,7 @@ public:
     XBT_INFO("Done dispatching all messages");
     /* sending message to stop receivers */
     for (const auto* host : hosts_) {
-      auto mbox = sg4::Mailbox::by_name(host->get_name());
+      auto* mbox = sg4::Mailbox::by_name(host->get_name());
       mbox->put(new std::string("finalize"), 0);
     }
   }
@@ -203,7 +203,7 @@ class Receiver {
 public:
   void operator()() const
   {
-    auto mbox = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
+    auto* mbox = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
     // Receiving the message was all we were supposed to do
     for (bool cont = true; cont;) {
       auto received = mbox->get_unique<std::string>();
index 6384e76..d109be7 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <simgrid/s4u.hpp>
+#include <string>
 
 namespace sg4 = simgrid::s4u;
 
@@ -23,10 +24,10 @@ public:
   void operator()() const
   {
     // sphinx-doc: init-begin (this line helps the doc to build; ignore it)
-    /* Vector in which we store all ongoing communications */
-    std::vector<sg4::CommPtr> pending_comms;
+    /* ActivitySet in which we store all ongoing communications */
+    sg4::ActivitySet pending_comms;
 
-    /* Make a vector of the mailboxes to use */
+    /* Mailbox to use */
     sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver");
     // sphinx-doc: init-end
 
@@ -41,13 +42,13 @@ public:
 
       /* Create a communication representing the ongoing communication, and store it in pending_comms */
       sg4::CommPtr comm = mbox->put_async(payload, size);
-      pending_comms.push_back(comm);
+      pending_comms.push(comm);
     }
 
     XBT_INFO("Done dispatching all messages");
 
     /* Now that all message exchanges were initiated, wait for their completion in one single call */
-    sg4::Comm::wait_all(pending_comms);
+    pending_comms.wait_all();
     // sphinx-doc: put-end
 
     XBT_INFO("Goodbye now!");
@@ -63,23 +64,28 @@ public:
   explicit Receiver(int count) : messages_count(count) { mbox = sg4::Mailbox::by_name("receiver"); }
   void operator()()
   {
-    /* Vector in which we store all incoming msgs */
-    std::vector<std::unique_ptr<std::string*>> pending_msgs;
-    std::vector<sg4::CommPtr> pending_comms;
+    /* Where we store all incoming msgs */
+    std::unordered_map<sg4::CommPtr, std::shared_ptr<std::string*>> pending_msgs;
+    sg4::ActivitySet pending_comms;
 
     XBT_INFO("Wait for %d messages asynchronously", messages_count);
     for (int i = 0; i < messages_count; i++) {
-      pending_msgs.push_back(std::make_unique<std::string*>());
-      pending_comms.emplace_back(mbox->get_async<std::string>(pending_msgs[i].get()));
+      std::shared_ptr<std::string*> msg =std::make_shared<std::string*>();
+      auto comm = mbox->get_async<std::string>(msg.get());
+      pending_comms.push(comm);
+      pending_msgs.insert({comm, msg});
     }
+
     while (not pending_comms.empty()) {
-      ssize_t index    = sg4::Comm::wait_any(pending_comms);
-      std::string* msg = *pending_msgs[index];
-      XBT_INFO("I got '%s'.", msg->c_str());
-      /* cleanup memory and remove from vectors */
-      delete msg;
-      pending_comms.erase(pending_comms.begin() + index);
-      pending_msgs.erase(pending_msgs.begin() + index);
+      auto completed_one = pending_comms.wait_any();
+      if (completed_one != nullptr){
+        auto comm = boost::dynamic_pointer_cast<sg4::Comm>(completed_one);
+        auto msg = *pending_msgs[comm];
+        XBT_INFO("I got '%s'.", msg->c_str());
+        /* cleanup memory and remove from map */
+        delete msg;
+        pending_msgs.erase(comm);
+      }
     }
   }
 };
@@ -125,8 +131,7 @@ static void load_platform()
   link->set_latency(10e-6)->seal();
 
   /* create routes between nodes */
-  zone->add_route(sender->get_netpoint(), receiver->get_netpoint(), nullptr, nullptr,
-                  {{link, sg4::LinkInRoute::Direction::UP}}, true);
+  zone->add_route(sender, receiver, {link});
   zone->seal();
 
   /* create actors Sender/Receiver */
@@ -47,10 +47,22 @@ $ ${bindir:=.}/s4u-network-ns3 ${platfdir}/onelink.xml ${srcdir}/onelink_d.xml -
 > [:maestro(0)] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
 > [C1:worker(2)] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
 
+! output sort
 p Crosstraffic TCP option DISABLED
-! output ignore
-$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/crosstraffic.xml ${srcdir}/crosstraffic_d.xml --cfg=network/model:ns-3 --cfg=network/crosstraffic:0
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/crosstraffic.xml ${srcdir}/crosstraffic_d.xml --cfg=network/model:ns-3 --cfg=network/crosstraffic:0 "--log=root.fmt:[%h:%a(%i)]%e[%c/%p]%e%m%n"
+> [:maestro(0)] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [:maestro(0)] [xbt_cfg/INFO] Configuration change: Set 'network/crosstraffic' to '0'
+> [C1:worker(2)] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
+> [C1:worker(4)] [s4u_test/INFO] FLOW[2] : Receive 10000 bytes from S1 to C1
+> [C1:worker(6)] [s4u_test/INFO] FLOW[3] : Receive 10000 bytes from S1 to C1
+> [S1:worker(8)] [s4u_test/INFO] FLOW[4] : Receive 10000 bytes from C1 to S1
 
+! output sort
 p Crosstraffic TCP option ENABLED
-! output ignore
-$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/crosstraffic.xml ${srcdir}/crosstraffic_d.xml --cfg=network/model:ns-3 --cfg=network/crosstraffic:1
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/crosstraffic.xml ${srcdir}/crosstraffic_d.xml --cfg=network/model:ns-3 --cfg=network/crosstraffic:1 "--log=root.fmt:[%h:%a(%i)]%e[%c/%p]%e%m%n"
+> [:maestro(0)] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [:maestro(0)] [xbt_cfg/INFO] Configuration change: Set 'network/crosstraffic' to '1'
+> [C1:worker(2)] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
+> [C1:worker(4)] [s4u_test/INFO] FLOW[2] : Receive 10000 bytes from S1 to C1
+> [C1:worker(6)] [s4u_test/INFO] FLOW[3] : Receive 10000 bytes from S1 to C1
+> [S1:worker(8)] [s4u_test/INFO] FLOW[4] : Receive 10000 bytes from C1 to S1
diff --git a/examples/cpp/network-ns3/s4u-network-ns3-timed.tesh b/examples/cpp/network-ns3/s4u-network-ns3-timed.tesh
new file mode 100644 (file)
index 0000000..23ec6c5
--- /dev/null
@@ -0,0 +1,89 @@
+#!/usr/bin/env tesh
+
+p In the ns-3 tests, the timings are valid only with the very latest version of ns3 (the exact values may vary with your ns-3 version).
+
+p 3hosts 2links
+
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/small_platform_one_link_routes.xml ${srcdir}/3hosts_2links_d.xml --cfg=network/model:ns-3 "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [Jupiter:worker(2) 0.000249] [s4u_test/INFO] FLOW[1] : Receive 100 bytes from Tremblay to Jupiter
+
+p 6hosts 3links
+
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/small_platform_one_link_routes.xml ${srcdir}/3links_d.xml --cfg=network/model:ns-3 "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [Jupiter:worker(2) 0.000498] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from Tremblay to Jupiter
+> [Ginette:worker(4) 0.007323] [s4u_test/INFO] FLOW[2] : Receive 10000 bytes from Fafard to Ginette
+> [Lovelace:worker(6) 0.037450] [s4u_test/INFO] FLOW[3] : Receive 10000 bytes from Bourassa to Lovelace
+
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/small_platform_one_link_routes.xml ${srcdir}/3links-timer_d.xml --cfg=network/model:ns-3 "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [Jupiter:worker(2) 0.000498] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from Tremblay to Jupiter
+> [Ginette:worker(4) 0.007323] [s4u_test/INFO] FLOW[2] : Receive 10000 bytes from Fafard to Ginette
+> [Lovelace:worker(6) 0.037450] [s4u_test/INFO] FLOW[3] : Receive 10000 bytes from Bourassa to Lovelace
+> [Lovelace:worker(7) 2.037450] [s4u_test/INFO] FLOW[4] : Receive 10000 bytes from Bourassa to Lovelace
+
+p One cluster
+
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/cluster_backbone.xml ${srcdir}/one_cluster_d.xml --cfg=network/model:ns-3 "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [node-6.simgrid.org:worker(2) 0.021502] [s4u_test/INFO] FLOW[1] : Receive 100 bytes from node-2.simgrid.org to node-6.simgrid.org
+
+p Dogbone
+
+! timeout 10
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/dogbone.xml ${srcdir}/dogbone_d.xml --cfg=network/model:ns-3 "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [:maestro(0) 0.000000] [res_ns3/WARNING] Ignoring a route between S1 and C1 of length 3: Only routes of length 1 are considered with ns-3.
+> WARNING: You can ignore this warning if your hosts can still communicate when only considering routes of length 1.
+> WARNING: Remove long routes to avoid this harmless message; subsequent long routes will be silently ignored.
+> [C1:worker(3) 0.120224] [s4u_test/INFO] FLOW[0] : Receive 10000 bytes from S1 to C1
+> [C2:worker(4) 0.120234] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S2 to C2
+
+p 2hosts 1link
+
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/onelink.xml ${srcdir}/onelink_d.xml --cfg=network/model:ns-3 "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [C1:worker(2) 1.104600] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
+
+p 2hosts 1link NewReno (no timing change)
+
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/onelink.xml ${srcdir}/onelink_d.xml --cfg=network/model:ns-3 --cfg=ns3/NetworkModel:NewReno "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'ns3/NetworkModel' to 'NewReno'
+> [:maestro(0) 0.000000] [res_ns3/INFO] Switching Tcp protocol to 'NewReno'
+> [C1:worker(2) 1.104600] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
+
+p 2hosts 1link Cubic (no timing change)
+
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/onelink.xml ${srcdir}/onelink_d.xml --cfg=network/model:ns-3 --cfg=ns3/NetworkModel:Cubic "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'ns3/NetworkModel' to 'Cubic'
+> [:maestro(0) 0.000000] [res_ns3/INFO] Switching Tcp protocol to 'Cubic'
+> [C1:worker(2) 1.104600] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
+
+p 2hosts 1link UDP
+
+# $ ${bindir:=.}/s4u-network-ns3 ${platfdir}/onelink.xml ${srcdir}/onelink_d.xml --cfg=network/model:ns-3 --cfg=ns3/NetworkModel:UDP "--log=root.fmt:[%h:%a(%i)%e%r]%e[%c/%p]%e%m%n"
+# > [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+# > [:maestro(0) 0.000000] [xbt_cfg/INFO] Configuration change: Set 'ns3/NetworkModel' to 'UDP'
+# > [:maestro(0) 0.000000] [res_ns3/INFO] Switching network protocol to 'UDP'
+# > [C1:worker(2) 1.104600] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
+
+p Crosstraffic TCP option DISABLED
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/crosstraffic.xml ${srcdir}/crosstraffic_d.xml --cfg=network/model:ns-3 --cfg=network/crosstraffic:0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/crosstraffic' to '0'
+> [C1:worker:(2) 1.236600] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
+> [C1:worker:(4) 2.150800] [s4u_test/INFO] FLOW[2] : Receive 10000 bytes from S1 to C1
+> [C1:worker:(6) 3.197000] [s4u_test/INFO] FLOW[3] : Receive 10000 bytes from S1 to C1
+> [S1:worker:(8) 3.537400] [s4u_test/INFO] FLOW[4] : Receive 10000 bytes from C1 to S1
+
+p Crosstraffic TCP option ENABLED
+$ ${bindir:=.}/s4u-network-ns3 ${platfdir}/crosstraffic.xml ${srcdir}/crosstraffic_d.xml --cfg=network/model:ns-3 --cfg=network/crosstraffic:1
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/crosstraffic' to '1'
+> [C1:worker:(2) 1.236600] [s4u_test/INFO] FLOW[1] : Receive 10000 bytes from S1 to C1
+> [C1:worker:(4) 2.150800] [s4u_test/INFO] FLOW[2] : Receive 10000 bytes from S1 to C1
+> [C1:worker:(6) 3.197000] [s4u_test/INFO] FLOW[3] : Receive 10000 bytes from S1 to C1
+> [S1:worker:(8) 3.537400] [s4u_test/INFO] FLOW[4] : Receive 10000 bytes from C1 to S1
index 33f8e9a..13eae66 100644 (file)
@@ -35,14 +35,14 @@ int main(int argc, char* argv[])
   e.load_platform(argv[1]);
 
   /* Exchange a message between the 2 stations */
-  auto mailbox  = sg4::Mailbox::by_name("mailbox");
-  auto station1 = e.host_by_name("Station 1");
-  auto station2 = e.host_by_name("Station 2");
+  auto* mailbox  = sg4::Mailbox::by_name("mailbox");
+  auto* station1 = e.host_by_name("Station 1");
+  auto* station2 = e.host_by_name("Station 2");
   sg4::Actor::create("sender", station1, sender, mailbox, 1e7);
   sg4::Actor::create("receiver", station2, receiver, mailbox);
 
   /* Declare that the stations are not at the same distance from their AP */
-  auto ap = e.link_by_name("AP1");
+  const auto* ap = e.link_by_name("AP1");
   ap->set_host_wifi_rate(station1, 1); // The host "Station 1" uses the second level of bandwidths on that AP
   ap->set_host_wifi_rate(station2, 0); // This is perfectly useless as level 0 is used by default
 
index 3fe272d..1e637ff 100644 (file)
@@ -7,7 +7,7 @@
  *
  * This example is very similar to the other asynchronous communication examples, but messages get serialized by the platform.
  * Without this call to Link::set_concurrency_limit(2) in main, all messages would be received at the exact same timestamp since
- * they are initiated at the same instant and are of the same size. But with this extra configuration to the link, at most 2 
+ * they are initiated at the same instant and are of the same size. But with this extra configuration to the link, at most 2
  * messages can travel through the link at the same time.
  */
 
@@ -26,10 +26,10 @@ public:
   void operator()() const
   {
     // sphinx-doc: init-begin (this line helps the doc to build; ignore it)
-    /* Vector in which we store all ongoing communications */
-    std::vector<sg4::CommPtr> pending_comms;
+    /* ActivitySet in which we store all ongoing communications */
+    sg4::ActivitySet pending_comms;
 
-    /* Make a vector of the mailboxes to use */
+    /* Mailbox to use */
     sg4::Mailbox* mbox = sg4::Mailbox::by_name("receiver");
     // sphinx-doc: init-end
 
@@ -44,13 +44,13 @@ public:
 
       /* Create a communication representing the ongoing communication, and store it in pending_comms */
       sg4::CommPtr comm = mbox->put_async(payload, msg_size);
-      pending_comms.push_back(comm);
+      pending_comms.push(comm);
     }
 
     XBT_INFO("Done dispatching all messages");
 
     /* Now that all message exchanges were initiated, wait for their completion in one single call */
-    sg4::Comm::wait_all(pending_comms);
+    pending_comms.wait_all();
     // sphinx-doc: put-end
 
     XBT_INFO("Goodbye now!");
@@ -66,23 +66,28 @@ public:
   explicit Receiver(int count) : messages_count(count) { mbox = sg4::Mailbox::by_name("receiver"); }
   void operator()()
   {
-    /* Vector in which we store all incoming msgs */
-    std::vector<std::unique_ptr<std::string*>> pending_msgs;
-    std::vector<sg4::CommPtr> pending_comms;
+    /* Where we store all incoming msgs */
+    std::unordered_map<sg4::CommPtr, std::shared_ptr<std::string*>> pending_msgs;
+    sg4::ActivitySet pending_comms;
 
     XBT_INFO("Wait for %d messages asynchronously", messages_count);
     for (int i = 0; i < messages_count; i++) {
-      pending_msgs.push_back(std::make_unique<std::string*>());
-      pending_comms.emplace_back(mbox->get_async<std::string>(pending_msgs[i].get()));
+      std::shared_ptr<std::string*> msg =std::make_shared<std::string*>();
+      auto comm = mbox->get_async<std::string>(msg.get());
+      pending_comms.push(comm);
+      pending_msgs.insert({comm, msg});
     }
+
     while (not pending_comms.empty()) {
-      ssize_t index    = sg4::Comm::wait_any(pending_comms);
-      std::string* msg = *pending_msgs[index];
-      XBT_INFO("I got '%s'.", msg->c_str());
-      /* cleanup memory and remove from vectors */
-      delete msg;
-      pending_comms.erase(pending_comms.begin() + index);
-      pending_msgs.erase(pending_msgs.begin() + index);
+      auto completed_one = pending_comms.wait_any();
+      if (completed_one != nullptr){
+        auto comm = boost::dynamic_pointer_cast<sg4::Comm>(completed_one);
+        auto msg = *pending_msgs[comm];
+        XBT_INFO("I got '%s'.", msg->c_str());
+        /* cleanup memory and remove from map */
+        delete msg;
+        pending_msgs.erase(comm);
+      }
     }
   }
 };
@@ -104,8 +109,7 @@ int main(int argc, char* argv[])
       zone->create_split_duplex_link("link1", 10e9)->set_latency(10e-6)->set_concurrency_limit(2)->seal();
 
   /* create routes between nodes */
-  zone->add_route(sender->get_netpoint(), receiver->get_netpoint(), nullptr, nullptr,
-                  {{link, sg4::LinkInRoute::Direction::UP}}, true);
+  zone->add_route(sender, receiver, {link});
   zone->seal();
 
   /* create actors Sender/Receiver */
index 4cafcc1..f622d90 100644 (file)
@@ -118,8 +118,8 @@ int main(int argc, char* argv[])
   // Add a new host programatically, and attach a state profile to it
   auto* root     = e.get_netzone_root();
   auto* lilibeth = root->create_host("Lilibeth", 1e15);
-  auto link      = sg4::LinkInRoute(e.link_by_name("10"));
-  root->add_route(e.host_by_name("Tremblay")->get_netpoint(), lilibeth->get_netpoint(), nullptr, nullptr, {link}, true);
+  auto link      = e.link_by_name("10");
+  root->add_route(e.host_by_name("Tremblay"), lilibeth, {link});
   lilibeth->set_state_profile(simgrid::kernel::profile::ProfileBuilder::from_string("lilibeth_profile", R"(
 4 0
 5 1
index 8a7311f..2369ec0 100644 (file)
@@ -3,7 +3,7 @@
 p Testing a simple master/worker example application handling failures TCP crosstraffic DISABLED
 
 ! output sort 19
-$ ${bindir:=.}/s4u-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/s4u-platform-failures_d.xml --cfg=path:${srcdir} --cfg=network/crosstraffic:0 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
+$ ${bindir:=.}/s4u-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/s4u-platform-failures_d.xml --cfg=network/crosstraffic:0 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
 > [  0.000000] (0:maestro@) Cannot launch actor 'worker' on failed host 'Fafard'
 > [  0.000000] (0:maestro@) Starting actor worker(Fafard) failed because its host is turned off.
 > [  0.000000] (1:master@Tremblay) Got 5 workers and 20 tasks to process
@@ -123,7 +123,7 @@ $ ${bindir:=.}/s4u-platform-failures --log=xbt_cfg.thres:critical --log=no_loc $
 p Testing a simple master/worker example application handling failures. TCP crosstraffic ENABLED
 
 ! output sort 19
-$ ${bindir:=.}/s4u-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/s4u-platform-failures_d.xml --cfg=path:${srcdir} "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
+$ ${bindir:=.}/s4u-platform-failures --log=xbt_cfg.thres:critical --log=no_loc ${platfdir}/small_platform_failures.xml ${srcdir:=.}/s4u-platform-failures_d.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
 > [  0.000000] (0:maestro@) Cannot launch actor 'worker' on failed host 'Fafard'
 > [  0.000000] (0:maestro@) Starting actor worker(Fafard) failed because its host is turned off.
 > [  0.000000] (1:master@Tremblay) Got 5 workers and 20 tasks to process
diff --git a/examples/cpp/plugin-jbod/s4u-plugin-jbod.cpp b/examples/cpp/plugin-jbod/s4u-plugin-jbod.cpp
new file mode 100644 (file)
index 0000000..bb3b20b
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/s4u.hpp"
+#include "simgrid/plugins/jbod.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(jbod_test, "Messages specific for this simulation");
+namespace sg4 = simgrid::s4u;
+
+static void write_then_read(simgrid::plugin::JbodPtr jbod)
+{
+  simgrid::plugin::JbodIoPtr io = jbod->write_async(1e7);
+  XBT_INFO("asynchronous write posted, wait for it");
+  io->wait();
+  XBT_INFO("asynchronous write done");
+  jbod->read(1e7);
+  XBT_INFO("synchonous read done");
+  jbod->write(1e7);
+  XBT_INFO("synchonous write done");
+  io = jbod->read_async(1e7);
+  XBT_INFO("asynchronous read posted, wait for it");
+  io->wait();
+  XBT_INFO("asynchonous read done");
+  jbod->write(1e7);
+  XBT_INFO("synchonous write done");
+  jbod->read(1e7);
+  XBT_INFO("synchonous read done");
+  jbod->read(1e7);
+  XBT_INFO("synchonous read done");
+}
+
+int main(int argc, char** argv)
+{
+  sg4::Engine e(&argc, argv);
+  auto* zone = sg4::create_full_zone("zone");
+  auto* host = zone->create_host("host", "1Gf");
+  // set up link so that data transfer from host to JBOD takes exactly 1 second (without crosstraffic)
+  auto* link = zone->create_link("link", 1e7/0.97)->set_latency(0);
+
+  auto jbod_raid0 =
+      simgrid::plugin::Jbod::create_jbod(zone, "jbod_raid0", 1e9, 4, simgrid::plugin::Jbod::RAID::RAID0, 1e7, 5e6);
+  zone->add_route(host, jbod_raid0->get_controller(), {link});
+
+  auto jbod_raid1 =
+      simgrid::plugin::Jbod::create_jbod(zone, "jbod_raid1", 1e9, 4, simgrid::plugin::Jbod::RAID::RAID1, 1e7, 5e6);
+  zone->add_route(host, jbod_raid1->get_controller(), {link});
+
+  auto jbod_raid4 =
+      simgrid::plugin::Jbod::create_jbod(zone, "jbod_raid4", 1e9, 4, simgrid::plugin::Jbod::RAID::RAID4, 1e7, 5e6);
+  zone->add_route(host, jbod_raid4->get_controller(), {link});
+
+  auto jbod_raid5 =
+      simgrid::plugin::Jbod::create_jbod(zone, "jbod_raid5", 1e9, 4, simgrid::plugin::Jbod::RAID::RAID5, 1e7, 5e6);
+  zone->add_route(host, jbod_raid5->get_controller(), {link});
+
+  auto jbod_raid6 =
+      simgrid::plugin::Jbod::create_jbod(zone, "jbod_raid6", 1e9, 4, simgrid::plugin::Jbod::RAID::RAID6, 1e7, 5e6);
+  zone->add_route(host, jbod_raid6->get_controller(), {link});
+
+  zone->seal();
+
+  XBT_INFO("XXXXXXXXXXXXXXX RAID 0 XXXXXXXXXXXXXXXX");
+  sg4::Actor::create("", host, write_then_read, jbod_raid0);
+  e.run();
+
+  XBT_INFO("XXXXXXXXXXXXXXX RAID 1 XXXXXXXXXXXXXXXX");
+  sg4::Actor::create("", host, write_then_read, jbod_raid1);
+  e.run();
+
+  XBT_INFO("XXXXXXXXXXXXXXX RAID 4 XXXXXXXXXXXXXXXX");
+  sg4::Actor::create("", host, write_then_read, jbod_raid4);
+  e.run();
+
+  XBT_INFO("XXXXXXXXXXXXXXX RAID 5 XXXXXXXXXXXXXXXX");
+  sg4::Actor::create("", host, write_then_read, jbod_raid5);
+  e.run();
+
+  XBT_INFO("XXXXXXXXXXXXXXX RAID 6 XXXXXXXXXXXXXXXX");
+  sg4::Actor::create("", host, write_then_read, jbod_raid6);
+  e.run();
+
+  XBT_INFO("Simulated time: %g", sg4::Engine::get_clock());
+
+  return 0;
+}
diff --git a/examples/cpp/plugin-jbod/s4u-plugin-jbod.tesh b/examples/cpp/plugin-jbod/s4u-plugin-jbod.tesh
new file mode 100644 (file)
index 0000000..cfb05a0
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/env tesh
+
+$ ${bindir}/s4u-plugin-jbod --cfg=network/crosstraffic:0 "--log=root.fmt:[%10.6r]%e%m%n"
+> [  0.000000] Configuration change: Set 'network/crosstraffic' to '0'
+> [  0.000000] XXXXXXXXXXXXXXX RAID 0 XXXXXXXXXXXXXXXX
+> [  0.000000] asynchronous write posted, wait for it
+> [  1.500000] asynchronous write done
+> [  2.750000] synchonous read done
+> [  4.250000] synchonous write done
+> [  4.250000] asynchronous read posted, wait for it
+> [  5.500000] asynchonous read done
+> [  7.000000] synchonous write done
+> [  8.250000] synchonous read done
+> [  9.500000] synchonous read done
+> [  9.500000] XXXXXXXXXXXXXXX RAID 1 XXXXXXXXXXXXXXXX
+> [  9.500000] asynchronous write posted, wait for it
+> [ 12.500000] asynchronous write done
+> [ 14.500000] synchonous read done
+> [ 17.500000] synchonous write done
+> [ 17.500000] asynchronous read posted, wait for it
+> [ 19.500000] asynchonous read done
+> [ 22.500000] synchonous write done
+> [ 24.500000] synchonous read done
+> [ 26.500000] synchonous read done
+> [ 26.500000] XXXXXXXXXXXXXXX RAID 4 XXXXXXXXXXXXXXXX
+> [ 26.500000] asynchronous write posted, wait for it
+> [ 28.170000] asynchronous write done
+> [ 29.503333] synchonous read done
+> [ 31.173333] synchonous write done
+> [ 31.173333] asynchronous read posted, wait for it
+> [ 32.506666] asynchonous read done
+> [ 34.176666] synchonous write done
+> [ 35.510000] synchonous read done
+> [ 36.843333] synchonous read done
+> [ 36.843333] XXXXXXXXXXXXXXX RAID 5 XXXXXXXXXXXXXXXX
+> [ 36.843333] asynchronous write posted, wait for it
+> [ 38.513333] asynchronous write done
+> [ 39.846666] synchonous read done
+> [ 41.516666] synchonous write done
+> [ 41.516666] asynchronous read posted, wait for it
+> [ 42.849999] asynchonous read done
+> [ 44.519999] synchonous write done
+> [ 45.853333] synchonous read done
+> [ 47.186666] synchonous read done
+> [ 47.186666] XXXXXXXXXXXXXXX RAID 6 XXXXXXXXXXXXXXXX
+> [ 47.186666] asynchronous write posted, wait for it
+> [ 50.186666] asynchronous write done
+> [ 51.686666] synchonous read done
+> [ 54.686666] synchonous write done
+> [ 54.686666] asynchronous read posted, wait for it
+> [ 56.186666] asynchonous read done
+> [ 59.186666] synchonous write done
+> [ 60.686666] synchonous read done
+> [ 62.186666] synchonous read done
+> [ 62.186666] Simulated time: 62.1867
\ No newline at end of file
index c76cbe8..5f962a1 100644 (file)
@@ -11,14 +11,14 @@ namespace sg4 = simgrid::s4u;
 
 static void sender(const std::string& mailbox, uint64_t msg_size)
 {
-  auto mbox          = sg4::Mailbox::by_name(mailbox);
+  auto* mbox         = sg4::Mailbox::by_name(mailbox);
   static int payload = 42;
   mbox->put(&payload, msg_size);
 }
 
 static void receiver(const std::string& mailbox)
 {
-  auto mbox = sg4::Mailbox::by_name(mailbox);
+  auto* mbox = sg4::Mailbox::by_name(mailbox);
   mbox->get<int>();
 }
 
@@ -31,8 +31,8 @@ static void run_transfer(sg4::Host* src_host, sg4::Host* dst_host, const std::st
 
 static void execute_load_test()
 {
-  auto host0 = sg4::Host::by_name("node-0.simgrid.org");
-  auto host1 = sg4::Host::by_name("node-1.simgrid.org");
+  auto* host0 = sg4::Host::by_name("node-0.simgrid.org");
+  auto* host1 = sg4::Host::by_name("node-1.simgrid.org");
 
   sg4::this_actor::sleep_for(1);
   run_transfer(host0, host1, "1", 1000 * 1000 * 1000);
@@ -52,9 +52,9 @@ static void show_link_load(const std::string& link_name, const sg4::Link* link)
 
 static void monitor()
 {
-  auto link_backbone = sg4::Link::by_name("cluster0_backbone");
-  auto link_host0    = sg4::Link::by_name("cluster0_link_0_UP");
-  auto link_host1    = sg4::Link::by_name("cluster0_link_1_DOWN");
+  const auto* link_backbone = sg4::Link::by_name("cluster0_backbone");
+  const auto* link_host0    = sg4::Link::by_name("cluster0_link_0_UP");
+  const auto* link_host1    = sg4::Link::by_name("cluster0_link_1_DOWN");
 
   XBT_INFO("Tracking desired links");
   sg_link_load_track(link_backbone);
index 4483303..8d1ceeb 100644 (file)
@@ -65,12 +65,9 @@ int main(int argc, char* argv[])
     std::string linkname = "cluster_link_" + std::to_string(i);
     const auto* link     = cluster->create_split_duplex_link(linkname, "1Gbps");
 
-    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, {{link, sg4::LinkInRoute::Direction::UP}},
-                       true);
+    cluster->add_route(host, nullptr,  {{link, sg4::LinkInRoute::Direction::UP}}, true);
   }
-
-  auto* router = cluster->create_router("cluster_router");
-  cluster->add_route(router, nullptr, nullptr, nullptr, {});
+  cluster->seal();
 
   simgrid::plugin::ProducerConsumerPtr<int> pc = simgrid::plugin::ProducerConsumer<int>::create(2);
 
diff --git a/examples/cpp/solar-panel-simple/s4u-solar-panel-simple.cpp b/examples/cpp/solar-panel-simple/s4u-solar-panel-simple.cpp
new file mode 100644 (file)
index 0000000..624d83e
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (c) 2003-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/plugins/solar_panel.hpp"
+#include "simgrid/s4u.hpp"
+#include <simgrid/s4u/Actor.hpp>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(solar_panel_simple, "Messages specific for this s4u example");
+
+static void manager()
+{
+  auto solar_panel = simgrid::plugins::SolarPanel::init("Solar Panel", 10, 0.9, 10, 0, 1e3);
+  simgrid::s4u::this_actor::sleep_for(1);
+  XBT_INFO("%s: area: %fm² efficiency: %f irradiance: %fW/m² power: %fW", solar_panel->get_cname(),
+           solar_panel->get_area(), solar_panel->get_conversion_efficiency(), solar_panel->get_solar_irradiance(),
+           solar_panel->get_power());
+
+  solar_panel->set_area(20);
+  simgrid::s4u::this_actor::sleep_for(1);
+  XBT_INFO("%s: area: %fm² efficiency: %f irradiance: %fW/m² power: %fW", solar_panel->get_cname(),
+           solar_panel->get_area(), solar_panel->get_conversion_efficiency(), solar_panel->get_solar_irradiance(),
+           solar_panel->get_power());
+
+  solar_panel->set_conversion_efficiency(0.8);
+  simgrid::s4u::this_actor::sleep_for(1);
+  XBT_INFO("%s: area: %fm² efficiency: %f irradiance: %fW/m² power: %fW", solar_panel->get_cname(),
+           solar_panel->get_area(), solar_panel->get_conversion_efficiency(), solar_panel->get_solar_irradiance(),
+           solar_panel->get_power());
+
+  solar_panel->set_solar_irradiance(20);
+  simgrid::s4u::this_actor::sleep_for(1);
+  XBT_INFO("%s: area: %fm² efficiency: %f irradiance: %fW/m² power: %fW", solar_panel->get_cname(),
+           solar_panel->get_area(), solar_panel->get_conversion_efficiency(), solar_panel->get_solar_irradiance(),
+           solar_panel->get_power());
+}
+
+int main(int argc, char* argv[])
+{
+  simgrid::s4u::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+  simgrid::s4u::Actor::create("manager", e.host_by_name("Tremblay"), manager);
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/solar-panel-simple/s4u-solar-panel-simple.tesh b/examples/cpp/solar-panel-simple/s4u-solar-panel-simple.tesh
new file mode 100644 (file)
index 0000000..53b64dc
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-solar-panel-simple ${platfdir}/small_platform.xml
+> [Tremblay:manager:(1) 1.000000] [solar_panel_simple/INFO] Solar Panel: area: 10.000000m² efficiency: 0.900000 irradiance: 10.000000W/m² power: 90.000000W
+> [Tremblay:manager:(1) 2.000000] [solar_panel_simple/INFO] Solar Panel: area: 20.000000m² efficiency: 0.900000 irradiance: 10.000000W/m² power: 180.000000W
+> [Tremblay:manager:(1) 3.000000] [solar_panel_simple/INFO] Solar Panel: area: 20.000000m² efficiency: 0.800000 irradiance: 10.000000W/m² power: 160.000000W
+> [Tremblay:manager:(1) 4.000000] [solar_panel_simple/INFO] Solar Panel: area: 20.000000m² efficiency: 0.800000 irradiance: 20.000000W/m² power: 320.000000W
index fa4fc25..a9ee7ce 100644 (file)
 #!/usr/bin/env tesh
 
-$ ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-barrier 1 --log=s4u_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-barrier 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.
-> [Checker] Execute 1: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
-> [Checker] Execution came to an end at 1;1;0 (state: 3, depth: 3)
-> [Checker] Backtracking from 1;1;0
-> [Checker] DFS exploration ended. 3 unique states visited; 1 backtracks (3 transition replays, 0 states visited overall)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: BARRIER_WAIT(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
+> [Checker] 0 actors remain, but none of them need to be interleaved (depth 4).
+> [Checker] Execution came to an end at 1;1 (state: 3, depth: 3)
+> [Checker] Backtracking from 1;1
+> [Checker] DFS exploration ended. 3 unique states visited; 0 backtracks (0 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-barrier 2 --log=s4u_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-barrier 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.
-> [Checker] Execute 1: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
-> [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 3, state: 3, 0 interleaves)
-> [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=3)
-> [Checker] Execute 2: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 4, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=3)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=4)
-> [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=4)
-> [Checker] Execution came to an end at 1;2;1;2;0 (state: 5, depth: 5)
-> [Checker] Backtracking from 1;2;1;2;0
-> [Checker] Execute 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 1: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 6, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=6)
-> [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 3, state: 7, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
+> [Checker] INDEPENDENT Transitions:
+> [Checker]  #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
+> [Checker]  #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: BARRIER_WAIT(barrier: 0) (stack depth: 3, state: 3, 0 interleaves)
 > [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=7)
-> [Checker] Execute 2: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 8, 0 interleaves)
+> [Checker]  #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
+> [Checker]  #1 BARRIER_WAIT(barrier: 0) (state=3)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 4, 0 interleaves)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=7)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=8)
+> [Checker]  #1 BARRIER_WAIT(barrier: 0) (state=3)
+> [Checker]  #2 BARRIER_WAIT(barrier: 0) (state=4)
 > [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=6)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=8)
-> [Checker] Execution came to an end at 2;1;1;2;0 (state: 9, depth: 5)
-> [Checker] Backtracking from 2;1;1;2;0
-> [Checker] DFS exploration ended. 9 unique states visited; 2 backtracks (10 transition replays, 0 states visited overall)
+> [Checker]  #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
+> [Checker]  #2 BARRIER_WAIT(barrier: 0) (state=4)
+> [Checker] 0 actors remain, but none of them need to be interleaved (depth 6).
+> [Checker] Execution came to an end at 1;2;1;2 (state: 5, depth: 5)
+> [Checker] Backtracking from 1;2;1;2
+> [Checker] Sleep set actually containing:
+> [Checker]   <1,BARRIER_ASYNC_LOCK(barrier: 0)>
+> [Checker] Executed 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] 2 actors remain, but none of them need to be interleaved (depth 3).
+> [Checker] Backtracking from 2
+> [Checker] DFS exploration ended. 6 unique states visited; 1 backtracks (0 transition replays, 7 states visited overall)
 
-$ ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-barrier 3 --log=s4u_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-barrier 3 --log=s4u_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
 > [Checker] Start a DFS exploration. Reduction is: dpor.
-> [Checker] Execute 1: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
-> [Checker] Execute 3: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 3, state: 3, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=3)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=3)
-> [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 4, 0 interleaves)
-> [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=3)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=4)
-> [Checker] Execute 2: BARRIER_WAIT(barrier: 0) (stack depth: 5, state: 5, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=4)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=5)
-> [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=3)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=5)
-> [Checker] Execute 3: BARRIER_WAIT(barrier: 0) (stack depth: 6, state: 6, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=5)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=6)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=4)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=6)
-> [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=6)
-> [Checker] Execution came to an end at 1;2;3;1;2;3;0 (state: 7, depth: 7)
-> [Checker] Backtracking from 1;2;3;1;2;3;0
-> [Checker] Execute 3: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
-> [Checker] Execute 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 3, state: 8, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=8)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=8)
-> [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 9, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
+> [Checker] INDEPENDENT Transitions:
+> [Checker]  #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
+> [Checker]  #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 3: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 3, state: 3, 0 interleaves)
+> [Checker] INDEPENDENT Transitions:
+> [Checker]  #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
+> [Checker]  #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=3)
+> [Checker] INDEPENDENT Transitions:
+> [Checker]  #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
+> [Checker]  #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=3)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 4, 0 interleaves)
 > [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=8)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=9)
-> [Checker] Execute 2: BARRIER_WAIT(barrier: 0) (stack depth: 5, state: 10, 0 interleaves)
+> [Checker]  #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=3)
+> [Checker]  #1 BARRIER_WAIT(barrier: 0) (state=4)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: BARRIER_WAIT(barrier: 0) (stack depth: 5, state: 5, 0 interleaves)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=9)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=10)
+> [Checker]  #1 BARRIER_WAIT(barrier: 0) (state=4)
+> [Checker]  #2 BARRIER_WAIT(barrier: 0) (state=5)
 > [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=10)
-> [Checker] Execute 3: BARRIER_WAIT(barrier: 0) (stack depth: 6, state: 11, 0 interleaves)
+> [Checker]  #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=3)
+> [Checker]  #2 BARRIER_WAIT(barrier: 0) (state=5)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 3: BARRIER_WAIT(barrier: 0) (stack depth: 6, state: 6, 0 interleaves)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=10)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=11)
+> [Checker]  #2 BARRIER_WAIT(barrier: 0) (state=5)
+> [Checker]  #3 BARRIER_WAIT(barrier: 0) (state=6)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=9)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=11)
+> [Checker]  #1 BARRIER_WAIT(barrier: 0) (state=4)
+> [Checker]  #3 BARRIER_WAIT(barrier: 0) (state=6)
 > [Checker] Dependent Transitions:
-> [Checker]   BARRIER_ASYNC_LOCK(barrier: 0) (state=8)
-> [Checker]   BARRIER_WAIT(barrier: 0) (state=11)
-> [Checker] Execution came to an end at 1;3;2;1;2;3;0 (state: 12, depth: 7)
-> [Checker] Backtracking from 1;3;2;1;2;3;0
-> [Checker] DFS exploration ended. 12 unique states visited; 2 backtracks (14 transition replays, 1 states visited overall)
\ No newline at end of file
+> [Checker]  #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
+> [Checker]  #3 BARRIER_WAIT(barrier: 0) (state=6)
+> [Checker] 0 actors remain, but none of them need to be interleaved (depth 8).
+> [Checker] Execution came to an end at 1;2;3;1;2;3 (state: 7, depth: 7)
+> [Checker] Backtracking from 1;2;3;1;2;3
+> [Checker] Sleep set actually containing:
+> [Checker]   <2,BARRIER_ASYNC_LOCK(barrier: 0)>
+> [Checker] Executed 3: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
+> [Checker] INDEPENDENT Transitions:
+> [Checker]  #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1)
+> [Checker]  #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=2)
+> [Checker] 3 actors remain, but none of them need to be interleaved (depth 4).
+> [Checker] Backtracking from 1;3
+> [Checker] DFS exploration ended. 8 unique states visited; 1 backtracks (1 transition replays, 10 states visited overall)
\ No newline at end of file
index b7944d8..07b0b62 100644 (file)
@@ -11,10 +11,10 @@ namespace sg4 = simgrid::s4u;
 /// Wait on the barrier then leave
 static void worker(sg4::BarrierPtr barrier)
 {
-    XBT_INFO("Waiting on the barrier");
-    barrier->wait();
+  XBT_INFO("Waiting on the barrier");
+  barrier->wait();
 
-    XBT_INFO("Bye");
+  XBT_INFO("Bye");
 }
 
 /// Spawn actor_count-1 workers and do a barrier with them
@@ -27,10 +27,10 @@ static void master(int actor_count)
     sg4::Actor::create("worker", sg4::Host::by_name("Jupiter"), worker, barrier);
   }
 
-    XBT_INFO("Waiting on the barrier");
-    barrier->wait();
+  XBT_INFO("Waiting on the barrier");
+  barrier->wait();
 
-    XBT_INFO("Bye");
+  XBT_INFO("Bye");
 }
 
 int main(int argc, char **argv)
index 67d1ac2..b660bf3 100644 (file)
@@ -40,7 +40,7 @@ static void main_actor()
   auto cv    = sg4::ConditionVariable::create();
   auto ready = std::make_shared<bool>(false);
 
-  auto host = sg4::this_actor::get_host();
+  auto* host = sg4::this_actor::get_host();
   for (int i = 0; i < 10; ++i)
     sg4::Actor::create("competitor", host, competitor, i, cv, mtx, ready);
   sg4::Actor::create("go", host, go, cv, mtx, ready);
index 6dda41c..26f7e20 100644 (file)
@@ -2,86 +2,84 @@
 
 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"
+$ $VALGRIND_NO_TRACE_CHILDREN ${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"
 > [App    ] Configuration change: Set 'actors' to '1'
 > [Checker] Start a DFS exploration. Reduction is: dpor.
-> [Checker] Execute 1: MUTEX_ASYNC_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)
-> [Checker] Execute 2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (stack depth: 4, state: 4, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: MUTEX_WAIT(mutex: 0, owner: 1) (stack depth: 2, state: 2, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: MUTEX_UNLOCK(mutex: 0, owner: -1) (stack depth: 3, state: 3, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (stack depth: 4, state: 4, 0 interleaves)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3)
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4)
+> [Checker]  #1 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3)
+> [Checker]  #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   MUTEX_WAIT(mutex: 0, owner: 1) (state=2)
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4)
+> [Checker]  #1 MUTEX_WAIT(mutex: 0, owner: 1) (state=2)
+> [Checker]  #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4)
 > [Checker] Dependent Transitions:
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=1)
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4)
-> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner: 2) (stack depth: 5, state: 5, 0 interleaves)
+> [Checker]  #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=1)
+> [Checker]  #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: MUTEX_WAIT(mutex: 0, owner: 2) (stack depth: 5, state: 5, 0 interleaves)
 > [Checker] Dependent Transitions:
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3)
-> [Checker]   MUTEX_WAIT(mutex: 0, owner: 2) (state=5)
-> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner: -1) (stack depth: 6, state: 6, 0 interleaves)
+> [Checker]  #1 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3)
+> [Checker]  #2 MUTEX_WAIT(mutex: 0, owner: 2) (state=5)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: MUTEX_UNLOCK(mutex: 0, owner: -1) (stack depth: 6, state: 6, 0 interleaves)
 > [Checker] Dependent Transitions:
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3)
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: -1) (state=6)
-> [Checker] Execution came to an end at 1;1;1;2;2;2;0 (state: 7, depth: 7)
-> [Checker] Backtracking from 1;1;1;2;2;2;0
-> [Checker] Execute 2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (stack depth: 3, state: 3, 0 interleaves)
+> [Checker]  #1 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3)
+> [Checker]  #2 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=6)
+> [Checker] 0 actors remain, but none of them need to be interleaved (depth 8).
+> [Checker] Execution came to an end at 1;1;1;2;2;2 (state: 7, depth: 7)
+> [Checker] Backtracking from 1;1;1;2;2;2
+> [Checker] Sleep set actually containing:
+> [Checker]   <1,MUTEX_UNLOCK(mutex: 0, owner: -1)>
+> [Checker] Executed 2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (stack depth: 3, state: 3, 0 interleaves)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   MUTEX_WAIT(mutex: 0, owner: 1) (state=2)
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3)
+> [Checker]  #1 MUTEX_WAIT(mutex: 0, owner: 1) (state=2)
+> [Checker]  #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3)
 > [Checker] Dependent Transitions:
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=1)
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3)
-> [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner: 2) (stack depth: 4, state: 8, 0 interleaves)
-> [Checker] INDEPENDENT Transitions:
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3)
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: 2) (state=8)
-> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner: 2) (stack depth: 5, state: 9, 0 interleaves)
-> [Checker] Dependent Transitions:
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: 2) (state=8)
-> [Checker]   MUTEX_WAIT(mutex: 0, owner: 2) (state=9)
-> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner: -1) (stack depth: 6, state: 10, 0 interleaves)
-> [Checker] Dependent Transitions:
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: 2) (state=8)
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: -1) (state=10)
-> [Checker] Execution came to an end at 1;1;2;1;2;2;0 (state: 11, depth: 7)
-> [Checker] Backtracking from 1;1;2;1;2;2;0
-> [Checker] Execute 2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 1: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (stack depth: 2, state: 12, 0 interleaves)
+> [Checker]  #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=1)
+> [Checker]  #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3)
+> [Checker] 2 actors remain, but none of them need to be interleaved (depth 5).
+> [Checker] Backtracking from 1;1;2
+> [Checker] Sleep set actually containing:
+> [Checker]   <1,MUTEX_ASYNC_LOCK(mutex: 0, owner: 1)>
+> [Checker] Executed 2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (stack depth: 2, state: 9, 0 interleaves)
 > [Checker] Dependent Transitions:
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=1)
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=12)
-> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner: 2) (stack depth: 3, state: 13, 0 interleaves)
+> [Checker]  #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=1)
+> [Checker]  #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: MUTEX_WAIT(mutex: 0, owner: 2) (stack depth: 3, state: 10, 0 interleaves)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=12)
-> [Checker]   MUTEX_WAIT(mutex: 0, owner: 2) (state=13)
-> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner: 1) (stack depth: 4, state: 14, 0 interleaves)
+> [Checker]  #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9)
+> [Checker]  #2 MUTEX_WAIT(mutex: 0, owner: 2) (state=10)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 2: MUTEX_UNLOCK(mutex: 0, owner: 1) (stack depth: 4, state: 11, 0 interleaves)
 > [Checker] INDEPENDENT Transitions:
-> [Checker]   MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=12)
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: 1) (state=14)
-> [Checker] Execute 1: MUTEX_WAIT(mutex: 0, owner: 1) (stack depth: 5, state: 15, 0 interleaves)
+> [Checker]  #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9)
+> [Checker]  #2 MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: MUTEX_WAIT(mutex: 0, owner: 1) (stack depth: 5, state: 12, 0 interleaves)
 > [Checker] Dependent Transitions:
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: 1) (state=14)
-> [Checker]   MUTEX_WAIT(mutex: 0, owner: 1) (state=15)
-> [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner: -1) (stack depth: 6, state: 16, 0 interleaves)
+> [Checker]  #2 MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11)
+> [Checker]  #1 MUTEX_WAIT(mutex: 0, owner: 1) (state=12)
+> [Checker] Sleep set actually containing:
+> [Checker] Executed 1: MUTEX_UNLOCK(mutex: 0, owner: -1) (stack depth: 6, state: 13, 0 interleaves)
 > [Checker] Dependent Transitions:
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: 1) (state=14)
-> [Checker]   MUTEX_UNLOCK(mutex: 0, owner: -1) (state=16)
-> [Checker] Execution came to an end at 2;1;2;2;1;1;0 (state: 17, depth: 7)
-> [Checker] Backtracking from 2;1;2;2;1;1;0
-> [Checker] DFS exploration ended. 17 unique states visited; 3 backtracks (21 transition replays, 2 states visited overall)
+> [Checker]  #2 MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11)
+> [Checker]  #1 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=13)
+> [Checker] 0 actors remain, but none of them need to be interleaved (depth 8).
+> [Checker] Execution came to an end at 2;1;2;2;1;1 (state: 14, depth: 7)
+> [Checker] Backtracking from 2;1;2;2;1;1
+> [Checker] DFS exploration ended. 14 unique states visited; 2 backtracks (2 transition replays, 18 states visited overall)
 
-$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:2 --log=s4u_test.thres:critical
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/sleep-set' to 'true'
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:2 --log=s4u_test.thres:critical
 > [0.000000] [xbt_cfg/INFO] Configuration change: Set 'actors' to '2'
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 128 unique states visited; 26 backtracks (296 transition replays, 143 states visited overall)
-
-$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true -- ${bindir:=.}/s4u-synchro-mutex  --cfg=actors:3 --log=s4u_test.thres:critical
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/sleep-set' to 'true'
-> [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. 4645 unique states visited; 1082 backtracks (18004 transition replays, 12278 states visited overall)
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 66 unique states visited; 11 backtracks (49 transition replays, 126 states visited overall)
index 54e641e..65836b1 100644 (file)
@@ -1,6 +1,5 @@
 #!/usr/bin/env tesh
 
-$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true --log=mc_dfs.thres:info --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-semaphore --log=sem_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
-> [Checker] Configuration change: Set 'model-check/sleep-set' to 'true'
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:info --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-semaphore --log=sem_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
 > [Checker] Start a DFS exploration. Reduction is: dpor.
-> [Checker] DFS exploration ended. 33 unique states visited; 9 backtracks (125 transition replays, 84 states visited overall)
+> [Checker] DFS exploration ended. 33 unique states visited; 8 backtracks (84 transition replays, 125 states visited overall)
diff --git a/examples/cpp/task-dispatch/s4u-task-dispatch.cpp b/examples/cpp/task-dispatch/s4u-task-dispatch.cpp
new file mode 100644 (file)
index 0000000..10bd0d2
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(task_dispatch, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+
+static void manager(sg4::ExecTaskPtr t)
+{
+  auto PM0 = sg4::Engine::get_instance()->host_by_name("PM0");
+  auto PM1 = sg4::Engine::get_instance()->host_by_name("PM1");
+
+  XBT_INFO("Test set_flops");
+  t->enqueue_firings(2);
+  sg4::this_actor::sleep_for(50);
+  XBT_INFO("Set instance_0 flops to 50.");
+  t->set_flops(50 * PM0->get_speed());
+  sg4::this_actor::sleep_for(250);
+  t->set_flops(100 * PM0->get_speed());
+
+  XBT_INFO("Test set_parallelism degree");
+  t->enqueue_firings(3);
+  sg4::this_actor::sleep_for(50);
+  XBT_INFO("Set Task parallelism degree to 2.");
+  t->set_parallelism_degree(2);
+  sg4::this_actor::sleep_for(250);
+  t->set_parallelism_degree(1);
+
+  XBT_INFO("Test set_host dispatcher");
+  t->enqueue_firings(2);
+  sg4::this_actor::sleep_for(50);
+  XBT_INFO("Move dispatcher to PM1");
+  t->set_host(PM1, "dispatcher");
+  t->set_internal_bytes(1e6, "dispatcher");
+  sg4::this_actor::sleep_for(250);
+  t->set_host(PM0, "dispatcher");
+
+  XBT_INFO("Test set_host instance_0");
+  t->enqueue_firings(2);
+  sg4::this_actor::sleep_for(50);
+  XBT_INFO("Move instance_0 to PM1");
+  t->set_host(PM1, "instance_0");
+  t->set_flops(100 * PM1->get_speed());
+  t->set_internal_bytes(1e6, "instance_0");
+  sg4::this_actor::sleep_for(250);
+  t->set_host(PM0, "instance_0");
+  t->set_flops(100 * PM0->get_speed());
+
+  XBT_INFO("Test set_host collector");
+  t->enqueue_firings(2);
+  sg4::this_actor::sleep_for(50);
+  XBT_INFO("Move collector to PM1");
+  t->set_host(PM1, "collector");
+  sg4::this_actor::sleep_for(250);
+  t->set_host(PM0, "collector");
+
+  XBT_INFO("Test add_instances");
+  t->enqueue_firings(1);
+  sg4::this_actor::sleep_for(50);
+  XBT_INFO("Add 1 instance and update load balancing function");
+  t->add_instances(1);
+  t->set_load_balancing_function([]() {
+    static int round_robin_counter = 0;
+    int ret                        = round_robin_counter;
+    round_robin_counter            = round_robin_counter == 1 ? 0 : round_robin_counter + 1;
+    return "instance_" + std::to_string(ret);
+  });
+  t->enqueue_firings(2);
+  sg4::this_actor::sleep_for(250);
+
+  XBT_INFO("Test remove_instances");
+  XBT_INFO("Remove 1 instance and update load balancing function");
+  t->remove_instances(1);
+  t->set_load_balancing_function([]() { return "instance_0"; });
+  t->enqueue_firings(2);
+  sg4::this_actor::sleep_for(300);
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+  auto PM0 = e.host_by_name("PM0");
+  auto PM1 = sg4::Engine::get_instance()->host_by_name("PM1");
+
+  auto a = sg4::ExecTask::init("A", 100 * PM0->get_speed(), PM0);
+  auto b = sg4::ExecTask::init("B", 50 * PM0->get_speed(), PM0);
+  auto c = sg4::CommTask::init("C", 1e6, PM1, PM0);
+
+  a->add_successor(b);
+
+  sg4::Task::on_completion_cb(
+      [](const sg4::Task* t) { XBT_INFO("Task %s finished (%d)", t->get_name().c_str(), t->get_count()); });
+  sg4::Task::on_start_cb([](const sg4::Task* t) { XBT_INFO("Task %s start", t->get_name().c_str()); });
+
+  sg4::Actor::create("manager", PM0, manager, a);
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/task-dispatch/s4u-task-dispatch.tesh b/examples/cpp/task-dispatch/s4u-task-dispatch.tesh
new file mode 100644 (file)
index 0000000..a4ace54
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/env tesh
+
+> > $ ${bindir:=.}/s4u-task-parallelism ${platfdir}/three_multicore_hosts.xml
+> [PM0:manager:(1) 0.000000] [task_dispatch/INFO] Test set_flops
+> [0.000000] [task_dispatch/INFO] Task A start
+> [0.000000] [task_dispatch/INFO] Task A start
+> [PM0:manager:(1) 50.000000] [task_dispatch/INFO] Set instance_0 flops to 50.
+> [100.000000] [task_dispatch/INFO] Task A finished (1)
+> [100.000000] [task_dispatch/INFO] Task B start
+> [150.000000] [task_dispatch/INFO] Task A finished (2)
+> [150.000000] [task_dispatch/INFO] Task B start
+> [150.000000] [task_dispatch/INFO] Task B finished (1)
+> [200.000000] [task_dispatch/INFO] Task B finished (2)
+> [PM0:manager:(1) 300.000000] [task_dispatch/INFO] Test set_parallelism degree
+> [300.000000] [task_dispatch/INFO] Task A start
+> [300.000000] [task_dispatch/INFO] Task A start
+> [300.000000] [task_dispatch/INFO] Task A start
+> [PM0:manager:(1) 350.000000] [task_dispatch/INFO] Set Task parallelism degree to 2.
+> [400.000000] [task_dispatch/INFO] Task A finished (3)
+> [400.000000] [task_dispatch/INFO] Task B start
+> [450.000000] [task_dispatch/INFO] Task A finished (4)
+> [450.000000] [task_dispatch/INFO] Task B start
+> [450.000000] [task_dispatch/INFO] Task B finished (3)
+> [500.000000] [task_dispatch/INFO] Task A finished (5)
+> [500.000000] [task_dispatch/INFO] Task B start
+> [500.000000] [task_dispatch/INFO] Task B finished (4)
+> [550.000000] [task_dispatch/INFO] Task B finished (5)
+> [PM0:manager:(1) 600.000000] [task_dispatch/INFO] Test set_host dispatcher
+> [600.000000] [task_dispatch/INFO] Task A start
+> [600.000000] [task_dispatch/INFO] Task A start
+> [PM0:manager:(1) 650.000000] [task_dispatch/INFO] Move dispatcher to PM1
+> [700.000000] [task_dispatch/INFO] Task A finished (6)
+> [700.000000] [task_dispatch/INFO] Task B start
+> [750.000000] [task_dispatch/INFO] Task B finished (6)
+> [800.009961] [task_dispatch/INFO] Task A finished (7)
+> [800.009961] [task_dispatch/INFO] Task B start
+> [850.009961] [task_dispatch/INFO] Task B finished (7)
+> [PM0:manager:(1) 900.000000] [task_dispatch/INFO] Test set_host instance_0
+> [900.000000] [task_dispatch/INFO] Task A start
+> [900.000000] [task_dispatch/INFO] Task A start
+> [PM0:manager:(1) 950.000000] [task_dispatch/INFO] Move instance_0 to PM1
+> [1000.000000] [task_dispatch/INFO] Task A finished (8)
+> [1000.000000] [task_dispatch/INFO] Task B start
+> [1050.000000] [task_dispatch/INFO] Task B finished (8)
+> [1100.019922] [task_dispatch/INFO] Task A finished (9)
+> [1100.019922] [task_dispatch/INFO] Task B start
+> [1150.019922] [task_dispatch/INFO] Task B finished (9)
+> [PM0:manager:(1) 1200.000000] [task_dispatch/INFO] Test set_host collector
+> [1200.000000] [task_dispatch/INFO] Task A start
+> [1200.000000] [task_dispatch/INFO] Task A start
+> [PM0:manager:(1) 1250.000000] [task_dispatch/INFO] Move collector to PM1
+> [1300.000000] [task_dispatch/INFO] Task A finished (10)
+> [1300.000000] [task_dispatch/INFO] Task B start
+> [1350.000000] [task_dispatch/INFO] Task B finished (10)
+> [1400.009961] [task_dispatch/INFO] Task A finished (11)
+> [1400.009961] [task_dispatch/INFO] Task B start
+> [1450.009961] [task_dispatch/INFO] Task B finished (11)
+> [PM0:manager:(1) 1500.000000] [task_dispatch/INFO] Test add_instances
+> [1500.000000] [task_dispatch/INFO] Task A start
+> [PM0:manager:(1) 1550.000000] [task_dispatch/INFO] Add 1 instance and update load balancing function
+> [1550.000000] [task_dispatch/INFO] Task A start
+> [1550.000000] [task_dispatch/INFO] Task A start
+> [1600.000000] [task_dispatch/INFO] Task A finished (12)
+> [1600.000000] [task_dispatch/INFO] Task B start
+> [1650.000000] [task_dispatch/INFO] Task A finished (13)
+> [1650.000000] [task_dispatch/INFO] Task B start
+> [1650.000000] [task_dispatch/INFO] Task B finished (12)
+> [1700.000000] [task_dispatch/INFO] Task A finished (14)
+> [1700.000000] [task_dispatch/INFO] Task B start
+> [1700.000000] [task_dispatch/INFO] Task B finished (13)
+> [1750.000000] [task_dispatch/INFO] Task B finished (14)
+> [PM0:manager:(1) 1800.000000] [task_dispatch/INFO] Test remove_instances
+> [PM0:manager:(1) 1800.000000] [task_dispatch/INFO] Remove 1 instance and update load balancing function
+> [1800.000000] [task_dispatch/INFO] Task A start
+> [1800.000000] [task_dispatch/INFO] Task A start
+> [1900.000000] [task_dispatch/INFO] Task A finished (15)
+> [1900.000000] [task_dispatch/INFO] Task B start
+> [1950.000000] [task_dispatch/INFO] Task B finished (15)
+> [2000.000000] [task_dispatch/INFO] Task A finished (16)
+> [2000.000000] [task_dispatch/INFO] Task B start
+> [2050.000000] [task_dispatch/INFO] Task B finished (16)
+> 
\ No newline at end of file
diff --git a/examples/cpp/task-io/s4u-task-io.cpp b/examples/cpp/task-io/s4u-task-io.cpp
new file mode 100644 (file)
index 0000000..c0f6eb0
--- /dev/null
@@ -0,0 +1,53 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example demonstrate basic use of tasks.
+ *
+ * We model the following graph:
+ *
+ * exec1 -> comm -> exec2
+ *
+ * exec1 and exec2 are execution tasks.
+ * comm is a communication task.
+ */
+
+#include "simgrid/s4u.hpp"
+#include "simgrid/s4u/Task.hpp"
+#include <simgrid/plugins/file_system.h>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(task_simple, "Messages specific for this task example");
+namespace sg4 = simgrid::s4u;
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  // Retrieve hosts
+  auto* bob  = e.host_by_name("bob");
+  auto* carl = e.host_by_name("carl");
+
+  // Create tasks
+  auto exec1 = sg4::ExecTask::init("exec1", 1e9, bob);
+  auto exec2 = sg4::ExecTask::init("exec2", 1e9, carl);
+  auto write = sg4::IoTask::init("write", 1e7, bob->get_disks().front(), sg4::Io::OpType::WRITE);
+  auto read  = sg4::IoTask::init("read", 1e7, carl->get_disks().front(), sg4::Io::OpType::READ);
+
+  // Create the graph by defining dependencies between tasks
+  exec1->add_successor(write);
+  write->add_successor(read);
+  read->add_successor(exec2);
+
+  // Add a function to be called when tasks end for log purpose
+  sg4::Task::on_completion_cb(
+      [](const sg4::Task* t) { XBT_INFO("Task %s finished (%d)", t->get_name().c_str(), t->get_count()); });
+
+  // Enqueue two firings for task exec1
+  exec1->enqueue_firings(2);
+
+  // Start the simulation
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/task-io/s4u-task-io.tesh b/examples/cpp/task-io/s4u-task-io.tesh
new file mode 100644 (file)
index 0000000..b1b5cdb
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-task-io ${platfdir}/hosts_with_disks.xml
+> [1.000000] [task_simple/INFO] Task exec1 finished (1)
+> [1.250000] [task_simple/INFO] Task write finished (1)
+> [1.350000] [task_simple/INFO] Task read finished (1)
+> [2.000000] [task_simple/INFO] Task exec1 finished (2)
+> [2.250000] [task_simple/INFO] Task write finished (2)
+> [2.350000] [task_simple/INFO] Task exec2 finished (1)
+> [2.350000] [task_simple/INFO] Task read finished (2)
+> [3.350000] [task_simple/INFO] Task exec2 finished (2)
diff --git a/examples/cpp/task-microservice/s4u-task-microservice.cpp b/examples/cpp/task-microservice/s4u-task-microservice.cpp
new file mode 100644 (file)
index 0000000..5c449e8
--- /dev/null
@@ -0,0 +1,145 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example illustrates how to use Simgrid Tasks to reproduce the workflow 2.a of the article
+ * "Automated performance prediction of microservice applications using simulation" by Clément Courageux-Sudan et al.
+ *
+ * To build this workflow we create;
+ *   - each Execution Task
+ *   - each Communication Task
+ *   - the links between the Tasks, i.e. the graph
+ *
+ * We also increase the parallelism degree of each Task to 10.
+ *
+ * In this scenario we send 500 requests per second (RPS) to the entry point of the graph for 7 seconds,
+ * and we count the number of processed requests between 2 and 7 seconds to evaluate the number of requests processed
+ * per second.
+ */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(task_microservice, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+
+static void request_sender(sg4::TaskPtr t, int requests_per_second)
+{
+  for (int i = 0; i < requests_per_second * 7; i++) {
+    t->enqueue_firings(1);
+    sg4::this_actor::sleep_for(1.0 / requests_per_second);
+  }
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  // Retrieve Hosts
+  auto pm0 = e.host_by_name("PM0");
+  auto pm1 = e.host_by_name("PM1");
+
+  // Set concurrency limit
+  pm0->set_concurrency_limit(10);
+  pm1->set_concurrency_limit(10);
+
+  // Create Exec Tasks
+  auto nginx_web_server        = sg4::ExecTask::init("nginx_web_server", 783 * pm0->get_speed() / 1e6, pm0);
+  auto compose_post_service_0  = sg4::ExecTask::init("compose_post_service_0", 682 * pm0->get_speed() / 1e6, pm0);
+  auto unique_id_service       = sg4::ExecTask::init("unique_id_service", 12 * pm0->get_speed() / 1e6, pm0);
+  auto compose_post_service_1  = sg4::ExecTask::init("compose_post_service_1", 140 * pm0->get_speed() / 1e6, pm0);
+  auto media_service           = sg4::ExecTask::init("media_service", 6 * pm1->get_speed() / 1e6, pm1);
+  auto compose_post_service_2  = sg4::ExecTask::init("compose_post_service_2", 135 * pm0->get_speed() / 1e6, pm0);
+  auto user_service            = sg4::ExecTask::init("user_service", 5 * pm0->get_speed() / 1e6, pm0);
+  auto compose_post_service_3  = sg4::ExecTask::init("compose_post_service_3", 147 * pm0->get_speed() / 1e6, pm0);
+  auto text_service_0          = sg4::ExecTask::init("text_service_0", 296 * pm0->get_speed() / 1e6, pm0);
+  auto text_service_1          = sg4::ExecTask::init("text_service_1", 350 * pm0->get_speed() / 1e6, pm0);
+  auto text_service_2          = sg4::ExecTask::init("text_service_2", 146 * pm0->get_speed() / 1e6, pm0);
+  auto user_mention_service    = sg4::ExecTask::init("user_mention_service", 934 * pm0->get_speed() / 1e6, pm0);
+  auto url_shorten_service     = sg4::ExecTask::init("url_shorten_service", 555 * pm0->get_speed() / 1e6, pm0);
+  auto compose_post_service_4  = sg4::ExecTask::init("compose_post_service_4", 138 * pm0->get_speed() / 1e6, pm0);
+  auto home_timeline_service_0 = sg4::ExecTask::init("home_timeline_service_0", 243 * pm0->get_speed() / 1e6, pm0);
+  auto social_graph_service    = sg4::ExecTask::init("home_timeline_service_0", 707 * pm0->get_speed() / 1e6, pm0);
+  auto home_timeline_service_1 = sg4::ExecTask::init("home_timeline_service_0", 7 * pm0->get_speed() / 1e6, pm0);
+  auto compose_post_service_5  = sg4::ExecTask::init("compose_post_service_5", 192 * pm0->get_speed() / 1e6, pm0);
+  auto user_timeline_service   = sg4::ExecTask::init("user_timeline_service", 913 * pm0->get_speed() / 1e6, pm0);
+  auto compose_post_service_6  = sg4::ExecTask::init("compose_post_service_6", 508 * pm0->get_speed() / 1e6, pm0);
+  auto post_storage_service    = sg4::ExecTask::init("post_storage_service", 391 * pm1->get_speed() / 1e6, pm1);
+
+  // Create Comm Tasks
+  auto compose_post_service_1_to_media_service =
+      sg4::CommTask::init("compose_post_service_1_to_media_service", 100, pm0, pm1);
+  auto media_service_to_compose_post_service_2 =
+      sg4::CommTask::init("media_service_to_compose_post_service_2", 100, pm1, pm0);
+  auto compose_post_service_6_to_post_storage_service =
+      sg4::CommTask::init("media_service_to_compose_post_service_2", 100, pm1, pm0);
+
+  // Create the graph
+  nginx_web_server->add_successor(compose_post_service_0);
+  compose_post_service_0->add_successor(unique_id_service);
+  unique_id_service->add_successor(compose_post_service_1);
+  compose_post_service_1->add_successor(compose_post_service_1_to_media_service);
+  compose_post_service_1_to_media_service->add_successor(media_service);
+  media_service->add_successor(media_service_to_compose_post_service_2);
+  media_service_to_compose_post_service_2->add_successor(compose_post_service_2);
+  compose_post_service_2->add_successor(user_service);
+  user_service->add_successor(compose_post_service_3);
+  compose_post_service_3->add_successor(text_service_0);
+  text_service_0->add_successor(text_service_1);
+  text_service_0->add_successor(text_service_2);
+  text_service_1->add_successor(user_mention_service);
+  text_service_2->add_successor(url_shorten_service);
+  user_mention_service->add_successor(compose_post_service_4);
+  compose_post_service_4->add_successor(home_timeline_service_0);
+  home_timeline_service_0->add_successor(social_graph_service);
+  social_graph_service->add_successor(home_timeline_service_1);
+  home_timeline_service_1->add_successor(compose_post_service_5);
+  compose_post_service_5->add_successor(user_timeline_service);
+  user_timeline_service->add_successor(compose_post_service_6);
+  compose_post_service_6->add_successor(compose_post_service_6_to_post_storage_service);
+  compose_post_service_6_to_post_storage_service->add_successor(post_storage_service);
+
+  // Dispatch Exec Tasks
+  std::vector<sg4::TaskPtr> exec_tasks = {nginx_web_server,
+                                          compose_post_service_0,
+                                          unique_id_service,
+                                          compose_post_service_1,
+                                          compose_post_service_1_to_media_service,
+                                          media_service,
+                                          media_service_to_compose_post_service_2,
+                                          compose_post_service_2,
+                                          user_service,
+                                          compose_post_service_3,
+                                          text_service_0,
+                                          text_service_1,
+                                          text_service_2,
+                                          user_mention_service,
+                                          url_shorten_service,
+                                          compose_post_service_4,
+                                          home_timeline_service_0,
+                                          social_graph_service,
+                                          home_timeline_service_1,
+                                          compose_post_service_5,
+                                          user_timeline_service,
+                                          compose_post_service_6,
+                                          compose_post_service_6_to_post_storage_service,
+                                          post_storage_service};
+  for (auto t : exec_tasks)
+    t->set_parallelism_degree(10);
+
+  // Create the actor that will inject requests during the simulation
+  sg4::Actor::create("request_sender", pm0, request_sender, nginx_web_server, 500);
+
+  // Add a function to be called when tasks end for log purpose
+  int requests_processed = 0;
+  sg4::Task::on_completion_cb([&e, &requests_processed](const sg4::Task* t) {
+    if (t->get_name() == "post_storage_service" and e.get_clock() < 7 and e.get_clock() > 2)
+      requests_processed++;
+  });
+
+  // Start the simulation
+  e.run();
+  XBT_INFO("Requests processed per second: %f", requests_processed / 5.0);
+  return 0;
+}
diff --git a/examples/cpp/task-microservice/s4u-task-microservice.tesh b/examples/cpp/task-microservice/s4u-task-microservice.tesh
new file mode 100644 (file)
index 0000000..9a95e44
--- /dev/null
@@ -0,0 +1,4 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-task-microservice ${platfdir}/three_multicore_hosts.xml
+> [7.008495] [task_microservice/INFO] Requests processed per second: 500.000000
\ No newline at end of file
diff --git a/examples/cpp/task-parallelism/s4u-task-parallelism.cpp b/examples/cpp/task-parallelism/s4u-task-parallelism.cpp
new file mode 100644 (file)
index 0000000..c9f70da
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example tests increasing and decreasing parallelism degree of Tasks.
+ * First we increase and decrease parallelism degree while the Task is idle,
+ * then we increase and decrease parallelism degree while the Task has queued firings.
+ */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(task_parallelism, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+
+static void manager(sg4::ExecTaskPtr t)
+{
+  t->set_parallelism_degree(1);
+  t->enqueue_firings(2);
+  sg4::this_actor::sleep_for(300);
+
+  t->set_parallelism_degree(2);
+  t->enqueue_firings(4);
+  sg4::this_actor::sleep_for(300);
+
+  t->set_parallelism_degree(1);
+  t->enqueue_firings(2);
+  sg4::this_actor::sleep_for(300);
+
+  t->enqueue_firings(11);
+  t->set_parallelism_degree(2);
+  sg4::this_actor::sleep_for(150);
+  t->set_parallelism_degree(1);
+  sg4::this_actor::sleep_for(200);
+  t->set_parallelism_degree(3);
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+  auto pm0 = e.host_by_name("PM0");
+  auto t   = sg4::ExecTask::init("exec_A", 100 * pm0->get_speed(), pm0);
+  sg4::Task::on_completion_cb(
+      [](const sg4::Task* t) { XBT_INFO("Task %s finished (%d)", t->get_cname(), t->get_count()); });
+  sg4::Task::on_start_cb([](const sg4::Task* t) { XBT_INFO("Task %s start", t->get_cname()); });
+  sg4::Actor::create("sender", pm0, manager, t);
+
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/task-parallelism/s4u-task-parallelism.tesh b/examples/cpp/task-parallelism/s4u-task-parallelism.tesh
new file mode 100644 (file)
index 0000000..492d015
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-task-parallelism ${platfdir}/three_multicore_hosts.xml
+> [0.000000] [task_parallelism/INFO] Task exec_A start
+> [100.000000] [task_parallelism/INFO] Task exec_A start
+> [100.000000] [task_parallelism/INFO] Task exec_A finished (1)
+> [200.000000] [task_parallelism/INFO] Task exec_A finished (2)
+> [300.000000] [task_parallelism/INFO] Task exec_A start
+> [300.000000] [task_parallelism/INFO] Task exec_A start
+> [400.000000] [task_parallelism/INFO] Task exec_A start
+> [400.000000] [task_parallelism/INFO] Task exec_A start
+> [400.000000] [task_parallelism/INFO] Task exec_A finished (3)
+> [400.000000] [task_parallelism/INFO] Task exec_A finished (4)
+> [500.000000] [task_parallelism/INFO] Task exec_A finished (5)
+> [500.000000] [task_parallelism/INFO] Task exec_A finished (6)
+> [600.000000] [task_parallelism/INFO] Task exec_A start
+> [700.000000] [task_parallelism/INFO] Task exec_A start
+> [700.000000] [task_parallelism/INFO] Task exec_A finished (7)
+> [800.000000] [task_parallelism/INFO] Task exec_A finished (8)
+> [900.000000] [task_parallelism/INFO] Task exec_A start
+> [900.000000] [task_parallelism/INFO] Task exec_A start
+> [1000.000000] [task_parallelism/INFO] Task exec_A start
+> [1000.000000] [task_parallelism/INFO] Task exec_A start
+> [1000.000000] [task_parallelism/INFO] Task exec_A finished (9)
+> [1000.000000] [task_parallelism/INFO] Task exec_A finished (10)
+> [1100.000000] [task_parallelism/INFO] Task exec_A start
+> [1100.000000] [task_parallelism/INFO] Task exec_A finished (11)
+> [1100.000000] [task_parallelism/INFO] Task exec_A finished (12)
+> [1200.000000] [task_parallelism/INFO] Task exec_A start
+> [1200.000000] [task_parallelism/INFO] Task exec_A finished (13)
+> [1250.000000] [task_parallelism/INFO] Task exec_A start
+> [1250.000000] [task_parallelism/INFO] Task exec_A start
+> [1300.000000] [task_parallelism/INFO] Task exec_A start
+> [1300.000000] [task_parallelism/INFO] Task exec_A finished (14)
+> [1350.000000] [task_parallelism/INFO] Task exec_A start
+> [1350.000000] [task_parallelism/INFO] Task exec_A start
+> [1350.000000] [task_parallelism/INFO] Task exec_A finished (15)
+> [1350.000000] [task_parallelism/INFO] Task exec_A finished (16)
+> [1400.000000] [task_parallelism/INFO] Task exec_A finished (17)
+> [1450.000000] [task_parallelism/INFO] Task exec_A finished (18)
+> [1450.000000] [task_parallelism/INFO] Task exec_A finished (19)
\ No newline at end of file
diff --git a/examples/cpp/task-simple/s4u-task-simple.cpp b/examples/cpp/task-simple/s4u-task-simple.cpp
new file mode 100644 (file)
index 0000000..2d7224f
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example demonstrate basic use of tasks.
+ *
+ * We model the following graph:
+ *
+ * exec1 -> comm -> exec2
+ *
+ * exec1 and exec2 are execution tasks.
+ * comm is a communication task.
+ */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(task_simple, "Messages specific for this task example");
+
+namespace sg4 = simgrid::s4u;
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  // Retrieve hosts
+  auto* tremblay = e.host_by_name("Tremblay");
+  auto* jupiter  = e.host_by_name("Jupiter");
+
+  // Create tasks
+  auto exec1 = sg4::ExecTask::init("exec1", 1e9, tremblay);
+  auto exec2 = sg4::ExecTask::init("exec2", 1e9, jupiter);
+  auto comm  = sg4::CommTask::init("comm", 1e7, tremblay, jupiter);
+
+  // Create the graph by defining dependencies between tasks
+  exec1->add_successor(comm);
+  comm->add_successor(exec2);
+
+  // Add a function to be called when tasks end for log purpose
+  sg4::Task::on_completion_cb(
+      [](const sg4::Task* t) { XBT_INFO("Task %s finished (%d)", t->get_name().c_str(), t->get_count()); });
+
+  // Enqueue two firings for task exec1
+  exec1->enqueue_firings(2);
+
+  // Start the simulation
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/task-simple/s4u-task-simple.tesh b/examples/cpp/task-simple/s4u-task-simple.tesh
new file mode 100644 (file)
index 0000000..b07d406
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-task-simple ${platfdir}/small_platform.xml
+> [10.194200] [task_simple/INFO] Task exec1 finished (1)
+> [11.714617] [task_simple/INFO] Task comm finished (1)
+> [20.388399] [task_simple/INFO] Task exec1 finished (2)
+> [21.908817] [task_simple/INFO] Task comm finished (2)
+> [24.821464] [task_simple/INFO] Task exec2 finished (1)
+> [37.928311] [task_simple/INFO] Task exec2 finished (2)
diff --git a/examples/cpp/task-storm/s4u-task-storm.cpp b/examples/cpp/task-storm/s4u-task-storm.cpp
new file mode 100644 (file)
index 0000000..ca0f61e
--- /dev/null
@@ -0,0 +1,134 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example takes the main concepts of Apache Storm presented here
+   https://storm.apache.org/releases/2.4.0/Concepts.html and use them to build a simulation of a stream processing
+   application
+
+   Spout SA produces data every 100ms. The volume produced is alternatively 1e3, 1e6 and 1e9 bytes.
+   Spout SB produces 1e6 bytes every 200ms.
+
+   Bolt B1 and B2 processes data from Spout SA alternatively. The quantity of work to process this data is 10 flops per
+   bytes Bolt B3 processes data from Spout SB. Bolt B4 processes data from Bolt B3.
+
+                        Fafard
+                        ┌────┐
+                    ┌──►│ B1 │
+         Tremblay   │   └────┘
+          ┌────┐    │
+          │ SA ├────┤  Ginette
+          └────┘    │   ┌────┐
+                    └──►│ B2 │
+                        └────┘
+
+
+                       Bourassa
+         Jupiter     ┌──────────┐
+          ┌────┐     │          │
+          │ SB ├─────┤ B3 ──► B4│
+          └────┘     │          │
+                     └──────────┘
+ */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(task_storm, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  // Retrieve hosts
+  auto tremblay = e.host_by_name("Tremblay");
+  auto jupiter  = e.host_by_name("Jupiter");
+  auto fafard   = e.host_by_name("Fafard");
+  auto ginette  = e.host_by_name("Ginette");
+  auto bourassa = e.host_by_name("Bourassa");
+
+  // Create execution tasks
+  auto SA = sg4::ExecTask::init("SA", tremblay->get_speed() * 0.1, tremblay);
+  auto SB = sg4::ExecTask::init("SB", jupiter->get_speed() * 0.2, jupiter);
+  auto B1 = sg4::ExecTask::init("B1", 1e8, fafard);
+  auto B2 = sg4::ExecTask::init("B2", 1e8, ginette);
+  auto B3 = sg4::ExecTask::init("B3", 1e8, bourassa);
+  auto B4 = sg4::ExecTask::init("B4", 2e8, bourassa);
+
+  // Create communication tasks
+  auto SA_to_B1 = sg4::CommTask::init("SA_to_B1", 0, tremblay, fafard);
+  auto SA_to_B2 = sg4::CommTask::init("SA_to_B2", 0, tremblay, ginette);
+  auto SB_to_B3 = sg4::CommTask::init("SB_to_B3", 1e6, jupiter, bourassa);
+
+  // Create the graph by defining dependencies between tasks
+  // Some dependencies are defined dynamically
+  SA_to_B1->add_successor(B1);
+  SA_to_B2->add_successor(B2);
+  SB->add_successor(SB_to_B3);
+  SB_to_B3->add_successor(B3);
+  B3->add_successor(B4);
+
+  /* Dynamic modification of the graph and bytes sent
+     Alternatively we: remove/add the link between SA and SA_to_B2
+                       add/remove the link between SA and SA_to_B1
+  */
+  SA->on_this_completion_cb([&SA_to_B1, &SA_to_B2](sg4::Task* t) {
+    int count = t->get_count();
+    sg4::CommTaskPtr comm;
+    if (count % 2 == 1) {
+      t->remove_successor(SA_to_B2);
+      t->add_successor(SA_to_B1);
+      comm = SA_to_B1;
+    } else {
+      t->remove_successor(SA_to_B1);
+      t->add_successor(SA_to_B2);
+      comm = SA_to_B2;
+    }
+    std::vector<double> amount = {1e9, 1e3, 1e6};
+    // XBT_INFO("Comm %f", amount[count % 3]);
+    comm->set_amount(amount[count % 3]);
+    auto token = std::make_shared<sg4::Token>();
+    token->set_data(new double(amount[count % 3]));
+    t->set_token(token);
+  });
+
+  // The token sent by SA is forwarded by both communication tasks
+  SA_to_B1->on_this_completion_cb([&SA](sg4::Task* t) {
+    t->set_token(t->get_token_from(SA));
+    t->deque_token_from(SA);
+  });
+  SA_to_B2->on_this_completion_cb([&SA](sg4::Task* t) {
+    t->set_token(t->get_token_from(SA));
+    t->deque_token_from(SA);
+  });
+
+  /* B1 and B2 read the value of the token received by their predecessors
+     and use it to adapt their amount of work to do.
+  */
+  B1->on_this_start_cb([&SA_to_B1](sg4::Task* t) {
+    auto data = t->get_token_from(SA_to_B1)->get_data<double>();
+    t->deque_token_from(SA_to_B1);
+    t->set_amount(*data * 10);
+    delete data;
+  });
+  B2->on_this_start_cb([&SA_to_B2](sg4::Task* t) {
+    auto data = t->get_token_from(SA_to_B2)->get_data<double>();
+    t->deque_token_from(SA_to_B2);
+    t->set_amount(*data * 10);
+    delete data;
+  });
+
+  // Enqueue firings for tasks without predecessors
+  SA->enqueue_firings(5);
+  SB->enqueue_firings(5);
+
+  // Add a function to be called when tasks end for log purpose
+  sg4::Task::on_completion_cb(
+      [](const sg4::Task* t) { XBT_INFO("Task %s finished (%d)", t->get_name().c_str(), t->get_count()); });
+
+  // Start the simulation
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/task-storm/s4u-task-storm.tesh b/examples/cpp/task-storm/s4u-task-storm.tesh
new file mode 100644 (file)
index 0000000..376dc31
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-task-storm ${platfdir}/small_platform.xml
+> [0.100000] [task_storm/INFO] Task SA finished (1)
+> [0.125841] [task_storm/INFO] Task SA_to_B1 finished (1)
+> [0.125972] [task_storm/INFO] Task B1 finished (1)
+> [0.200000] [task_storm/INFO] Task SB finished (1)
+> [0.200000] [task_storm/INFO] Task SA finished (2)
+> [0.300000] [task_storm/INFO] Task SA finished (3)
+> [0.364429] [task_storm/INFO] Task SA_to_B2 finished (1)
+> [0.400000] [task_storm/INFO] Task SB finished (2)
+> [0.400000] [task_storm/INFO] Task SA finished (4)
+> [0.416759] [task_storm/INFO] Task SA_to_B2 finished (2)
+> [0.500000] [task_storm/INFO] Task SA finished (5)
+> [0.557036] [task_storm/INFO] Task SB_to_B3 finished (1)
+> [0.570648] [task_storm/INFO] Task B2 finished (1)
+> [0.570855] [task_storm/INFO] Task B2 finished (2)
+> [0.600000] [task_storm/INFO] Task SB finished (3)
+> [0.800000] [task_storm/INFO] Task SB finished (4)
+> [0.867388] [task_storm/INFO] Task SB_to_B3 finished (2)
+> [1.000000] [task_storm/INFO] Task SB finished (5)
+> [1.177739] [task_storm/INFO] Task SB_to_B3 finished (3)
+> [1.488090] [task_storm/INFO] Task SB_to_B3 finished (4)
+> [1.798442] [task_storm/INFO] Task SB_to_B3 finished (5)
+> [2.619232] [task_storm/INFO] Task B3 finished (1)
+> [6.743624] [task_storm/INFO] Task B3 finished (2)
+> [10.868015] [task_storm/INFO] Task B4 finished (1)
+> [10.868015] [task_storm/INFO] Task B3 finished (3)
+> [14.992407] [task_storm/INFO] Task B3 finished (4)
+> [19.116799] [task_storm/INFO] Task B4 finished (2)
+> [19.116799] [task_storm/INFO] Task B3 finished (5)
+> [23.241190] [task_storm/INFO] Task B4 finished (3)
+> [27.365582] [task_storm/INFO] Task B4 finished (4)
+> [31.489974] [task_storm/INFO] Task B4 finished (5)
+> [133.367321] [task_storm/INFO] Task SA_to_B1 finished (2)
+> [133.525717] [task_storm/INFO] Task SA_to_B1 finished (3)
+> [264.435791] [task_storm/INFO] Task B1 finished (2)
+> [264.566859] [task_storm/INFO] Task B1 finished (3)
diff --git a/examples/cpp/task-switch-host/s4u-task-switch-host.cpp b/examples/cpp/task-switch-host/s4u-task-switch-host.cpp
new file mode 100644 (file)
index 0000000..c236bdb
--- /dev/null
@@ -0,0 +1,82 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example demonstrates how to dynamically modify a graph of tasks.
+ *
+ * Assuming we have two instances of a service placed on different hosts,
+ * we want to send data alternatively to thoses instances.
+ *
+ * We consider the following graph:
+ *
+ * comm0 -> exec1 -> comm1
+ *     ↳-> exec2 ->comm2
+ *
+ * With exec1 and exec2 on different hosts.
+ */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(task_switch_host, "Messages specific for this task example");
+namespace sg4 = simgrid::s4u;
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  // Retrieve hosts
+  auto* tremblay = e.host_by_name("Tremblay");
+  auto* jupiter  = e.host_by_name("Jupiter");
+  auto* fafard   = e.host_by_name("Fafard");
+
+  // Create tasks
+  auto comm0 = sg4::CommTask::init("comm0");
+  comm0->set_bytes(1e7);
+  comm0->set_source(tremblay);
+  auto exec1 = sg4::ExecTask::init("exec1", 1e9, jupiter);
+  auto exec2 = sg4::ExecTask::init("exec2", 1e9, fafard);
+  auto comm1 = sg4::CommTask::init("comm1", 1e7, jupiter, tremblay);
+  auto comm2 = sg4::CommTask::init("comm2", 1e7, fafard, tremblay);
+
+  // Create the initial graph by defining dependencies between tasks
+  comm0->add_successor(exec2);
+  exec1->add_successor(comm1);
+  exec2->add_successor(comm2);
+
+  // Add a function to be called when tasks end for log purpose
+  sg4::Task::on_completion_cb(
+      [](const sg4::Task* t) { XBT_INFO("Task %s finished (%d)", t->get_name().c_str(), t->get_count()); });
+
+  // Add a function to be called before each firing of comm0
+  // This function modifies the graph of tasks by adding or removing
+  // successors to comm0
+  comm0->on_this_start_cb([&comm0, exec1, exec2, jupiter, fafard](const sg4::Task*) {
+    static int count = 0;
+    if (count % 2 == 0)
+      comm0->set_destination(jupiter);
+    else
+      comm0->set_destination(fafard);
+    count++;
+  });
+
+  comm0->on_this_completion_cb([&comm0, exec1, exec2](const sg4::Task*) {
+    static int count = 0;
+    if (count % 2 == 0) {
+      comm0->add_successor(exec1);
+      comm0->remove_successor(exec2);
+    } else {
+      comm0->add_successor(exec2);
+      comm0->remove_successor(exec1);
+    }
+    count++;
+  });
+
+  // Enqueue four firings for task comm0
+  comm0->enqueue_firings(4);
+
+  // Start the simulation
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/task-switch-host/s4u-task-switch-host.tesh b/examples/cpp/task-switch-host/s4u-task-switch-host.tesh
new file mode 100644 (file)
index 0000000..b3146ff
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-task-switch-host ${platfdir}/small_platform.xml
+> [1.520418] [task_switch_host/INFO] Task comm0 finished (1)
+> [2.873012] [task_switch_host/INFO] Task comm0 finished (2)
+> [4.393430] [task_switch_host/INFO] Task comm0 finished (3)
+> [5.746025] [task_switch_host/INFO] Task comm0 finished (4)
+> [14.627265] [task_switch_host/INFO] Task exec1 finished (1)
+> [15.979859] [task_switch_host/INFO] Task exec2 finished (1)
+> [16.147682] [task_switch_host/INFO] Task comm1 finished (1)
+> [17.332454] [task_switch_host/INFO] Task comm2 finished (1)
+> [27.734112] [task_switch_host/INFO] Task exec1 finished (2)
+> [29.086707] [task_switch_host/INFO] Task exec2 finished (2)
+> [29.254529] [task_switch_host/INFO] Task comm1 finished (2)
+> [30.439301] [task_switch_host/INFO] Task comm2 finished (2)
\ No newline at end of file
diff --git a/examples/cpp/task-variable-load/s4u-task-variable-load.cpp b/examples/cpp/task-variable-load/s4u-task-variable-load.cpp
new file mode 100644 (file)
index 0000000..fff790d
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* This example demonstrates how to create a variable load for tasks.
+ *
+ * We consider the following graph:
+ *
+ * comm -> exec
+ *
+ * With a small load each comm task is followed by an exec task.
+ * With a heavy load there is a burst of comm before the exec task can even finish once.
+ */
+
+#include "simgrid/s4u.hpp"
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(task_variable_load, "Messages specific for this s4u example");
+namespace sg4 = simgrid::s4u;
+
+static void variable_load(sg4::TaskPtr t)
+{
+  XBT_INFO("--- Small load ---");
+  for (int i = 0; i < 3; i++) {
+    t->enqueue_firings(1);
+    sg4::this_actor::sleep_for(100);
+  }
+  sg4::this_actor::sleep_until(1000);
+  XBT_INFO("--- Heavy load ---");
+  for (int i = 0; i < 3; i++) {
+    t->enqueue_firings(1);
+    sg4::this_actor::sleep_for(1);
+  }
+}
+
+int main(int argc, char* argv[])
+{
+  sg4::Engine e(&argc, argv);
+  e.load_platform(argv[1]);
+
+  // Retreive hosts
+  auto* tremblay = e.host_by_name("Tremblay");
+  auto* jupiter  = e.host_by_name("Jupiter");
+
+  // Create tasks
+  auto comm = sg4::CommTask::init("comm", 1e7, tremblay, jupiter);
+  auto exec = sg4::ExecTask::init("exec", 1e9, jupiter);
+
+  // Create the graph by defining dependencies between tasks
+  comm->add_successor(exec);
+
+  // Add a function to be called when tasks end for log purpose
+  sg4::Task::on_completion_cb(
+      [](const sg4::Task* t) { XBT_INFO("Task %s finished (%d)", t->get_name().c_str(), t->get_count()); });
+
+  // Create the actor that will inject load during the simulation
+  sg4::Actor::create("input", tremblay, variable_load, comm);
+
+  // Start the simulation
+  e.run();
+  return 0;
+}
diff --git a/examples/cpp/task-variable-load/s4u-task-variable-load.tesh b/examples/cpp/task-variable-load/s4u-task-variable-load.tesh
new file mode 100644 (file)
index 0000000..2f2ab9b
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env tesh
+
+$ ${bindir:=.}/s4u-task-variable-load ${platfdir}/small_platform.xml
+> [Tremblay:input:(1) 0.000000] [task_variable_load/INFO] --- Small load ---
+> [1.520418] [task_variable_load/INFO] Task comm finished (1)
+> [14.627265] [task_variable_load/INFO] Task exec finished (1)
+> [101.520418] [task_variable_load/INFO] Task comm finished (2)
+> [114.627265] [task_variable_load/INFO] Task exec finished (2)
+> [201.520418] [task_variable_load/INFO] Task comm finished (3)
+> [214.627265] [task_variable_load/INFO] Task exec finished (3)
+> [Tremblay:input:(1) 1000.000000] [task_variable_load/INFO] --- Heavy load ---
+> [1001.520418] [task_variable_load/INFO] Task comm finished (4)
+> [1003.040835] [task_variable_load/INFO] Task comm finished (5)
+> [1004.561253] [task_variable_load/INFO] Task comm finished (6)
+> [1014.627265] [task_variable_load/INFO] Task exec finished (4)
+> [1027.734112] [task_variable_load/INFO] Task exec finished (5)
+> [1040.840959] [task_variable_load/INFO] Task exec finished (6)
index 30a6d30..adf6f3d 100644 (file)
@@ -22,7 +22,7 @@ struct Task {
 
 static void master()
 {
-  auto mbox = sg4::Mailbox::by_name("master_mailbox");
+  auto* mbox = sg4::Mailbox::by_name("master_mailbox");
   for (int i = 0; i < 10; i++) {
     Task task;
     if (i % 2)
@@ -39,7 +39,7 @@ static void master()
 
 static void worker()
 {
-  auto mbox = sg4::Mailbox::by_name("master_mailbox");
+  auto* mbox = sg4::Mailbox::by_name("master_mailbox");
   while (true) {
     auto task = mbox->get_unique<Task>();
     if (task->name == "finalize") {
index 14a4b74..d63d4a1 100644 (file)
@@ -24,7 +24,7 @@ static void master(std::vector<std::string> args)
   long communication_cost = std::stol(args[3]);
   size_t workers_count    = args.size() - 4;
   const auto& my_host     = sg4::this_actor::get_host()->get_name();
-  auto mailbox            = sg4::Mailbox::by_name("master_mailbox");
+  auto* mailbox           = sg4::Mailbox::by_name("master_mailbox");
 
   XBT_DEBUG("Got %zu workers and %ld tasks to process", workers_count, tasks_count);
 
@@ -54,7 +54,7 @@ static void worker(std::vector<std::string> args)
   xbt_assert(args.size() == 1, "The worker expects no argument");
 
   const auto& my_host = sg4::this_actor::get_host()->get_name();
-  auto mailbox        = sg4::Mailbox::by_name("master_mailbox");
+  auto* mailbox       = sg4::Mailbox::by_name("master_mailbox");
 
   simgrid::instr::set_host_variable(my_host, "is_worker", 1);
   simgrid::instr::set_host_variable(my_host, "task_computation", 0);
index cecea13..a09afe8 100644 (file)
@@ -17,7 +17,7 @@ namespace sg4 = simgrid::s4u;
 /* The guy we will move from host to host. It move alone and then is moved by policeman back  */
 static void emigrant()
 {
-  auto mailbox = sg4::Mailbox::by_name("master_mailbox");
+  auto* mailbox = sg4::Mailbox::by_name("master_mailbox");
 
   sg4::this_actor::sleep_for(2);
 
@@ -35,7 +35,7 @@ static void policeman()
   // I am the master of emigrant actor,
   // I tell it where it must emigrate to.
   auto destinations = {"Tremblay", "Jupiter", "Fafard", "Ginette", "Bourassa", "Fafard", "Tremblay", "Ginette", ""};
-  auto mailbox      = sg4::Mailbox::by_name("master_mailbox");
+  auto* mailbox     = sg4::Mailbox::by_name("master_mailbox");
 
   for (auto const& destination : destinations) {
     mailbox->put_init(new std::string(destination), 0)->set_tracing_category("migration_order")->wait();
index b6dafe2..99d6865 100644 (file)
@@ -117,253 +117,257 @@ $ tail -n +3 procmig.trace
 > %EndEventDef
 > 0 1 0 HOST
 > 6 0.000000 1 1 0 "Tremblay"
+> 2 2 1 HOST_STATE
+> 5 3 2 receive "1 0 0"
+> 5 4 2 send "0 0 1"
+> 5 5 2 execute "0 1 1"
 > 6 0.000000 2 1 0 "Jupiter"
 > 6 0.000000 3 1 0 "Fafard"
 > 6 0.000000 4 1 0 "Ginette"
 > 6 0.000000 5 1 0 "Bourassa"
 > 6 0.000000 6 1 0 "Jacquelin"
 > 6 0.000000 7 1 0 "Boivin"
-> 0 2 0 LINK
-> 6 0.000000 8 2 0 "6"
-> 6 0.000000 9 2 0 "3"
-> 6 0.000000 10 2 0 "7"
-> 6 0.000000 11 2 0 "9"
-> 6 0.000000 12 2 0 "2"
-> 6 0.000000 13 2 0 "8"
-> 6 0.000000 14 2 0 "1"
-> 6 0.000000 15 2 0 "4"
-> 6 0.000000 16 2 0 "0"
-> 6 0.000000 17 2 0 "5"
-> 6 0.000000 18 2 0 "145"
-> 6 0.000000 19 2 0 "10"
-> 6 0.000000 20 2 0 "11"
-> 6 0.000000 21 2 0 "16"
-> 6 0.000000 22 2 0 "17"
-> 6 0.000000 23 2 0 "44"
-> 6 0.000000 24 2 0 "47"
-> 6 0.000000 25 2 0 "54"
-> 6 0.000000 26 2 0 "56"
-> 6 0.000000 27 2 0 "59"
-> 6 0.000000 28 2 0 "78"
-> 6 0.000000 29 2 0 "79"
-> 6 0.000000 30 2 0 "80"
-> 6 0.000000 31 2 0 "loopback"
-> 4 3 0 2 2 0-LINK2-LINK2
-> 4 4 0 1 2 0-HOST1-LINK2
-> 4 5 0 2 1 0-LINK2-HOST1
-> 15 0.000000 3 0 topology 12 0
-> 16 0.000000 3 0 topology 16 0
-> 15 0.000000 3 0 topology 9 1
-> 16 0.000000 3 0 topology 16 1
-> 15 0.000000 3 0 topology 16 2
-> 16 0.000000 3 0 topology 14 2
-> 15 0.000000 3 0 topology 21 3
-> 16 0.000000 3 0 topology 19 3
-> 15 0.000000 3 0 topology 8 4
-> 16 0.000000 3 0 topology 19 4
-> 15 0.000000 3 0 topology 19 5
-> 16 0.000000 3 0 topology 20 5
-> 15 0.000000 3 0 topology 8 6
-> 16 0.000000 3 0 topology 20 6
-> 15 0.000000 3 0 topology 27 7
-> 16 0.000000 3 0 topology 18 7
-> 15 0.000000 4 0 topology 5 8
-> 16 0.000000 4 0 topology 18 8
-> 15 0.000000 4 0 topology 4 9
-> 16 0.000000 4 0 topology 18 9
-> 15 0.000000 4 0 topology 2 10
-> 16 0.000000 4 0 topology 18 10
-> 15 0.000000 3 0 topology 16 11
-> 16 0.000000 3 0 topology 21 11
-> 15 0.000000 3 0 topology 21 12
-> 16 0.000000 3 0 topology 22 12
-> 15 0.000000 3 0 topology 9 13
-> 16 0.000000 3 0 topology 12 13
-> 15 0.000000 3 0 topology 15 14
-> 16 0.000000 3 0 topology 9 14
-> 15 0.000000 4 0 topology 1 15
-> 16 0.000000 4 0 topology 9 15
-> 15 0.000000 3 0 topology 20 16
-> 16 0.000000 3 0 topology 23 16
-> 15 0.000000 3 0 topology 23 17
-> 16 0.000000 3 0 topology 24 17
-> 15 0.000000 4 0 topology 5 18
-> 16 0.000000 4 0 topology 24 18
-> 15 0.000000 4 0 topology 4 19
-> 16 0.000000 4 0 topology 24 19
-> 15 0.000000 4 0 topology 2 20
-> 16 0.000000 4 0 topology 24 20
-> 15 0.000000 3 0 topology 11 21
-> 16 0.000000 3 0 topology 15 21
-> 15 0.000000 4 0 topology 1 22
-> 16 0.000000 4 0 topology 15 22
-> 15 0.000000 3 0 topology 12 23
-> 16 0.000000 3 0 topology 17 23
-> 15 0.000000 3 0 topology 9 24
-> 16 0.000000 3 0 topology 17 24
-> 15 0.000000 3 0 topology 22 25
-> 16 0.000000 3 0 topology 25 25
-> 15 0.000000 3 0 topology 12 26
-> 16 0.000000 3 0 topology 25 26
-> 15 0.000000 3 0 topology 25 27
-> 16 0.000000 3 0 topology 26 27
-> 15 0.000000 3 0 topology 26 28
-> 16 0.000000 3 0 topology 27 28
-> 15 0.000000 3 0 topology 14 29
-> 16 0.000000 3 0 topology 8 29
-> 15 0.000000 3 0 topology 13 30
-> 16 0.000000 3 0 topology 8 30
-> 15 0.000000 3 0 topology 11 31
-> 16 0.000000 3 0 topology 8 31
-> 15 0.000000 3 0 topology 8 32
-> 16 0.000000 3 0 topology 10 32
-> 15 0.000000 3 0 topology 30 33
-> 16 0.000000 3 0 topology 28 33
-> 15 0.000000 4 0 topology 3 34
-> 16 0.000000 4 0 topology 28 34
-> 15 0.000000 3 0 topology 28 35
-> 16 0.000000 3 0 topology 29 35
-> 15 0.000000 4 0 topology 3 36
-> 16 0.000000 4 0 topology 30 36
-> 15 0.000000 3 0 topology 14 37
-> 16 0.000000 3 0 topology 13 37
-> 15 0.000000 3 0 topology 29 38
-> 16 0.000000 3 0 topology 11 38
-> 15 0.000000 4 0 topology 1 39
-> 16 0.000000 4 0 topology 11 39
-> 15 0.000000 5 0 topology 24 40
-> 16 0.000000 5 0 topology 7 40
-> 15 0.000000 5 0 topology 10 41
-> 16 0.000000 5 0 topology 5 41
-> 15 0.000000 5 0 topology 13 42
-> 16 0.000000 5 0 topology 3 42
-> 15 0.000000 5 0 topology 17 43
-> 16 0.000000 5 0 topology 4 43
-> 15 0.000000 5 0 topology 18 44
-> 16 0.000000 5 0 topology 6 44
-> 15 0.000000 5 0 topology 11 45
-> 16 0.000000 5 0 topology 2 45
-> 0 6 1 ACTOR
-> 6 0.000000 32 6 3 "emigrant-1"
-> 2 7 6 ACTOR_STATE
-> 5 8 7 suspend "1 0 1"
-> 5 9 7 sleep "1 1 0"
-> 5 10 7 receive "1 0 0"
-> 5 11 7 send "0 0 1"
-> 5 12 7 execute "0 1 1"
-> 4 13 0 6 6 ACTOR_LINK
-> 6 0.000000 33 6 1 "policeman-2"
-> 12 0.000000 7 32 9
-> 12 0.000000 7 33 11
-> 13 2.000000 7 32
-> 12 2.000000 7 32 10
-> 13 2.025708 7 33
-> 12 2.025708 7 33 11
-> 13 2.025708 7 32
-> 15 2.025708 13 0 M 32 0
-> 7 2.025708 6 32
-> 6 2.025708 34 6 1 "emigrant-1"
-> 16 2.025708 13 0 M 34 0
-> 12 2.025708 7 34 9
-> 13 4.025708 7 34
-> 12 4.025708 7 34 10
-> 13 4.025903 7 33
-> 12 4.025903 7 33 11
-> 13 4.025903 7 34
-> 15 4.025903 13 0 M 34 1
-> 7 4.025903 6 34
-> 6 4.025903 35 6 2 "emigrant-1"
-> 16 4.025903 13 0 M 35 1
-> 12 4.025903 7 35 9
-> 13 6.025903 7 35
-> 12 6.025903 7 35 10
-> 13 6.044918 7 33
-> 12 6.044918 7 33 11
-> 13 6.044918 7 35
-> 15 6.044918 13 0 M 35 2
-> 7 6.044918 6 35
-> 6 6.044918 36 6 3 "emigrant-1"
-> 16 6.044918 13 0 M 36 2
-> 12 6.044918 7 36 9
-> 13 8.044918 7 36
-> 12 8.044918 7 36 10
-> 13 8.070626 7 33
-> 12 8.070626 7 33 11
-> 13 8.070626 7 36
-> 15 8.070626 13 0 M 36 3
-> 7 8.070626 6 36
-> 6 8.070626 37 6 4 "emigrant-1"
-> 16 8.070626 13 0 M 37 3
-> 12 8.070626 7 37 9
-> 13 10.070626 7 37
-> 12 10.070626 7 37 10
-> 13 10.087178 7 33
-> 12 10.087178 7 33 11
-> 13 10.087178 7 37
-> 15 10.087178 13 0 M 37 4
-> 7 10.087178 6 37
-> 6 10.087178 38 6 5 "emigrant-1"
-> 16 10.087178 13 0 M 38 4
-> 12 10.087178 7 38 9
-> 13 12.087178 7 38
-> 12 12.087178 7 38 10
-> 13 12.112617 7 33
-> 12 12.112617 7 33 11
-> 13 12.112617 7 38
-> 15 12.112617 13 0 M 38 5
-> 7 12.112617 6 38
-> 6 12.112617 39 6 3 "emigrant-1"
-> 16 12.112617 13 0 M 39 5
-> 12 12.112617 7 39 9
-> 13 14.112617 7 39
-> 12 14.112617 7 39 10
-> 13 14.138325 7 33
-> 12 14.138325 7 33 11
-> 13 14.138325 7 39
-> 15 14.138325 13 0 M 39 6
-> 7 14.138325 6 39
-> 6 14.138325 40 6 1 "emigrant-1"
-> 16 14.138325 13 0 M 40 6
-> 12 14.138325 7 40 9
-> 13 16.138325 7 40
-> 12 16.138325 7 40 10
-> 13 16.138521 7 33
-> 12 16.138521 7 33 11
-> 13 16.138521 7 40
-> 15 16.138521 13 0 M 40 7
-> 7 16.138521 6 40
-> 6 16.138521 41 6 4 "emigrant-1"
-> 16 16.138521 13 0 M 41 7
-> 12 16.138521 7 41 9
-> 13 18.138521 7 41
-> 12 18.138521 7 41 10
-> 13 18.155073 7 33
-> 13 18.155073 7 41
-> 7 18.155073 6 33
-> 7 18.155073 6 41
-> 7 18.155073 2 16
-> 7 18.155073 2 14
-> 7 18.155073 2 19
-> 7 18.155073 2 20
-> 7 18.155073 2 18
-> 7 18.155073 2 21
-> 7 18.155073 2 22
-> 7 18.155073 2 12
-> 7 18.155073 2 9
-> 7 18.155073 2 15
-> 7 18.155073 2 23
-> 7 18.155073 2 24
-> 7 18.155073 2 17
-> 7 18.155073 2 25
-> 7 18.155073 2 26
-> 7 18.155073 2 27
-> 7 18.155073 2 8
-> 7 18.155073 2 10
-> 7 18.155073 2 28
-> 7 18.155073 2 29
-> 7 18.155073 2 13
-> 7 18.155073 2 30
-> 7 18.155073 2 11
+> 0 6 0 LINK
+> 6 0.000000 8 6 0 "6"
+> 6 0.000000 9 6 0 "3"
+> 6 0.000000 10 6 0 "7"
+> 6 0.000000 11 6 0 "9"
+> 6 0.000000 12 6 0 "2"
+> 6 0.000000 13 6 0 "8"
+> 6 0.000000 14 6 0 "1"
+> 6 0.000000 15 6 0 "4"
+> 6 0.000000 16 6 0 "0"
+> 6 0.000000 17 6 0 "5"
+> 6 0.000000 18 6 0 "145"
+> 6 0.000000 19 6 0 "10"
+> 6 0.000000 20 6 0 "11"
+> 6 0.000000 21 6 0 "16"
+> 6 0.000000 22 6 0 "17"
+> 6 0.000000 23 6 0 "44"
+> 6 0.000000 24 6 0 "47"
+> 6 0.000000 25 6 0 "54"
+> 6 0.000000 26 6 0 "56"
+> 6 0.000000 27 6 0 "59"
+> 6 0.000000 28 6 0 "78"
+> 6 0.000000 29 6 0 "79"
+> 6 0.000000 30 6 0 "80"
+> 6 0.000000 31 6 0 "loopback"
+> 4 7 0 6 6 0-LINK6-LINK6
+> 4 8 0 1 6 0-HOST1-LINK6
+> 4 9 0 6 1 0-LINK6-HOST1
+> 15 0.000000 7 0 topology 12 0
+> 16 0.000000 7 0 topology 16 0
+> 15 0.000000 7 0 topology 9 1
+> 16 0.000000 7 0 topology 16 1
+> 15 0.000000 7 0 topology 16 2
+> 16 0.000000 7 0 topology 14 2
+> 15 0.000000 7 0 topology 21 3
+> 16 0.000000 7 0 topology 19 3
+> 15 0.000000 7 0 topology 8 4
+> 16 0.000000 7 0 topology 19 4
+> 15 0.000000 7 0 topology 19 5
+> 16 0.000000 7 0 topology 20 5
+> 15 0.000000 7 0 topology 8 6
+> 16 0.000000 7 0 topology 20 6
+> 15 0.000000 7 0 topology 27 7
+> 16 0.000000 7 0 topology 18 7
+> 15 0.000000 8 0 topology 5 8
+> 16 0.000000 8 0 topology 18 8
+> 15 0.000000 8 0 topology 4 9
+> 16 0.000000 8 0 topology 18 9
+> 15 0.000000 8 0 topology 2 10
+> 16 0.000000 8 0 topology 18 10
+> 15 0.000000 7 0 topology 16 11
+> 16 0.000000 7 0 topology 21 11
+> 15 0.000000 7 0 topology 21 12
+> 16 0.000000 7 0 topology 22 12
+> 15 0.000000 7 0 topology 9 13
+> 16 0.000000 7 0 topology 12 13
+> 15 0.000000 7 0 topology 15 14
+> 16 0.000000 7 0 topology 9 14
+> 15 0.000000 8 0 topology 1 15
+> 16 0.000000 8 0 topology 9 15
+> 15 0.000000 7 0 topology 20 16
+> 16 0.000000 7 0 topology 23 16
+> 15 0.000000 7 0 topology 23 17
+> 16 0.000000 7 0 topology 24 17
+> 15 0.000000 8 0 topology 5 18
+> 16 0.000000 8 0 topology 24 18
+> 15 0.000000 8 0 topology 4 19
+> 16 0.000000 8 0 topology 24 19
+> 15 0.000000 8 0 topology 2 20
+> 16 0.000000 8 0 topology 24 20
+> 15 0.000000 7 0 topology 11 21
+> 16 0.000000 7 0 topology 15 21
+> 15 0.000000 8 0 topology 1 22
+> 16 0.000000 8 0 topology 15 22
+> 15 0.000000 7 0 topology 12 23
+> 16 0.000000 7 0 topology 17 23
+> 15 0.000000 7 0 topology 9 24
+> 16 0.000000 7 0 topology 17 24
+> 15 0.000000 7 0 topology 22 25
+> 16 0.000000 7 0 topology 25 25
+> 15 0.000000 7 0 topology 12 26
+> 16 0.000000 7 0 topology 25 26
+> 15 0.000000 7 0 topology 25 27
+> 16 0.000000 7 0 topology 26 27
+> 15 0.000000 7 0 topology 26 28
+> 16 0.000000 7 0 topology 27 28
+> 15 0.000000 7 0 topology 14 29
+> 16 0.000000 7 0 topology 8 29
+> 15 0.000000 7 0 topology 13 30
+> 16 0.000000 7 0 topology 8 30
+> 15 0.000000 7 0 topology 11 31
+> 16 0.000000 7 0 topology 8 31
+> 15 0.000000 7 0 topology 8 32
+> 16 0.000000 7 0 topology 10 32
+> 15 0.000000 7 0 topology 30 33
+> 16 0.000000 7 0 topology 28 33
+> 15 0.000000 8 0 topology 3 34
+> 16 0.000000 8 0 topology 28 34
+> 15 0.000000 7 0 topology 28 35
+> 16 0.000000 7 0 topology 29 35
+> 15 0.000000 8 0 topology 3 36
+> 16 0.000000 8 0 topology 30 36
+> 15 0.000000 7 0 topology 14 37
+> 16 0.000000 7 0 topology 13 37
+> 15 0.000000 7 0 topology 29 38
+> 16 0.000000 7 0 topology 11 38
+> 15 0.000000 8 0 topology 1 39
+> 16 0.000000 8 0 topology 11 39
+> 15 0.000000 9 0 topology 24 40
+> 16 0.000000 9 0 topology 7 40
+> 15 0.000000 9 0 topology 10 41
+> 16 0.000000 9 0 topology 5 41
+> 15 0.000000 9 0 topology 13 42
+> 16 0.000000 9 0 topology 3 42
+> 15 0.000000 9 0 topology 17 43
+> 16 0.000000 9 0 topology 4 43
+> 15 0.000000 9 0 topology 18 44
+> 16 0.000000 9 0 topology 6 44
+> 15 0.000000 9 0 topology 11 45
+> 16 0.000000 9 0 topology 2 45
+> 0 10 1 ACTOR
+> 6 0.000000 32 10 3 "emigrant-1"
+> 2 11 10 ACTOR_STATE
+> 5 12 11 suspend "1 0 1"
+> 5 13 11 sleep "1 1 0"
+> 5 14 11 receive "1 0 0"
+> 5 15 11 send "0 0 1"
+> 5 16 11 execute "0 1 1"
+> 4 17 0 10 10 ACTOR_LINK
+> 6 0.000000 33 10 1 "policeman-2"
+> 12 0.000000 11 32 13
+> 12 0.000000 11 33 15
+> 13 2.000000 11 32
+> 12 2.000000 11 32 14
+> 13 2.025708 11 33
+> 13 2.025708 11 32
+> 12 2.025708 11 33 15
+> 15 2.025708 17 0 M 32 0
+> 7 2.025708 10 32
+> 6 2.025708 34 10 1 "emigrant-1"
+> 16 2.025708 17 0 M 34 0
+> 12 2.025708 11 34 13
+> 13 4.025708 11 34
+> 12 4.025708 11 34 14
+> 13 4.025903 11 33
+> 13 4.025903 11 34
+> 12 4.025903 11 33 15
+> 15 4.025903 17 0 M 34 1
+> 7 4.025903 10 34
+> 6 4.025903 35 10 2 "emigrant-1"
+> 16 4.025903 17 0 M 35 1
+> 12 4.025903 11 35 13
+> 13 6.025903 11 35
+> 12 6.025903 11 35 14
+> 13 6.044918 11 33
+> 13 6.044918 11 35
+> 12 6.044918 11 33 15
+> 15 6.044918 17 0 M 35 2
+> 7 6.044918 10 35
+> 6 6.044918 36 10 3 "emigrant-1"
+> 16 6.044918 17 0 M 36 2
+> 12 6.044918 11 36 13
+> 13 8.044918 11 36
+> 12 8.044918 11 36 14
+> 13 8.070626 11 33
+> 13 8.070626 11 36
+> 12 8.070626 11 33 15
+> 15 8.070626 17 0 M 36 3
+> 7 8.070626 10 36
+> 6 8.070626 37 10 4 "emigrant-1"
+> 16 8.070626 17 0 M 37 3
+> 12 8.070626 11 37 13
+> 13 10.070626 11 37
+> 12 10.070626 11 37 14
+> 13 10.087178 11 33
+> 13 10.087178 11 37
+> 12 10.087178 11 33 15
+> 15 10.087178 17 0 M 37 4
+> 7 10.087178 10 37
+> 6 10.087178 38 10 5 "emigrant-1"
+> 16 10.087178 17 0 M 38 4
+> 12 10.087178 11 38 13
+> 13 12.087178 11 38
+> 12 12.087178 11 38 14
+> 13 12.112617 11 33
+> 13 12.112617 11 38
+> 12 12.112617 11 33 15
+> 15 12.112617 17 0 M 38 5
+> 7 12.112617 10 38
+> 6 12.112617 39 10 3 "emigrant-1"
+> 16 12.112617 17 0 M 39 5
+> 12 12.112617 11 39 13
+> 13 14.112617 11 39
+> 12 14.112617 11 39 14
+> 13 14.138325 11 33
+> 13 14.138325 11 39
+> 12 14.138325 11 33 15
+> 15 14.138325 17 0 M 39 6
+> 7 14.138325 10 39
+> 6 14.138325 40 10 1 "emigrant-1"
+> 16 14.138325 17 0 M 40 6
+> 12 14.138325 11 40 13
+> 13 16.138325 11 40
+> 12 16.138325 11 40 14
+> 13 16.138521 11 33
+> 13 16.138521 11 40
+> 12 16.138521 11 33 15
+> 15 16.138521 17 0 M 40 7
+> 7 16.138521 10 40
+> 6 16.138521 41 10 4 "emigrant-1"
+> 16 16.138521 17 0 M 41 7
+> 12 16.138521 11 41 13
+> 13 18.138521 11 41
+> 12 18.138521 11 41 14
+> 13 18.155073 11 33
+> 13 18.155073 11 41
+> 7 18.155073 10 33
+> 7 18.155073 10 41
+> 7 18.155073 6 16
+> 7 18.155073 6 14
+> 7 18.155073 6 19
+> 7 18.155073 6 20
+> 7 18.155073 6 18
+> 7 18.155073 6 21
+> 7 18.155073 6 22
+> 7 18.155073 6 12
+> 7 18.155073 6 9
+> 7 18.155073 6 15
+> 7 18.155073 6 23
+> 7 18.155073 6 24
+> 7 18.155073 6 17
+> 7 18.155073 6 25
+> 7 18.155073 6 26
+> 7 18.155073 6 27
+> 7 18.155073 6 8
+> 7 18.155073 6 10
+> 7 18.155073 6 28
+> 7 18.155073 6 29
+> 7 18.155073 6 13
+> 7 18.155073 6 30
+> 7 18.155073 6 11
 > 7 18.155073 1 7
 > 7 18.155073 1 5
 > 7 18.155073 1 3
@@ -371,6 +375,6 @@ $ tail -n +3 procmig.trace
 > 7 18.155073 1 6
 > 7 18.155073 1 2
 > 7 18.155073 1 1
-> 7 18.155073 2 31
+> 7 18.155073 6 31
 
 $ rm -f procmig.trace
index 8adfdc0..04a83e6 100644 (file)
@@ -16,18 +16,17 @@ namespace sg4 = simgrid::s4u;
  * @param root Root netzone
  * @param name Cabinet name
  * @param radicals IDs of nodes inside the cabinet
- * @return netzone,router the created netzone and its router
+ * @return netzone the created netzone
  */
-static std::pair<sg4::NetZone*, simgrid::kernel::routing::NetPoint*>
+static sg4::NetZone*
 create_cabinet(const sg4::NetZone* root, const std::string& name, const std::vector<int>& radicals)
 {
-  auto* cluster      = sg4::create_star_zone(name);
+  auto* cluster      = sg4::create_star_zone(name)->set_parent(root);
   std::string prefix = "griffon-";
   std::string suffix = ".nancy.grid5000.fr";
-  cluster->set_parent(root);
 
   /* create the backbone link */
-  const sg4::Link* l_bb = cluster->create_link("backbone-" + name, "1.25GBps")->seal();
+  const sg4::Link* l_bb = cluster->create_link("backbone-" + name, "1.25GBps");
   sg4::LinkInRoute backbone(l_bb);
 
   /* create all hosts and connect them to outside world */
@@ -36,18 +35,17 @@ create_cabinet(const sg4::NetZone* root, const std::string& name, const std::vec
     /* create host */
     const sg4::Host* host = cluster->create_host(hostname, "286.087kf");
     /* create UP/DOWN link */
-    const sg4::Link* link = cluster->create_split_duplex_link(hostname, "125MBps")->set_latency("24us")->seal();
+    const sg4::Link* link = cluster->create_split_duplex_link(hostname, "125MBps")->set_latency("24us");
 
     /* add link and backbone for communications from the host */
-    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr,
-                       {{link, sg4::LinkInRoute::Direction::UP}, backbone}, true);
+    cluster->add_route(host, nullptr, {{link, sg4::LinkInRoute::Direction::UP}, backbone}, true);
   }
 
-  /* create router */
-  auto* router = cluster->create_router(prefix + name + "-router" + suffix);
+  /* create gateway */
+  cluster->set_gateway(cluster->create_router(prefix + name + "-router" + suffix));
 
   cluster->seal();
-  return std::make_pair(cluster, router);
+  return cluster;
 }
 
 /** @brief Programmatic version of griffon.xml */
@@ -75,7 +73,6 @@ void load_platform(const sg4::Engine& /*e*/)
 
   auto* root = sg4::create_star_zone("AS_griffon");
   sg4::NetZone* cab_zone;
-  simgrid::kernel::routing::NetPoint* router;
 
   /* create top link */
   const sg4::Link* l_bb = root->create_link("backbone", "1.25GBps")->set_latency("24us")->seal();
@@ -84,23 +81,23 @@ void load_platform(const sg4::Engine& /*e*/)
   /* create cabinet1 */
   std::vector<int> rad(32);
   std::iota(rad.begin(), rad.end(), 1); // 1-29,58,59,60
-  rad[rad.size() - 1]        = 60;
-  rad[rad.size() - 2]        = 59;
-  rad[rad.size() - 3]        = 58;
-  std::tie(cab_zone, router) = create_cabinet(root, "cabinet1", rad);
-  root->add_route(cab_zone->get_netpoint(), nullptr, router, nullptr, {backbone});
+  rad[rad.size() - 1]  = 60;
+  rad[rad.size() - 2]  = 59;
+  rad[rad.size() - 3]  = 58;
+  cab_zone             = create_cabinet(root, "cabinet1", rad);
+  root->add_route(cab_zone, nullptr, {backbone});
 
   /* create cabinet2 */
   rad.resize(28);
   std::iota(rad.begin(), rad.end(), 30); // 30-57
-  std::tie(cab_zone, router) = create_cabinet(root, "cabinet2", rad);
-  root->add_route(cab_zone->get_netpoint(), nullptr, router, nullptr, {backbone});
+  cab_zone = create_cabinet(root, "cabinet2", rad);
+  root->add_route(cab_zone, nullptr, {backbone});
 
   /* create cabinet3 */
   rad.resize(32);
   std::iota(rad.begin(), rad.end(), 61); // 61-92
-  std::tie(cab_zone, router) = create_cabinet(root, "cabinet3", rad);
-  root->add_route(cab_zone->get_netpoint(), nullptr, router, nullptr, {backbone});
+  cab_zone = create_cabinet(root, "cabinet3", rad);
+  root->add_route(cab_zone, nullptr, {backbone});
 
   root->seal();
 }
index f3bd3cc..b7b218f 100644 (file)
@@ -16,40 +16,40 @@ namespace sg4 = simgrid::s4u;
  * @param host List of hostname inside the cluster
  * @param single_link_host Hostname of "special" node
  */
-static void create_cluster(const sg4::NetZone* root, const std::string& cluster_suffix,
+static sg4::NetZone* create_cluster(const sg4::NetZone* root, const std::string& cluster_suffix,
                            const std::vector<std::string>& hosts, const std::string& single_link_host)
 {
-  auto* cluster = sg4::create_star_zone("cluster" + cluster_suffix);
-  cluster->set_parent(root);
+  auto* cluster = sg4::create_star_zone("cluster" + cluster_suffix)->set_parent(root);
 
   /* create the backbone link */
-  const sg4::Link* l_bb = cluster->create_link("backbone" + cluster_suffix, 2.25e9)->set_latency(5e-4)->seal();
+  const sg4::Link* l_bb = cluster->create_link("backbone" + cluster_suffix, "20Gbps")->set_latency("500us");
 
   /* create all hosts and connect them to outside world */
   for (const auto& hostname : hosts) {
     /* create host */
-    const sg4::Host* host = cluster->create_host(hostname, 1e9);
+    const sg4::Host* host = cluster->create_host(hostname, "1Gf");
     /* create UP link */
-    const sg4::Link* l_up = cluster->create_link(hostname + "_up", 1.25e8)->set_latency(0.0001)->seal();
+    const sg4::Link* l_up = cluster->create_link(hostname + "_up", "1Gbps")->set_latency("100us");
     /* create DOWN link, if needed */
     const sg4::Link* l_down = l_up;
     if (hostname != single_link_host) {
-      l_down = cluster->create_link(hostname + "_down", 1.25e8)->set_latency(0.0001)->seal();
+      l_down = cluster->create_link(hostname + "_down", "1Gbps")->set_latency("100us");
     }
     sg4::LinkInRoute backbone{l_bb};
     sg4::LinkInRoute link_up{l_up};
     sg4::LinkInRoute link_down{l_down};
 
     /* add link UP and backbone for communications from the host */
-    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, {link_up, backbone}, false);
+    cluster->add_route(host, nullptr, {link_up, backbone}, false);
     /* add backbone and link DOWN for communications to the host */
-    cluster->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, {backbone, link_down}, false);
+    cluster->add_route(nullptr, host, {backbone, link_down}, false);
   }
 
-  /* create router */
-  cluster->create_router("router" + cluster_suffix);
+  /* create gateway*/
+  cluster->set_gateway(cluster->create_router("router" + cluster_suffix));
 
   cluster->seal();
+  return cluster;
 }
 
 /** @brief Programmatic version of routing_cluster.xml */
@@ -76,15 +76,14 @@ void load_platform(const sg4::Engine& e)
   auto* root = sg4::create_full_zone("AS0");
 
   /* create left cluster */
-  create_cluster(root, "1", {"host1", "host2", "host3"}, "host3");
+  auto* left_cluster = create_cluster(root, "1", {"host1", "host2", "host3"}, "host3");
   /* create right cluster */
-  create_cluster(root, "2", {"host4", "host5", "host6"}, "host6");
+  auto* right_cluster = create_cluster(root, "2", {"host4", "host5", "host6"}, "host6");
 
-  /* connect both cluster through their respective routers */
-  const sg4::Link* l = root->create_link("link1-2", 2.25e9)->set_latency(5e-4)->seal();
+  /* connect both clusters */
+  const sg4::Link* l = root->create_link("link1-2", "20Gbps")->set_latency("500us");
   sg4::LinkInRoute link{l};
-  root->add_route(e.netpoint_by_name_or_null("cluster1"), e.netpoint_by_name_or_null("cluster2"),
-                  e.netpoint_by_name_or_null("router1"), e.netpoint_by_name_or_null("router2"), {link});
+  root->add_route(left_cluster, right_cluster, {link});
 
   root->seal();
 }
index aa9089e..033abe9 100644 (file)
@@ -26,8 +26,7 @@ static std::string int_string(int n)
  */
 static sg4::NetZone* create_node(const sg4::NetZone* root, const std::string& node_name, const int nb_cpu)
 {
-  auto* node = sg4::create_star_zone(node_name);
-  node->set_parent(root);
+  auto* node = sg4::create_star_zone(node_name)->set_parent(root);
 
   /* create all hosts and connect them to outside world */
   for (int i = 0; i < nb_cpu; i++) {
@@ -35,9 +34,8 @@ static sg4::NetZone* create_node(const sg4::NetZone* root, const std::string& no
     const auto& linkname = "link_" + cpuname;
 
     const sg4::Host* host = node->create_host(cpuname, 1e9);
-    const sg4::Link* l    = node->create_split_duplex_link(linkname, BW_CPU)->set_latency(LAT_CPU)->seal();
-
-    node->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, {{l, sg4::LinkInRoute::Direction::UP}}, true);
+    const sg4::Link* l    = node->create_split_duplex_link(linkname, BW_CPU)->set_latency(LAT_CPU);
+    node->add_route(host, nullptr, {{l, sg4::LinkInRoute::Direction::UP}}, true);
   }
 
   return node;
@@ -50,8 +48,7 @@ static sg4::NetZone* create_node(const sg4::NetZone* root, const std::string& no
 static sg4::NetZone* create_supernode(const sg4::NetZone* root, const std::string& supernode_name, const int nb_nodes,
                                       const int nb_cpu)
 {
-  auto* supernode = sg4::create_star_zone(supernode_name);
-  supernode->set_parent(root);
+  auto* supernode = sg4::create_star_zone(supernode_name)->set_parent(root);
 
   /* create all nodes and connect them to outside world */
   for (int i = 0; i < nb_nodes; i++) {
@@ -59,11 +56,11 @@ static sg4::NetZone* create_supernode(const sg4::NetZone* root, const std::strin
     const auto& linkname  = "link_" + node_name;
 
     sg4::NetZone* node = create_node(supernode, node_name, nb_cpu);
-    const auto router  = node->create_router("router_" + node_name);
+    node->set_gateway(node->create_router("router_" + node_name));
     node->seal();
 
-    const sg4::Link* l = supernode->create_split_duplex_link(linkname, BW_NODE)->set_latency(LAT_NODE)->seal();
-    supernode->add_route(node->get_netpoint(), nullptr, router, nullptr, {{l, sg4::LinkInRoute::Direction::UP}}, true);
+    const sg4::Link* l = supernode->create_split_duplex_link(linkname, BW_NODE)->set_latency(LAT_NODE);
+    supernode->add_route(node, nullptr, {{l, sg4::LinkInRoute::Direction::UP}}, true);
   }
   return supernode;
 }
@@ -83,12 +80,11 @@ static sg4::NetZone* create_cluster(const std::string& cluster_name, const int n
     const auto& linkname       = "link_" + supernode_name;
 
     sg4::NetZone* supernode = create_supernode(cluster, supernode_name, nb_nodes, nb_cpu);
-    const auto router       = supernode->create_router("router_" + supernode_name);
+    supernode->set_gateway(supernode->create_router("router_" + supernode_name));
     supernode->seal();
 
-    const sg4::Link* l = cluster->create_split_duplex_link(linkname, BW_NETWORK)->set_latency(LAT_NETWORK)->seal();
-    cluster->add_route(supernode->get_netpoint(), nullptr, router, nullptr, {{l, sg4::LinkInRoute::Direction::UP}},
-                       true);
+    const sg4::Link* l = cluster->create_split_duplex_link(linkname, BW_NETWORK)->set_latency(LAT_NETWORK);
+    cluster->add_route(supernode, nullptr, {{l, sg4::LinkInRoute::Direction::UP}}, true);
   }
   return cluster;
 }
index d2bb58a..3705f47 100644 (file)
@@ -1,9 +1,12 @@
 foreach(example actor-create actor-daemon actor-join actor-kill actor-migrate actor-suspend actor-yield actor-lifetime
+        activityset-testany activityset-waitall activityset-waitallfor activityset-waitany
         app-masterworkers
-        comm-wait comm-waitall comm-waitallfor comm-waitany comm-failure comm-host2host comm-pingpong
-        comm-ready comm-suspend comm-testany comm-throttling comm-waitallfor comm-waituntil
+        comm-wait comm-failure comm-host2host comm-pingpong
+        comm-ready comm-suspend comm-throttling comm-waituntil
         exec-async exec-basic exec-dvfs exec-remote exec-ptask
+        task-io task-simple task-switch-host task-variable-load
         platform-comm-serialize platform-profile platform-failures
+        plugin-host-load
         network-nonlinear clusters-multicpu io-degradation exec-cpu-nonlinear
         synchro-barrier synchro-mutex synchro-semaphore)
   set(tesh_files    ${tesh_files}   ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.tesh)
diff --git a/examples/python/activityset-testany/activityset-testany.py b/examples/python/activityset-testany/activityset-testany.py
new file mode 100644 (file)
index 0000000..6a8901f
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+"""
+Usage: activityset-testany.py platform_file [other parameters]
+"""
+
+import sys
+from simgrid import Actor, ActivitySet, Engine, Comm, Exec, Io, Host, Mailbox, this_actor
+
+def bob():
+  mbox = Mailbox.by_name("mbox")
+  disk = Host.current().get_disks()[0]
+
+  this_actor.info("Create my asynchronous activities")
+  exec = this_actor.exec_async(5e9)
+  comm = mbox.get_async()
+  io   = disk.read_async(300000000)
+
+  pending_activities = ActivitySet([exec, comm])
+  pending_activities.push(io) # Activities can be pushed after creation, too
+  this_actor.info("Sleep_for a while")
+  this_actor.sleep_for(1)
+
+  this_actor.info("Test for completed activities")
+  while not pending_activities.empty():
+    completed_one = pending_activities.test_any()
+    if completed_one == None:
+      this_actor.info("Nothing matches, test again in 0.5s")
+      this_actor.sleep_for(.5)
+    elif isinstance(completed_one, Comm):
+      this_actor.info("Completed a Comm")
+    elif isinstance(completed_one, Exec):
+      this_actor.info("Completed an Exec")
+    elif isinstance(completed_one, Io):
+      this_actor.info("Completed an I/O")
+
+  this_actor.info("Last activity is complete")
+
+def alice():
+  this_actor.info("Send 'Message'")
+  Mailbox.by_name("mbox").put("Message", 600000000)
+
+if __name__ == '__main__':
+  e = Engine(sys.argv)
+  e.set_log_control("root.fmt:[%4.2r]%e[%5a]%e%m%n")
+
+  # Load the platform description
+  e.load_platform(sys.argv[1])
+
+  Actor.create("bob",   Host.by_name("bob"), bob)
+  Actor.create("alice", Host.by_name("alice"), alice)
+
+  e.run()
@@ -1,6 +1,6 @@
 #!/usr/bin/env tesh
 
-$ ${bindir:=.}/s4u-activity-testany ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%4.2r]%e[%5a]%e%m%n"
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/activityset-testany.py ${platfdir}/hosts_with_disks.xml
 > [0.00] [alice] Send 'Message'
 > [0.00] [  bob] Create my asynchronous activities
 > [0.00] [  bob] Sleep_for a while
diff --git a/examples/python/activityset-waitall/activityset-waitall.py b/examples/python/activityset-waitall/activityset-waitall.py
new file mode 100644 (file)
index 0000000..4e4d1ee
--- /dev/null
@@ -0,0 +1,44 @@
+# Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+"""
+Usage: activityset-waitall.py platform_file [other parameters]
+"""
+
+import sys
+from simgrid import Actor, ActivitySet, Engine, Comm, Exec, Io, Host, Mailbox, this_actor
+
+def bob():
+  mbox = Mailbox.by_name("mbox")
+  disk = Host.current().get_disks()[0]
+
+  this_actor.info("Create my asynchronous activities")
+  exec = this_actor.exec_async(5e9)
+  comm = mbox.get_async()
+  io   = disk.read_async(300000000)
+
+  pending_activities = ActivitySet([exec, comm])
+  pending_activities.push(io) # Activities can be pushed after creation, too
+  this_actor.info("Wait for asynchronous activities to complete, all in one shot.")
+  pending_activities.wait_all()
+
+  this_actor.info("All activities are completed.")
+
+def alice():
+  this_actor.info("Send 'Message'")
+  Mailbox.by_name("mbox").put("Message", 600000000)
+
+if __name__ == '__main__':
+  e = Engine(sys.argv)
+  e.set_log_control("root.fmt:[%4.6r]%e[%5a]%e%m%n")
+
+  # Load the platform description
+  e.load_platform(sys.argv[1])
+
+  Actor.create("bob",   Host.by_name("bob"), bob)
+  Actor.create("alice", Host.by_name("alice"), alice)
+
+  e.run()
diff --git a/examples/python/activityset-waitall/activityset-waitall.tesh b/examples/python/activityset-waitall/activityset-waitall.tesh
new file mode 100644 (file)
index 0000000..ab4b175
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env tesh
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/activityset-waitall.py ${platfdir}/hosts_with_disks.xml
+> [0.000000] [alice] Send 'Message'
+> [0.000000] [  bob] Create my asynchronous activities
+> [0.000000] [  bob] Wait for asynchronous activities to complete, all in one shot.
+> [5.197828] [  bob] All activities are completed.
diff --git a/examples/python/activityset-waitallfor/activityset-waitallfor.py b/examples/python/activityset-waitallfor/activityset-waitallfor.py
new file mode 100644 (file)
index 0000000..44b3c6f
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+"""
+Usage: activityset-waitallfor.py platform_file [other parameters]
+"""
+
+import sys
+from simgrid import Actor, ActivitySet, Engine, Comm, Exec, Io, Host, Mailbox, this_actor, TimeoutException
+
+def bob():
+  mbox = Mailbox.by_name("mbox")
+  disk = Host.current().get_disks()[0]
+
+  this_actor.info("Create my asynchronous activities")
+  exec = this_actor.exec_async(5e9)
+  comm = mbox.get_async()
+  io   = disk.read_async(300000000)
+
+  pending_activities = ActivitySet([exec, comm])
+  pending_activities.push(io) # Activities can be pushed after creation, too
+  this_actor.info("Wait for asynchronous activities to complete")
+  while not pending_activities.empty():
+    try:
+      pending_activities.wait_all_for(1)
+    except TimeoutException:
+      this_actor.info("Not all activities are terminated yet.")
+
+    completed_one = pending_activities.test_any()
+    while completed_one != None:
+      if isinstance(completed_one, Comm):
+        this_actor.info("Completed a Comm")
+      elif isinstance(completed_one, Exec):
+        this_actor.info("Completed an Exec")
+      elif isinstance(completed_one, Io):
+        this_actor.info("Completed an I/O")
+      completed_one = pending_activities.test_any()
+
+  this_actor.info("Last activity is complete")
+
+def alice():
+  this_actor.info("Send 'Message'")
+  Mailbox.by_name("mbox").put("Message", 600000000)
+
+if __name__ == '__main__':
+  e = Engine(sys.argv)
+  e.set_log_control("root.fmt:[%4.6r]%e[%5a]%e%m%n")
+
+  # Load the platform description
+  e.load_platform(sys.argv[1])
+
+  Actor.create("bob",   Host.by_name("bob"), bob)
+  Actor.create("alice", Host.by_name("alice"), alice)
+
+  e.run()
diff --git a/examples/python/activityset-waitallfor/activityset-waitallfor.tesh b/examples/python/activityset-waitallfor/activityset-waitallfor.tesh
new file mode 100644 (file)
index 0000000..cf08947
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/env tesh
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/activityset-waitallfor.py ${platfdir}/hosts_with_disks.xml
+> [0.000000] [alice] Send 'Message'
+> [0.000000] [  bob] Create my asynchronous activities
+> [0.000000] [  bob] Wait for asynchronous activities to complete
+> [1.000000] [  bob] Not all activities are terminated yet.
+> [2.000000] [  bob] Not all activities are terminated yet.
+> [3.000000] [  bob] Not all activities are terminated yet.
+> [3.000000] [  bob] Completed an I/O
+> [4.000000] [  bob] Not all activities are terminated yet.
+> [5.000000] [  bob] Not all activities are terminated yet.
+> [5.000000] [  bob] Completed an Exec
+> [5.197828] [  bob] Completed a Comm
+> [5.197828] [  bob] Last activity is complete
diff --git a/examples/python/activityset-waitany/activityset-waitany.py b/examples/python/activityset-waitany/activityset-waitany.py
new file mode 100644 (file)
index 0000000..88ac531
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+"""
+Usage: activityset-waitany.py platform_file [other parameters]
+"""
+
+import sys
+from simgrid import Actor, ActivitySet, Engine, Comm, Exec, Io, Host, Mailbox, this_actor
+
+def bob():
+  mbox = Mailbox.by_name("mbox")
+  disk = Host.current().get_disks()[0]
+
+  this_actor.info("Create my asynchronous activities")
+  exec = this_actor.exec_async(5e9)
+  comm = mbox.get_async()
+  io   = disk.read_async(300000000)
+
+  pending_activities = ActivitySet([exec, comm])
+  pending_activities.push(io) # Activities can be pushed after creation, too
+  this_actor.info("Wait for asynchronous activities to complete")
+  while not pending_activities.empty():
+    completed_one = pending_activities.wait_any()
+
+    if isinstance(completed_one, Comm):
+      this_actor.info("Completed a Comm")
+    elif isinstance(completed_one, Exec):
+      this_actor.info("Completed an Exec")
+    elif isinstance(completed_one, Io):
+      this_actor.info("Completed an I/O")
+
+  this_actor.info("Last activity is complete")
+
+def alice():
+  this_actor.info("Send 'Message'")
+  Mailbox.by_name("mbox").put("Message", 600000000)
+
+if __name__ == '__main__':
+  e = Engine(sys.argv)
+  e.set_log_control("root.fmt:[%4.6r]%e[%5a]%e%m%n")
+
+  # Load the platform description
+  e.load_platform(sys.argv[1])
+
+  Actor.create("bob",   Host.by_name("bob"), bob)
+  Actor.create("alice", Host.by_name("alice"), alice)
+
+  e.run()
@@ -1,9 +1,9 @@
 #!/usr/bin/env tesh
 
-$ ${bindir:=.}/s4u-activity-waitany ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%7.6r]%e[%5a]%e%m%n"
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/activityset-waitany.py ${platfdir}/hosts_with_disks.xml
 > [0.000000] [alice] Send 'Message'
 > [0.000000] [  bob] Create my asynchronous activities
-> [0.000000] [  bob] Wait for asynchrounous activities to complete
+> [0.000000] [  bob] Wait for asynchronous activities to complete
 > [3.000000] [  bob] Completed an I/O
 > [5.000000] [  bob] Completed an Exec
 > [5.197828] [  bob] Completed a Comm
index 8f7240a..6a4d783 100644 (file)
@@ -28,19 +28,19 @@ class Sender:
     # Actors that are created as object will execute their __call__ method.
     # So, the following constitutes the main function of the Sender actor.
     def __call__(self):
-        pending_comms = []
+        pending_comms = simgrid.ActivitySet()
         mboxes = []
 
         for host in self.hosts:
             msg = "Hello, I'm alive and running on " + simgrid.this_actor.get_host().name
             mbox = simgrid.Mailbox.by_name(host.name)
             mboxes.append(mbox)
-            pending_comms.append(mbox.put_async(msg, self.msg_size))
+            pending_comms.push(mbox.put_async(msg, self.msg_size))
 
         simgrid.this_actor.info("Done dispatching all messages")
 
         # Now that all message exchanges were initiated, wait for their completion in one single call
-        simgrid.Comm.wait_all(pending_comms)
+        pending_comms.wait_all()
 
         simgrid.this_actor.info("Goodbye now!")
 
@@ -58,8 +58,7 @@ class Receiver:
 #####################################################################################################
 
 
-def create_hostzone(zone: simgrid.NetZone, coord: typing.List[int], ident: int) -> typing.Tuple[simgrid.NetPoint,
-                                                                                                simgrid.NetPoint]:
+def create_hostzone(zone: simgrid.NetZone, coord: typing.List[int], ident: int) -> simgrid.NetZone:
     r"""
     Callback to set a cluster leaf/element
 
@@ -94,24 +93,22 @@ def create_hostzone(zone: simgrid.NetZone, coord: typing.List[int], ident: int)
     # setting my Torus parent zone
     host_zone.set_parent(zone)
 
-    gateway = None
     # create CPUs
     for i in range(num_cpus):
         cpu_name = hostname + "-cpu" + str(i)
         host = host_zone.create_host(cpu_name, speed).seal()
         # the first CPU is the gateway
         if i == 0:
-            gateway = host
+            host_zone.set_gateway(host.netpoint)
         # create split-duplex link
         link = host_zone.create_split_duplex_link("link-" + cpu_name, link_bw)
         link.set_latency(link_lat).seal()
         # connecting CPU to outer world
-        host_zone.add_route(host.netpoint, None, None, None,
-                            [simgrid.LinkInRoute(link, simgrid.LinkInRoute.Direction.UP)], True)
+        host_zone.add_route(host, None, [simgrid.LinkInRoute(link, simgrid.LinkInRoute.Direction.UP)], True)
 
     # seal newly created netzone
     host_zone.seal()
-    return host_zone.netpoint, gateway.netpoint
+    return host_zone
 
 #####################################################################################################
 
index 4b70b33..02cd701 100644 (file)
@@ -5,7 +5,7 @@
 
 import sys
 
-from simgrid import Engine, Actor, Comm, NetZone, Link, LinkInRoute, Mailbox, this_actor, NetworkFailureException
+from simgrid import Engine, Actor, ActivitySet, Comm, NetZone, Link, LinkInRoute, Mailbox, this_actor, NetworkFailureException
 
 
 def sender(mailbox1_name: str, mailbox2_name: str) -> None:
@@ -19,10 +19,10 @@ def sender(mailbox1_name: str, mailbox2_name: str) -> None:
     comm2: Comm = mailbox2.put_async(666, 2)
 
     this_actor.info("Calling wait_any..")
-    pending_comms = [comm1, comm2]
+    pending_comms = ActivitySet([comm1, comm2])
     try:
-        index = Comm.wait_any([comm1, comm2])
-        this_actor.info(f"Wait any returned index {index} (comm to {pending_comms[index].mailbox.name})")
+        comm = pending_comms.wait_any()
+        this_actor.info(f"Wait any returned a comm to {comm.mailbox.name})")
     except NetworkFailureException:
         this_actor.info("Sender has experienced a network failure exception, so it knows that something went wrong")
         this_actor.info("Now it needs to figure out which of the two comms failed by looking at their state:")
@@ -36,9 +36,8 @@ def sender(mailbox1_name: str, mailbox2_name: str) -> None:
         this_actor.info(f"Waiting on a FAILED comm raises an exception: '{err}'")
 
     this_actor.info("Wait for remaining comm, just to be nice")
-    pending_comms.pop(0)
     try:
-        Comm.wait_any(pending_comms)
+        pending_comms.wait_all()
     except Exception as e:
         this_actor.warning(str(e))
 
@@ -66,11 +65,11 @@ def main():
     host2 = zone.create_host("Host2", "1f")
     host3 = zone.create_host("Host3", "1f")
 
-    link_to_2 = LinkInRoute(zone.create_link("link_to_2", "1bps").seal())
-    link_to_3 = LinkInRoute(zone.create_link("link_to_3", "1bps").seal())
+    link_to_2 = zone.create_link("link_to_2", "1bps").seal()
+    link_to_3 = zone.create_link("link_to_3", "1bps").seal()
 
-    zone.add_route(host1.netpoint, host2.netpoint, None, None, [link_to_2], False)
-    zone.add_route(host1.netpoint, host3.netpoint, None, None, [link_to_3], False)
+    zone.add_route(host1, host2, [link_to_2])
+    zone.add_route(host1, host3, [link_to_3])
     zone.seal()
 
     Actor.create("Sender", host1, sender, "mailbox2", "mailbox3")
index ee26ae8..8f4de0e 100644 (file)
@@ -14,4 +14,4 @@ $ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-failure.py "-
 > [ 10.000000] (1:Sender@Host1)   Comm to mailbox3 has state: STARTED
 > [ 10.000000] (1:Sender@Host1) Waiting on a FAILED comm raises an exception: 'Cannot wait for a failed communication'
 > [ 10.000000] (1:Sender@Host1) Wait for remaining comm, just to be nice
-> [ 16.494845] (3:Receiver-2@Host3) Receiver has received successfully (mailbox3)!
+> [ 17.319588] (3:Receiver-2@Host3) Receiver has received successfully (mailbox3)!
index fa5f91e..2006532 100644 (file)
@@ -7,7 +7,7 @@ from argparse import ArgumentParser
 from typing import List
 import sys
 
-from simgrid import Actor, Comm, Engine, Mailbox, this_actor
+from simgrid import Actor, ActivitySet, Comm, Engine, Mailbox, this_actor
 
 
 FINALIZE_MESSAGE = "finalize"
@@ -31,7 +31,7 @@ def get_peer_mailbox(peer_id: int) -> Mailbox:
 def peer(my_id: int, message_count: int, payload_size: int, peers_count: int):
     my_mailbox: Mailbox = get_peer_mailbox(my_id)
     my_mailbox.set_receiver(Actor.self())
-    pending_comms: List[Comm] = []
+    pending_comms = ActivitySet()
     # Start dispatching all messages to peers others that myself
     for i in range(message_count):
         for peer_id in range(peers_count):
@@ -39,14 +39,14 @@ def peer(my_id: int, message_count: int, payload_size: int, peers_count: int):
                 peer_mailbox = get_peer_mailbox(peer_id)
                 message = f"Message {i} from peer {my_id}"
                 this_actor.info(f"Send '{message}' to '{peer_mailbox.name}'")
-                pending_comms.append(peer_mailbox.put_async(message, payload_size))
+                pending_comms.push(peer_mailbox.put_async(message, payload_size))
 
     # Start sending messages to let peers know that they should stop
     for peer_id in range(peers_count):
         if peer_id != my_id:
             peer_mailbox = get_peer_mailbox(peer_id)
             payload = str(FINALIZE_MESSAGE)
-            pending_comms.append(peer_mailbox.put_async(payload, payload_size))
+            pending_comms.push(peer_mailbox.put_async(payload, payload_size))
             this_actor.info(f"Send '{payload}' to '{peer_mailbox.name}'")
     this_actor.info("Done dispatching all messages")
 
@@ -58,7 +58,7 @@ def peer(my_id: int, message_count: int, payload_size: int, peers_count: int):
             start = Engine.clock
             received: str = my_mailbox.get()
             waiting_time = Engine.clock - start
-            if waiting_time != 0.0:
+            if waiting_time > 0.0:
                 raise AssertionError(f"Expecting the waiting time to be 0.0 because the communication was supposedly "
                                      f"ready, but got {waiting_time} instead")
             this_actor.info(f"I got a '{received}'.")
@@ -69,7 +69,7 @@ def peer(my_id: int, message_count: int, payload_size: int, peers_count: int):
             this_actor.sleep_for(0.01)
 
     this_actor.info("I'm done, just waiting for my peers to receive the messages before exiting")
-    Comm.wait_all(pending_comms)
+    pending_comms.wait_all()
     this_actor.info("Goodbye now!")
 
 
diff --git a/examples/python/comm-testany/comm-testany.py b/examples/python/comm-testany/comm-testany.py
deleted file mode 100644 (file)
index 52220cf..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the license (GNU LGPL) which comes with this package.
-
-from argparse import ArgumentParser
-from typing import List
-import sys
-
-from simgrid import Engine, Actor, Comm, Mailbox, this_actor
-
-
-def create_parser() -> ArgumentParser:
-    parser = ArgumentParser()
-    parser.add_argument(
-        '--platform',
-        type=str,
-        required=True,
-        help='path to the platform description'
-    )
-    return parser
-
-
-def rank0():
-    rank0_mailbox: Mailbox = Mailbox.by_name("rank0")
-    this_actor.info("Post my asynchronous receives")
-    comm1, a1 = rank0_mailbox.get_async()
-    comm2, a2 = rank0_mailbox.get_async()
-    comm3, a3 = rank0_mailbox.get_async()
-    pending_comms: List[Comm] = [comm1, comm2, comm3]
-
-    this_actor.info("Send some data to rank-1")
-    rank1_mailbox: Mailbox = Mailbox.by_name("rank1")
-    for i in range(3):
-        rank1_mailbox.put(i, 1)
-
-    this_actor.info("Test for completed comms")
-    while pending_comms:
-        flag = Comm.test_any(pending_comms)
-        if flag != -1:
-            pending_comms.pop(flag)
-            this_actor.info("Remove a pending comm.")
-        else:
-            # Nothing matches, wait for a little bit
-            this_actor.sleep_for(0.1)
-    this_actor.info("Last comm is complete")
-
-
-def rank1():
-    rank0_mailbox: Mailbox = Mailbox.by_name("rank0")
-    rank1_mailbox: Mailbox = Mailbox.by_name("rank1")
-    for i in range(3):
-        data: int = rank1_mailbox.get()
-        this_actor.info(f"Received {data}")
-        msg_content = f"Message {i}"
-        this_actor.info(f"Send '{msg_content}'")
-        rank0_mailbox.put(msg_content, int(1e6))
-
-
-def main():
-    settings = create_parser().parse_known_args()[0]
-    e = Engine(sys.argv)
-    e.load_platform(settings.platform)
-
-    Actor.create("rank0", e.host_by_name("Tremblay"), rank0)
-    Actor.create("rank1", e.host_by_name("Fafard"), rank1)
-
-    e.run()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/examples/python/comm-testany/comm-testany.tesh b/examples/python/comm-testany/comm-testany.tesh
deleted file mode 100644 (file)
index 83d80f1..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env tesh
-
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-testany.py --platform ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[  0.000000] (1:rank0@Tremblay) Post my asynchronous receives
->[  0.000000] (1:rank0@Tremblay) Send some data to rank-1
->[  0.025708] (2:rank1@Fafard) Received 0
->[  0.025708] (2:rank1@Fafard) Send 'Message 0'
->[  0.209813] (2:rank1@Fafard) Received 1
->[  0.209813] (2:rank1@Fafard) Send 'Message 1'
->[  0.393918] (1:rank0@Tremblay) Test for completed comms
->[  0.393918] (2:rank1@Fafard) Received 2
->[  0.393918] (2:rank1@Fafard) Send 'Message 2'
->[  0.393918] (1:rank0@Tremblay) Remove a pending comm.
->[  0.393918] (1:rank0@Tremblay) Remove a pending comm.
->[  0.593918] (1:rank0@Tremblay) Remove a pending comm.
->[  0.593918] (1:rank0@Tremblay) Last comm is complete
diff --git a/examples/python/comm-waitall/comm-waitall.py b/examples/python/comm-waitall/comm-waitall.py
deleted file mode 100644 (file)
index 68dacca..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the license (GNU LGPL) which comes with this package.
-
-"""
-This example shows how to block on the completion of a set of communications.
-
-As for the other asynchronous examples, the sender initiate all the messages it wants to send and
-pack the resulting simgrid.Comm objects in a list. All messages thus occur concurrently.
-
-The sender then blocks until all ongoing communication terminate, using simgrid.Comm.wait_all()
-"""
-
-import sys
-from simgrid import Actor, Comm, Engine, Host, Mailbox, this_actor
-
-
-def sender(messages_count, msg_size, receivers_count):
-    # List in which we store all ongoing communications
-    pending_comms = []
-
-    # Vector of the used mailboxes
-    mboxes = [Mailbox.by_name("receiver-{:d}".format(i))
-              for i in range(0, receivers_count)]
-
-    # Start dispatching all messages to receivers, in a round robin fashion
-    for i in range(0, messages_count):
-        content = "Message {:d}".format(i)
-        mbox = mboxes[i % receivers_count]
-
-        this_actor.info("Send '{:s}' to '{:s}'".format(content, str(mbox)))
-
-        # Create a communication representing the ongoing communication, and store it in pending_comms
-        comm = mbox.put_async(content, msg_size)
-        pending_comms.append(comm)
-
-    # Start sending messages to let the workers know that they should stop
-    for i in range(0, receivers_count):
-        mbox = mboxes[i]
-        this_actor.info("Send 'finalize' to '{:s}'".format(str(mbox)))
-        comm = mbox.put_async("finalize", 0)
-        pending_comms.append(comm)
-
-    this_actor.info("Done dispatching all messages")
-
-    # Now that all message exchanges were initiated, wait for their completion in one single call
-    Comm.wait_all(pending_comms)
-
-    this_actor.info("Goodbye now!")
-
-
-def receiver(my_id):
-    mbox = Mailbox.by_name("receiver-{:d}".format(my_id))
-
-    this_actor.info("Wait for my first message")
-    while True:
-        received = mbox.get()
-        this_actor.info("I got a '{:s}'.".format(received))
-        if received == "finalize":
-            break  # If it's a finalize message, we're done.
-
-
-if __name__ == '__main__':
-    e = Engine(sys.argv)
-
-    # Load the platform description
-    e.load_platform(sys.argv[1])
-
-    Actor.create("sender", Host.by_name("Tremblay"), sender, 5, 1000000, 2)
-    Actor.create("receiver", Host.by_name("Ruby"), receiver, 0)
-    Actor.create("receiver", Host.by_name("Perl"), receiver, 1)
-
-    e.run()
diff --git a/examples/python/comm-waitall/comm-waitall.tesh b/examples/python/comm-waitall/comm-waitall.tesh
deleted file mode 100644 (file)
index 32ca46c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env tesh
-
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-waitall.py ${platfdir}/small_platform_fatpipe.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (2:receiver@Ruby) Wait for my first message
-> [  0.000000] (3:receiver@Perl) Wait for my first message
-> [  0.000000] (1:sender@Tremblay) Send 'Message 0' to 'Mailbox(receiver-0)'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 1' to 'Mailbox(receiver-1)'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 2' to 'Mailbox(receiver-0)'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 3' to 'Mailbox(receiver-1)'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 4' to 'Mailbox(receiver-0)'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'Mailbox(receiver-0)'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'Mailbox(receiver-1)'
-> [  0.000000] (1:sender@Tremblay) Done dispatching all messages
-> [  0.004022] (2:receiver@Ruby) I got a 'Message 0'.
-> [  0.004022] (3:receiver@Perl) I got a 'Message 1'.
-> [  0.008043] (2:receiver@Ruby) I got a 'Message 2'.
-> [  0.008043] (3:receiver@Perl) I got a 'Message 3'.
-> [  0.009995] (3:receiver@Perl) I got a 'finalize'.
-> [  0.012065] (2:receiver@Ruby) I got a 'Message 4'.
-> [  0.014016] (2:receiver@Ruby) I got a 'finalize'.
-> [  0.014016] (1:sender@Tremblay) Goodbye now!
diff --git a/examples/python/comm-waitallfor/comm-waitallfor.py b/examples/python/comm-waitallfor/comm-waitallfor.py
deleted file mode 100644 (file)
index 0f38795..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-# Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the license (GNU LGPL) which comes with this package.
-
-"""
-This example implements the following scenario:
-- Multiple workers consume jobs (Job) from a shared mailbox (worker)
-- A client first dispatches several jobs (with a simulated 'cost' - i.e. time the worker will 'process' the job)
-- The client then waits for all job results for a maximum time set by the 'wait timeout' (Comm.wait_all_for)
-- The client then displays the status of individual jobs.
-"""
-
-
-from argparse import ArgumentParser
-from dataclasses import dataclass
-from typing import List
-from uuid import uuid4
-import sys
-
-from simgrid import Actor, Comm, Engine, Host, Mailbox, PyGetAsync, this_actor
-
-
-SIMULATED_JOB_SIZE_BYTES = 1024
-SIMULATED_RESULT_SIZE_BYTES = 1024 * 1024
-
-
-def parse_requests(requests_str: str) -> List[float]:
-    return [float(item.strip()) for item in requests_str.split(",")]
-
-
-def create_parser() -> ArgumentParser:
-    parser = ArgumentParser()
-    parser.add_argument(
-        '--platform',
-        type=str,
-        required=True,
-        help='path to the platform description'
-    )
-    parser.add_argument(
-        "--workers",
-        type=int,
-        default=1,
-        help="number of worker actors to start"
-    )
-    parser.add_argument(
-        "--jobs",
-        type=parse_requests,
-        default="1,2,3,4,5",
-        help="duration of individual jobs sent to the workers by the client"
-    )
-    parser.add_argument(
-        "--wait-timeout",
-        type=float,
-        default=5.0,
-        help="number of seconds before the client gives up waiting for results and aborts the simulation"
-    )
-    return parser
-
-
-@dataclass
-class Job:
-    job_id: str
-    duration: float
-    result_mailbox: Mailbox
-
-
-def worker(worker_id: str):
-    this_actor.info(f"{worker_id} started")
-    mailbox: Mailbox = Mailbox.by_name("worker")
-    while True:
-        job: Job = mailbox.get()
-        this_actor.info(f"{worker_id} working on {job.job_id} (will take {job.duration}s to complete)")
-        this_actor.sleep_for(job.duration)
-        job.result_mailbox.put(f"{worker_id}", SIMULATED_RESULT_SIZE_BYTES)
-
-
-@dataclass
-class AsyncJobResult:
-    job: Job
-    result_comm: Comm
-    async_data: PyGetAsync
-
-    @property
-    def complete(self) -> bool:
-        return self.result_comm.test()
-
-    @property
-    def status(self) -> str:
-        return "complete" if self.complete else "pending"
-
-
-def client(client_id: str, jobs: List[float], wait_timeout: float):
-    worker_mailbox: Mailbox = Mailbox.by_name("worker")
-    this_actor.info(f"{client_id} started")
-    async_job_results: list[AsyncJobResult] = []
-    for job_idx, job_duration in enumerate(jobs):
-        result_mailbox: Mailbox = Mailbox.by_name(str(uuid4()))
-        job = Job(job_id=f"job-{job_idx}", duration=job_duration, result_mailbox=result_mailbox)
-        out_comm = worker_mailbox.put_init(Job(
-            job_id=f"job-{job_idx}",
-            duration=job_duration,
-            result_mailbox=result_mailbox
-        ), SIMULATED_JOB_SIZE_BYTES)
-        out_comm.detach()
-        result_comm, async_data = result_mailbox.get_async()
-        async_job_results.append(AsyncJobResult(
-            job=job,
-            result_comm=result_comm,
-            async_data=async_data
-        ))
-    this_actor.info(f"awaiting results for all jobs (timeout={wait_timeout}s)")
-    completed_comms = Comm.wait_all_for([entry.result_comm for entry in async_job_results], wait_timeout)
-    logger = this_actor.warning if completed_comms < len(async_job_results) else this_actor.info
-    logger(f"received {completed_comms}/{len(async_job_results)} results")
-    for result in async_job_results:
-        this_actor.info(f"{result.job.job_id}"
-                        f" status={result.status}"
-                        f" result_payload={result.async_data.get() if result.complete else ''}")
-
-
-def main():
-    settings = create_parser().parse_known_args()[0]
-    e = Engine(sys.argv)
-    e.load_platform(settings.platform)
-    Actor.create("client", Host.by_name("Tremblay"), client, "client", settings.jobs, settings.wait_timeout)
-    for worker_idx in range(settings.workers):
-        Actor.create("worker", Host.by_name("Ruby"), worker, f"worker-{worker_idx}").daemonize()
-    e.run()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/examples/python/comm-waitallfor/comm-waitallfor.tesh b/examples/python/comm-waitallfor/comm-waitallfor.tesh
deleted file mode 100644 (file)
index 50cc88c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env tesh
-
-p Testing Comm.wait_all_for()
-
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-waitallfor.py --platform ${platfdir}/small_platform_fatpipe.xml --workers 1 --wait-timeout 1 --jobs 1,2,3,4,5 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[  0.000000] (2:worker@Ruby) worker-0 started
->[  0.000000] (1:client@Tremblay) client started
->[  0.000000] (1:client@Tremblay) awaiting results for all jobs (timeout=1.0s)
->[  0.001954] (2:worker@Ruby) worker-0 working on job-0 (will take 1.0s to complete)
->[  1.000000] (1:client@Tremblay) received 0/5 results
->[  1.000000] (1:client@Tremblay) job-0 status=pending result_payload=
->[  1.000000] (1:client@Tremblay) job-1 status=pending result_payload=
->[  1.000000] (1:client@Tremblay) job-2 status=pending result_payload=
->[  1.000000] (1:client@Tremblay) job-3 status=pending result_payload=
->[  1.000000] (1:client@Tremblay) job-4 status=pending result_payload=
-
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-waitallfor.py --platform ${platfdir}/small_platform_fatpipe.xml --workers 1 --wait-timeout 5 --jobs 1,2,3,4,5 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[  0.000000] (2:worker@Ruby) worker-0 started
->[  0.000000] (1:client@Tremblay) client started
->[  0.000000] (1:client@Tremblay) awaiting results for all jobs (timeout=5.0s)
->[  0.001954] (2:worker@Ruby) worker-0 working on job-0 (will take 1.0s to complete)
->[  1.008029] (2:worker@Ruby) worker-0 working on job-1 (will take 2.0s to complete)
->[  3.014105] (2:worker@Ruby) worker-0 working on job-2 (will take 3.0s to complete)
->[  5.000000] (1:client@Tremblay) received 2/5 results
->[  5.000000] (1:client@Tremblay) job-0 status=complete result_payload=worker-0
->[  5.000000] (1:client@Tremblay) job-1 status=complete result_payload=worker-0
->[  5.000000] (1:client@Tremblay) job-2 status=pending result_payload=
->[  5.000000] (1:client@Tremblay) job-3 status=pending result_payload=
->[  5.000000] (1:client@Tremblay) job-4 status=pending result_payload=
-
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-waitallfor.py --platform ${platfdir}/small_platform_fatpipe.xml --workers 1 --wait-timeout -1 --jobs 1,2,3,4,5 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[  0.000000] (2:worker@Ruby) worker-0 started
->[  0.000000] (1:client@Tremblay) client started
->[  0.000000] (1:client@Tremblay) awaiting results for all jobs (timeout=-1.0s)
->[  0.001954] (2:worker@Ruby) worker-0 working on job-0 (will take 1.0s to complete)
->[  1.008029] (2:worker@Ruby) worker-0 working on job-1 (will take 2.0s to complete)
->[  3.014105] (2:worker@Ruby) worker-0 working on job-2 (will take 3.0s to complete)
->[  6.020181] (2:worker@Ruby) worker-0 working on job-3 (will take 4.0s to complete)
->[ 10.026257] (2:worker@Ruby) worker-0 working on job-4 (will take 5.0s to complete)
->[ 15.030379] (1:client@Tremblay) received 5/5 results
->[ 15.030379] (1:client@Tremblay) job-0 status=complete result_payload=worker-0
->[ 15.030379] (1:client@Tremblay) job-1 status=complete result_payload=worker-0
->[ 15.030379] (1:client@Tremblay) job-2 status=complete result_payload=worker-0
->[ 15.030379] (1:client@Tremblay) job-3 status=complete result_payload=worker-0
->[ 15.030379] (1:client@Tremblay) job-4 status=complete result_payload=worker-0
-
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-waitallfor.py --platform ${platfdir}/small_platform_fatpipe.xml --workers 5 --wait-timeout 3 --jobs 1,2,3,4,5 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[  0.000000] (2:worker@Ruby) worker-0 started
->[  0.000000] (3:worker@Ruby) worker-1 started
->[  0.000000] (4:worker@Ruby) worker-2 started
->[  0.000000] (5:worker@Ruby) worker-3 started
->[  0.000000] (6:worker@Ruby) worker-4 started
->[  0.000000] (1:client@Tremblay) client started
->[  0.000000] (1:client@Tremblay) awaiting results for all jobs (timeout=3.0s)
->[  0.001954] (6:worker@Ruby) worker-4 working on job-4 (will take 5.0s to complete)
->[  0.001954] (5:worker@Ruby) worker-3 working on job-3 (will take 4.0s to complete)
->[  0.001954] (4:worker@Ruby) worker-2 working on job-2 (will take 3.0s to complete)
->[  0.001954] (3:worker@Ruby) worker-1 working on job-1 (will take 2.0s to complete)
->[  0.001954] (2:worker@Ruby) worker-0 working on job-0 (will take 1.0s to complete)
->[  3.000000] (1:client@Tremblay) received 2/5 results
->[  3.000000] (1:client@Tremblay) job-0 status=complete result_payload=worker-0
->[  3.000000] (1:client@Tremblay) job-1 status=complete result_payload=worker-1
->[  3.000000] (1:client@Tremblay) job-2 status=pending result_payload=
->[  3.000000] (1:client@Tremblay) job-3 status=pending result_payload=
->[  3.000000] (1:client@Tremblay) job-4 status=pending result_payload=
-
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-waitallfor.py --platform ${platfdir}/small_platform_fatpipe.xml --workers 5 --wait-timeout -1 --jobs 5,10,5,20,5,40,5,80,5,160 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[  0.000000] (2:worker@Ruby) worker-0 started
->[  0.000000] (3:worker@Ruby) worker-1 started
->[  0.000000] (4:worker@Ruby) worker-2 started
->[  0.000000] (5:worker@Ruby) worker-3 started
->[  0.000000] (6:worker@Ruby) worker-4 started
->[  0.000000] (1:client@Tremblay) client started
->[  0.000000] (1:client@Tremblay) awaiting results for all jobs (timeout=-1.0s)
->[  0.001954] (6:worker@Ruby) worker-4 working on job-4 (will take 5.0s to complete)
->[  0.001954] (5:worker@Ruby) worker-3 working on job-3 (will take 20.0s to complete)
->[  0.001954] (4:worker@Ruby) worker-2 working on job-2 (will take 5.0s to complete)
->[  0.001954] (3:worker@Ruby) worker-1 working on job-1 (will take 10.0s to complete)
->[  0.001954] (2:worker@Ruby) worker-0 working on job-0 (will take 5.0s to complete)
->[  5.008029] (2:worker@Ruby) worker-0 working on job-7 (will take 80.0s to complete)
->[  5.008029] (4:worker@Ruby) worker-2 working on job-6 (will take 5.0s to complete)
->[  5.008029] (6:worker@Ruby) worker-4 working on job-5 (will take 40.0s to complete)
->[ 10.008029] (3:worker@Ruby) worker-1 working on job-8 (will take 5.0s to complete)
->[ 10.014105] (4:worker@Ruby) worker-2 working on job-9 (will take 160.0s to complete)
->[170.018227] (1:client@Tremblay) received 10/10 results
->[170.018227] (1:client@Tremblay) job-0 status=complete result_payload=worker-0
->[170.018227] (1:client@Tremblay) job-1 status=complete result_payload=worker-1
->[170.018227] (1:client@Tremblay) job-2 status=complete result_payload=worker-2
->[170.018227] (1:client@Tremblay) job-3 status=complete result_payload=worker-3
->[170.018227] (1:client@Tremblay) job-4 status=complete result_payload=worker-4
->[170.018227] (1:client@Tremblay) job-5 status=complete result_payload=worker-4
->[170.018227] (1:client@Tremblay) job-6 status=complete result_payload=worker-2
->[170.018227] (1:client@Tremblay) job-7 status=complete result_payload=worker-0
->[170.018227] (1:client@Tremblay) job-8 status=complete result_payload=worker-1
->[170.018227] (1:client@Tremblay) job-9 status=complete result_payload=worker-2
diff --git a/examples/python/comm-waitany/comm-waitany.py b/examples/python/comm-waitany/comm-waitany.py
deleted file mode 100644 (file)
index 76dd8ce..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the license (GNU LGPL) which comes with this package.
-
-"""
-This example shows how to block on the completion of a set of communications.
-
-As for the other asynchronous examples, the sender initiate all the messages it wants to send and
-pack the resulting simgrid.Comm objects in a list. All messages thus occur concurrently.
-
-The sender then loops until there is no ongoing communication. Using wait_any() ensures that the sender
-will notice events as soon as they occur even if it does not follow the order of the container.
-
-Here, finalize messages will terminate earlier because their size is 0, so they travel faster than the
-other messages of this application.  As expected, the trace shows that the finalize of worker 1 is
-processed before 'Message 5' that is sent to worker 0.
-"""
-
-import sys
-from simgrid import Actor, Comm, Engine, Host, Mailbox, this_actor
-
-
-def sender(messages_count, msg_size, receivers_count):
-    # List in which we store all ongoing communications
-    pending_comms = []
-
-    # Vector of the used mailboxes
-    mboxes = [Mailbox.by_name("receiver-{:d}".format(i))
-              for i in range(0, receivers_count)]
-
-    # Start dispatching all messages to receivers, in a round robin fashion
-    for i in range(0, messages_count):
-        content = "Message {:d}".format(i)
-        mbox = mboxes[i % receivers_count]
-
-        this_actor.info("Send '{:s}' to '{:s}'".format(content, str(mbox)))
-
-        # Create a communication representing the ongoing communication, and store it in pending_comms
-        comm = mbox.put_async(content, msg_size)
-        pending_comms.append(comm)
-
-    # Start sending messages to let the workers know that they should stop
-    for i in range(0, receivers_count):
-        mbox = mboxes[i]
-        this_actor.info("Send 'finalize' to '{:s}'".format(str(mbox)))
-        comm = mbox.put_async("finalize", 0)
-        pending_comms.append(comm)
-
-    this_actor.info("Done dispatching all messages")
-
-    # Now that all message exchanges were initiated, wait for their completion, in order of completion.
-    #
-    # This loop waits for first terminating message with wait_any() and remove it with del, until all comms are
-    # terminated.
-    # Even in this simple example, the pending comms do not terminate in the exact same order of creation.
-    while pending_comms:
-        changed_pos = Comm.wait_any(pending_comms)
-        del pending_comms[changed_pos]
-        if changed_pos != 0:
-            this_actor.info(
-                "Remove the {:d}th pending comm: it terminated earlier than another comm that was initiated first."
-                .format(changed_pos))
-
-    this_actor.info("Goodbye now!")
-
-
-def receiver(my_id):
-    mbox = Mailbox.by_name("receiver-{:d}".format(my_id))
-    this_actor.info("Wait for my first message")
-    while True:
-        received = mbox.get()
-        this_actor.info("I got a '{:s}'.".format(received))
-        if received == "finalize":
-            break  # If it's a finalize message, we're done.
-
-if __name__ == '__main__':
-    e = Engine(sys.argv)
-
-    # Load the platform description
-    e.load_platform(sys.argv[1])
-
-    Actor.create("sender", Host.by_name("Tremblay"), sender, 6, 1000000, 2)
-    Actor.create("receiver", Host.by_name("Fafard"), receiver, 0)
-    Actor.create("receiver", Host.by_name("Jupiter"), receiver, 1)
-
-    e.run()
diff --git a/examples/python/comm-waitany/comm-waitany.tesh b/examples/python/comm-waitany/comm-waitany.tesh
deleted file mode 100644 (file)
index d4593c1..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env tesh
-
-p Testing Comm.wait_any()
-
-! output sort 19
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/comm-waitany.py ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (1:sender@Tremblay) Send 'Message 0' to 'Mailbox(receiver-0)'
-> [  0.000000] (2:receiver@Fafard) Wait for my first message
-> [  0.000000] (3:receiver@Jupiter) Wait for my first message
-> [  0.000000] (1:sender@Tremblay) Send 'Message 1' to 'Mailbox(receiver-1)'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 2' to 'Mailbox(receiver-0)'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 3' to 'Mailbox(receiver-1)'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 4' to 'Mailbox(receiver-0)'
-> [  0.000000] (1:sender@Tremblay) Send 'Message 5' to 'Mailbox(receiver-1)'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'Mailbox(receiver-0)'
-> [  0.000000] (1:sender@Tremblay) Send 'finalize' to 'Mailbox(receiver-1)'
-> [  0.000000] (1:sender@Tremblay) Done dispatching all messages
-> [  0.158397] (2:receiver@Fafard) I got a 'Message 0'.
-> [  0.169155] (3:receiver@Jupiter) I got a 'Message 1'.
-> [  0.316794] (2:receiver@Fafard) I got a 'Message 2'.
-> [  0.338309] (3:receiver@Jupiter) I got a 'Message 3'.
-> [  0.475190] (2:receiver@Fafard) I got a 'Message 4'.
-> [  0.500898] (2:receiver@Fafard) I got a 'finalize'.
-> [  0.500898] (1:sender@Tremblay) Remove the 1th pending comm: it terminated earlier than another comm that was initiated first.
-> [  0.507464] (3:receiver@Jupiter) I got a 'Message 5'.
-> [  0.526478] (3:receiver@Jupiter) I got a 'finalize'.
-> [  0.526478] (1:sender@Tremblay) Goodbye now!
index fc957d8..40df779 100644 (file)
@@ -9,7 +9,7 @@ This example shows how to simulate a non-linear resource sharing for network lin
 
 import functools
 import sys
-from simgrid import Actor, Engine, Comm, Mailbox, NetZone, Link, LinkInRoute, this_actor
+from simgrid import Actor, ActivitySet, Engine, Comm, Mailbox, NetZone, Link, LinkInRoute, this_actor
 
 class Sender:
     """
@@ -22,7 +22,7 @@ class Sender:
     # Actors that are created as object will execute their __call__ method.
     # So, the following constitutes the main function of the Sender actor.
     def __call__(self):
-        pending_comms = []
+        pending_comms = ActivitySet()
         mbox = Mailbox.by_name("receiver")
 
         for i in range(self.msg_count):
@@ -30,12 +30,12 @@ class Sender:
             size = self.msg_size * (i + 1)
             this_actor.info("Send '%s' to '%s, msg size: %d'" % (msg, mbox.name, size))
             comm = mbox.put_async(msg, size)
-            pending_comms.append(comm)
+            pending_comms.push(comm)
 
         this_actor.info("Done dispatching all messages")
 
         # Now that all message exchanges were initiated, wait for their completion in one single call
-        Comm.wait_all(pending_comms)
+        pending_comms.wait_all()
 
         this_actor.info("Goodbye now!")
 
@@ -50,21 +50,16 @@ class Receiver:
     def __call__(self):
         mbox = Mailbox.by_name("receiver")
 
-        pending_msgs = []
-        pending_comms = []
+        pending_comms = ActivitySet()
 
         this_actor.info("Wait for %d messages asynchronously" % self.msg_count)
         for _ in range(self.msg_count):
-            comm, data = mbox.get_async()
-            pending_comms.append(comm)
-            pending_msgs.append(data)
+            comm = mbox.get_async()
+            pending_comms.push(comm)
 
-        while pending_comms:
-            index = Comm.wait_any(pending_comms)
-            msg = pending_msgs[index].get()
-            this_actor.info("I got '%s'." % msg)
-            del pending_comms[index]
-            del pending_msgs[index]
+        while not pending_comms.empty():
+            comm = pending_comms.wait_any()
+            this_actor.info("I got '%s'." % comm.get_payload())
 
 ####################################################################################################
 def link_nonlinear(link: Link, capacity: float, n: int) -> float:
@@ -104,8 +99,7 @@ def load_platform():
     link.set_latency(10e-6).seal()
 
     # create routes between nodes
-    zone.add_route(sender.netpoint, receiver.netpoint, None, None,
-                   [LinkInRoute(link, LinkInRoute.Direction.UP)], True)
+    zone.add_route(sender, receiver, [link])
     zone.seal()
 
     # create actors Sender/Receiver
index b50b60c..f221f49 100644 (file)
@@ -6,7 +6,7 @@
 from typing import List, Tuple
 import sys
 
-from simgrid import Engine, Actor, Comm, Host, LinkInRoute, Mailbox, NetZone, this_actor, PyGetAsync
+from simgrid import Engine, Actor, ActivitySet, Comm, Host, LinkInRoute, Mailbox, NetZone, this_actor
 
 
 RECEIVER_MAILBOX_NAME = "receiver"
@@ -19,7 +19,7 @@ class Sender(object):
 
     def __call__(self) -> None:
         # List in which we store all ongoing communications
-        pending_comms: List[Comm] = []
+        pending_comms = ActivitySet()
 
         # Make a vector of the mailboxes to use
         receiver_mailbox: Mailbox = Mailbox.by_name(RECEIVER_MAILBOX_NAME)
@@ -27,12 +27,12 @@ class Sender(object):
             message_content = f"Message {i}"
             this_actor.info(f"Send '{message_content}' to '{receiver_mailbox.name}'")
             # Create a communication representing the ongoing communication, and store it in pending_comms
-            pending_comms.append(receiver_mailbox.put_async(message_content, self.message_size))
+            pending_comms.push(receiver_mailbox.put_async(message_content, self.message_size))
 
         this_actor.info("Done dispatching all messages")
 
         # Now that all message exchanges were initiated, wait for their completion in one single call
-        Comm.wait_all(pending_comms)
+        pending_comms.wait_all()
 
         this_actor.info("Goodbye now!")
 
@@ -44,15 +44,13 @@ class Receiver(object):
 
     def __call__(self):
         # List in which we store all incoming msgs
-        pending_comms: List[Tuple[Comm, PyGetAsync]] = []
+        pending_comms = ActivitySet()
         this_actor.info(f"Wait for {self.messages_count} messages asynchronously")
         for _ in range(self.messages_count):
-            pending_comms.append(self.mailbox.get_async())
-        while pending_comms:
-            index = Comm.wait_any([comm for (comm, _) in pending_comms])
-            _, async_data = pending_comms[index]
-            this_actor.info(f"I got '{async_data.get()}'.")
-            pending_comms.pop(index)
+            pending_comms.push(self.mailbox.get_async())
+        while not pending_comms.empty():
+            comm = pending_comms.wait_any()
+            this_actor.info(f"I got '{comm.get_payload()}'.")
 
 
 def main():
@@ -70,14 +68,7 @@ def main():
     link = zone.create_split_duplex_link("link1", 10e9).set_latency(10e-6).set_concurrency_limit(2).seal()
 
     # create routes between nodes
-    zone.add_route(
-        sender_host.netpoint,
-        receiver_host.netpoint,
-        None,
-        None,
-        [LinkInRoute(link, LinkInRoute.UP)],
-        True
-    )
+    zone.add_route(sender_host, receiver_host, [link])
     zone.seal()
 
     # create actors Sender/Receiver
index 54bfd27..2ab163e 100644 (file)
@@ -3,7 +3,7 @@
 p Testing a simple master/workers example application handling failures
 
 ! output sort 19
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/platform-failures.py ${platfdir}/small_platform_failures.xml ${srcdir:=.}/platform-failures_d.xml --log=xbt_cfg.thres:critical --log=no_loc --cfg=path:${srcdir} --cfg=network/crosstraffic:0 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/platform-failures.py ${platfdir}/small_platform_failures.xml ${srcdir:=.}/platform-failures_d.xml --log=xbt_cfg.thres:critical --log=no_loc --cfg=network/crosstraffic:0 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=res_cpu.t:verbose
 > [  0.000000] (0:maestro@) Cannot launch actor 'worker' on failed host 'Fafard'
 > [  0.000000] (0:maestro@) Starting actor worker(Fafard) failed because its host is turned off.
 > [  0.000000] (1:master@Tremblay) Got 5 workers and 20 tasks to process
diff --git a/examples/python/plugin-host-load/plugin-host-load.py b/examples/python/plugin-host-load/plugin-host-load.py
new file mode 100644 (file)
index 0000000..71d3ac8
--- /dev/null
@@ -0,0 +1,87 @@
+# Copyright (c) 2006-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+
+from argparse import ArgumentParser
+import sys
+from simgrid import Engine, Host, this_actor, Actor, sg_host_load_plugin_init
+
+def parse():
+    parser = ArgumentParser()
+    parser.add_argument(
+        '--platform',
+        type=str,
+        required=True,
+        help='path to the platform description'
+    )
+    return parser.parse_args()
+
+def execute_load_test():
+  host = Host.by_name('MyHost1')
+  this_actor.info(f'Initial peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E} (should be 0) and current average load: {host.avg_load} (should be 0)')
+
+  start = Engine.clock
+  this_actor.info('Sleep for 10 seconds')
+  this_actor.sleep_for(10)
+
+  speed = host.speed
+  this_actor.info(f'Done sleeping {Engine.clock - start}s; peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E} (nothing should have changed)')
+
+  # Run an activity
+  start = e.clock
+  this_actor.info(f'Run an activity of {200E6:.0E} flops at current speed of {host.speed:.0E} flop/s')
+  this_actor.execute(200E6)
+
+  this_actor.info(f'Done working on my activity; this took {Engine.clock - start}s; current peak speed: {host.speed:.0E} flop/s (when I started the computation, \
+the speed was set to {speed:.0E} flop/s); number of flops computed so \
+far: {host.computed_flops:.0E}, average load as reported by the HostLoad plugin: {host.avg_load:.5f} (should be {200E6 / (10.5 * speed * host.core_count + (Engine.clock - start - 0.5) * host.speed * host.core_count):.5f})')
+
+  # ========= Change power peak =========
+  pstate = 1
+  host.pstate = pstate
+  this_actor.info(f'========= Requesting pstate {pstate} (speed should be of {host.pstate_speed(pstate):.0E} flop/s and is of {host.speed:.0E} flop/s, average load is {host.avg_load:.5f})')
+
+  # Run a second activity
+  start = Engine.clock
+  this_actor.info(f'Run an activity of {100E6:.0E} flops')
+  this_actor.execute(100E6)
+  this_actor.info(f'Done working on my activity; this took {Engine.clock - start}s; current peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E}')
+
+  start = Engine.clock
+  this_actor.info("========= Requesting a reset of the computation and load counters")
+  host.reset_load()
+  this_actor.info(f'After reset: {host.computed_flops:.0E} flops computed; load is {host.avg_load}')
+  this_actor.info('Sleep for 4 seconds')
+  this_actor.sleep_for(4)
+  this_actor.info(f'Done sleeping {Engine.clock - start}s; peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E}')
+
+  # =========== Turn the other host off ==========
+  host2 = Host.by_name('MyHost2')
+  this_actor.info(f'Turning MyHost2 off, and sleeping another 10 seconds. MyHost2 computed {host2.computed_flops:.0E} flops so far and has an average load of {host2.avg_load}')
+  host2.turn_off()
+  start = Engine.clock
+  this_actor.sleep_for(10)
+  this_actor.info(f'Done sleeping {Engine.clock - start}s; peak speed: {host.speed:.0E} flop/s; number of flops computed so far: {host.computed_flops:.0E}')
+
+def change_speed():
+  host = Host.by_name('MyHost1')
+  this_actor.sleep_for(10.5)
+  this_actor.info("I slept until now, but now I'll change the speed of this host while the other actor is still computing! This should slow the computation down.")
+  host.pstate = 2
+
+if __name__ == '__main__':
+  args = parse()
+  
+  sg_host_load_plugin_init()
+  e = Engine(sys.argv)
+  e.load_platform(args.platform)
+
+  Actor.create('load_test', e.host_by_name('MyHost1'), execute_load_test)
+  Actor.create('change_speed', e.host_by_name('MyHost1'), change_speed)
+
+  e.run()
+
+  this_actor.info(f'Total simulation time: {Engine.clock}')
+
diff --git a/examples/python/plugin-host-load/plugin-host-load.tesh b/examples/python/plugin-host-load/plugin-host-load.tesh
new file mode 100644 (file)
index 0000000..ad14d19
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env tesh
+
+p This tests the Host Load plugin (that allows the user to get the current load of a host and the computed flops)
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/plugin-host-load.py --platform ${platfdir}/energy_platform.xml
+> [MyHost1:load_test:(1) 0.000000] [python/INFO] Initial peak speed: 1E+08 flop/s; number of flops computed so far: 0E+00 (should be 0) and current average load: 0.0 (should be 0)
+> [MyHost1:load_test:(1) 0.000000] [python/INFO] Sleep for 10 seconds
+> [MyHost1:load_test:(1) 10.000000] [python/INFO] Done sleeping 10.0s; peak speed: 1E+08 flop/s; number of flops computed so far: 0E+00 (nothing should have changed)
+> [MyHost1:load_test:(1) 10.000000] [python/INFO] Run an activity of 2E+08 flops at current speed of 1E+08 flop/s
+> [MyHost1:change_speed:(2) 10.500000] [python/INFO] I slept until now, but now I'll change the speed of this host while the other actor is still computing! This should slow the computation down.
+> [MyHost1:load_test:(1) 18.000000] [python/INFO] Done working on my activity; this took 8.0s; current peak speed: 2E+07 flop/s (when I started the computation, the speed was set to 1E+08 flop/s); number of flops computed so far: 2E+08, average load as reported by the HostLoad plugin: 0.04167 (should be 0.04167)
+> [MyHost1:load_test:(1) 18.000000] [python/INFO] ========= Requesting pstate 1 (speed should be of 5E+07 flop/s and is of 5E+07 flop/s, average load is 0.04167)
+> [MyHost1:load_test:(1) 18.000000] [python/INFO] Run an activity of 1E+08 flops
+> [MyHost1:load_test:(1) 20.000000] [python/INFO] Done working on my activity; this took 2.0s; current peak speed: 5E+07 flop/s; number of flops computed so far: 3E+08
+> [MyHost1:load_test:(1) 20.000000] [python/INFO] ========= Requesting a reset of the computation and load counters
+> [MyHost1:load_test:(1) 20.000000] [python/INFO] After reset: 0E+00 flops computed; load is 0.0
+> [MyHost1:load_test:(1) 20.000000] [python/INFO] Sleep for 4 seconds
+> [MyHost1:load_test:(1) 24.000000] [python/INFO] Done sleeping 4.0s; peak speed: 5E+07 flop/s; number of flops computed so far: 0E+00
+> [MyHost1:load_test:(1) 24.000000] [python/INFO] Turning MyHost2 off, and sleeping another 10 seconds. MyHost2 computed 0E+00 flops so far and has an average load of 0.0
+> [MyHost1:load_test:(1) 34.000000] [python/INFO] Done sleeping 10.0s; peak speed: 5E+07 flop/s; number of flops computed so far: 0E+00
+> [34.000000] [python/INFO] Total simulation time: 34.0
diff --git a/examples/python/task-io/task-io.py b/examples/python/task-io/task-io.py
new file mode 100644 (file)
index 0000000..d3ab8c1
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2006-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+from argparse import ArgumentParser
+import sys
+from simgrid import Engine, Task, ExecTask, IoTask, IoOpType
+
+def parse():
+    parser = ArgumentParser()
+    parser.add_argument(
+        '--platform',
+        type=str,
+        required=True,
+        help='path to the platform description'
+    )
+    return parser.parse_args()
+
+def callback(t):
+    print(f'[{Engine.clock}] {t} finished ({t.get_count()})')
+
+if __name__ == '__main__':
+    args = parse()
+    e = Engine(sys.argv)
+    e.load_platform(args.platform)
+
+    # Retrieve hosts
+    bob = e.host_by_name('bob')
+    carl = e.host_by_name('carl')
+
+    # Create tasks
+    exec1 = ExecTask.init("exec1", 1e9, bob)
+    exec2 = ExecTask.init("exec2", 1e9, carl)
+    write = IoTask.init("write", 1e7, bob.disks[0], IoOpType.WRITE)
+    read = IoTask.init("read", 1e7, carl.disks[0], IoOpType.READ)
+
+   # Create the graph by defining dependencies between tasks
+    exec1.add_successor(write)
+    write.add_successor(read)
+    read.add_successor(exec2)
+
+    # Add a function to be called when tasks end for log purpose
+    Task.on_completion_cb(callback)
+
+    # Enqueue two firings for task exec1
+    exec1.enqueue_firings(2)
+
+    # runs the simulation
+    e.run()
diff --git a/examples/python/task-io/task-io.tesh b/examples/python/task-io/task-io.tesh
new file mode 100644 (file)
index 0000000..c6e5691
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env tesh
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/task-io.py --platform ${platfdir}/hosts_with_disks.xml
+> [1.0] ExecTask(exec1) finished (1)
+> [1.25] IoTask(write) finished (1)
+> [1.35] IoTask(read) finished (1)
+> [2.0] ExecTask(exec1) finished (2)
+> [2.25] IoTask(write) finished (2)
+> [2.35] ExecTask(exec2) finished (1)
+> [2.35] IoTask(read) finished (2)
+> [3.35] ExecTask(exec2) finished (2)
+
diff --git a/examples/python/task-simple/task-simple.py b/examples/python/task-simple/task-simple.py
new file mode 100644 (file)
index 0000000..beca2b6
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (c) 2006-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+"""
+This example demonstrates basic use of the task plugin.
+We model the following graph:
+
+exec1 -> comm -> exec2
+
+exec1 and exec2 are execution tasks.
+comm is a communication task.
+"""
+
+from argparse import ArgumentParser
+import sys
+from simgrid import Engine, Task, CommTask, ExecTask
+
+def parse():
+    parser = ArgumentParser()
+    parser.add_argument(
+        '--platform',
+        type=str,
+        required=True,
+        help='path to the platform description'
+    )
+    return parser.parse_args()
+
+def callback(t):
+    print(f'[{Engine.clock}] {t} finished ({t.get_count()})')
+
+if __name__ == '__main__':
+    args = parse()
+    e = Engine(sys.argv)
+    e.load_platform(args.platform)
+
+    # Retrieve hosts
+    tremblay = e.host_by_name('Tremblay')
+    jupiter = e.host_by_name('Jupiter')
+
+    # Create tasks
+    exec1 = ExecTask.init("exec1", 1e9, tremblay)
+    exec2 = ExecTask.init("exec2", 1e9, jupiter)
+    comm = CommTask.init("comm", 1e7, tremblay, jupiter)
+
+    # Create the graph by defining dependencies between tasks
+    exec1.add_successor(comm)
+    comm.add_successor(exec2)
+
+    # Add a function to be called when tasks end for log purpose
+    Task.on_completion_cb(callback)
+
+    # Enqueue two firings for task exec1
+    exec1.enqueue_firings(2)
+
+    # runs the simulation
+    e.run()
diff --git a/examples/python/task-simple/task-simple.tesh b/examples/python/task-simple/task-simple.tesh
new file mode 100644 (file)
index 0000000..f9a828f
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/env tesh
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/task-simple.py --platform ${platfdir}/small_platform.xml
+> [10.194199500484224] ExecTask(exec1) finished (1)
+> [11.714617112501687] CommTask(comm) finished (1)
+> [20.388399000968448] ExecTask(exec1) finished (2)
+> [21.90881661298591] CommTask(comm) finished (2)
+> [24.821464129383305] ExecTask(exec2) finished (1)
+> [37.928311146264925] ExecTask(exec2) finished (2)
diff --git a/examples/python/task-switch-host/task-switch-host.py b/examples/python/task-switch-host/task-switch-host.py
new file mode 100644 (file)
index 0000000..03dce6a
--- /dev/null
@@ -0,0 +1,96 @@
+# Copyright (c) 2006-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+"""
+This example demonstrates how to dynamically modify a graph of tasks.
+
+Assuming we have two instances of a service placed on different hosts,
+we want to send data alternatively to thoses instances.
+
+We consider the following graph:
+
+           comm1
+     ┌────────────────────────┐
+     │                        │
+     │               Fafard   │
+     │              ┌───────┐ │
+     │      ┌──────►│ exec1 ├─┘
+     ▼      │       └───────┘
+ Tremblay ──┤comm0
+     ▲      │        Jupiter
+     │      │       ┌───────┐
+     │      └──────►│ exec2 ├─┐
+     │              └───────┘ │
+     │                        │
+     └────────────────────────┘
+           comm2
+
+"""
+
+from argparse import ArgumentParser
+import sys
+from simgrid import Engine, Task, CommTask, ExecTask
+
+def parse():
+    parser = ArgumentParser()
+    parser.add_argument(
+        '--platform',
+        type=str,
+        required=True,
+        help='path to the platform description'
+    )
+    return parser.parse_args()
+
+def callback(t):
+    print(f'[{Engine.clock}] {t} finished ({t.get_count()})')
+
+def switch_destination(t, hosts):
+    t.destination = hosts[switch_destination.count % 2]
+    switch_destination.count += 1
+switch_destination.count = 0
+
+def switch_successor(t, execs):
+    t.remove_successor(execs[t.get_count() % 2])
+    t.add_successor(execs[t.get_count() % 2 - 1])
+
+if __name__ == '__main__':
+    args = parse()
+    e = Engine(sys.argv)
+    e.load_platform(args.platform)
+
+    # Retrieve hosts
+    tremblay = e.host_by_name('Tremblay')
+    jupiter = e.host_by_name('Jupiter')
+    fafard = e.host_by_name('Fafard')
+
+    # Create tasks
+    comm0 = CommTask.init("comm0")
+    comm0.bytes = 1e7
+    comm0.source = tremblay
+    exec1 = ExecTask.init("exec1", 1e9, jupiter)
+    exec2 = ExecTask.init("exec2", 1e9, fafard)
+    comm1 = CommTask.init("comm1", 1e7, jupiter, tremblay)
+    comm2 = CommTask.init("comm2", 1e7, fafard, tremblay)
+
+    # Create the initial graph by defining dependencies between tasks
+    exec1.add_successor(comm1)
+    exec2.add_successor(comm2)
+
+    # Add a callback when tasks end for log purpose
+    Task.on_completion_cb(callback)
+
+    # Add a callback before each firing of comm0
+    # It switches the destination of comm0
+    comm0.on_this_start_cb(lambda t: switch_destination(t, [jupiter, fafard]))
+
+    # Add a callback before comm0 send tokens to successors
+    # It switches the successor of comm0
+    comm0.on_this_completion_cb(lambda t: switch_successor(t, [exec1,exec2]))
+
+    # Enqueue two firings for task exec1
+    comm0.enqueue_firings(4)
+
+    # runs the simulation
+    e.run()
diff --git a/examples/python/task-switch-host/task-switch-host.tesh b/examples/python/task-switch-host/task-switch-host.tesh
new file mode 100644 (file)
index 0000000..e506de7
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/env tesh
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/task-switch-host.py --platform ${platfdir}/small_platform.xml
+> [1.5204176120174615] CommTask(comm0) finished (1)
+> [2.873012467069035] CommTask(comm0) finished (2)
+> [4.393430079086497] CommTask(comm0) finished (3)
+> [5.74602493413807] CommTask(comm0) finished (4)
+> [14.62726462889908] ExecTask(exec1) finished (1)
+> [15.979859483950655] ExecTask(exec2) finished (1)
+> [16.14768224091654] CommTask(comm1) finished (1)
+> [17.33245433900223] CommTask(comm2) finished (1)
+> [27.7341116457807] ExecTask(exec1) finished (2)
+> [29.086706500832275] ExecTask(exec2) finished (2)
+> [29.25452925779816] CommTask(comm1) finished (2)
+> [30.43930135588385] CommTask(comm2) finished (2)
diff --git a/examples/python/task-variable-load/task-variable-load.py b/examples/python/task-variable-load/task-variable-load.py
new file mode 100644 (file)
index 0000000..14fc2ec
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright (c) 2006-2023. The SimGrid Team. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the license (GNU LGPL) which comes with this package.
+
+"""
+This example demonstrates how to create a variable load for tasks.
+We consider the following graph:
+
+comm -> exec
+
+With a small load each comm task is followed by an exec task.
+With a heavy load there is a burst of comm before the exec task can even finish once.
+"""
+
+from argparse import ArgumentParser
+import sys
+from simgrid import Engine, Task, CommTask, ExecTask, Actor, this_actor
+
+def parse():
+    parser = ArgumentParser()
+    parser.add_argument(
+        '--platform',
+        type=str,
+        required=True,
+        help='path to the platform description'
+    )
+    return parser.parse_args()
+
+def callback(t):
+    print(f'[{Engine.clock}] {t} finished ({t.get_count()})')
+
+def variable_load(t):
+    print('--- Small load ---')
+    for _ in range(3):
+        t.enqueue_firings(1)
+        this_actor.sleep_for(100)
+    this_actor.sleep_for(1000)
+    print('--- Heavy load ---')
+    for _ in range(3):
+        t.enqueue_firings(1)
+        this_actor.sleep_for(1)
+
+if __name__ == '__main__':
+    args = parse()
+    e = Engine(sys.argv)
+    e.load_platform(args.platform)
+
+    # Retrieve hosts
+    tremblay = e.host_by_name('Tremblay')
+    jupiter = e.host_by_name('Jupiter')
+
+    # Create tasks
+    comm = CommTask.init("comm", 1e7, tremblay, jupiter)
+    exec = ExecTask.init("exec", 1e9, jupiter)
+
+    # Create the graph by defining dependencies between tasks
+    comm.add_successor(exec)
+
+    # Add a function to be called when tasks end for log purpose
+    Task.on_completion_cb(callback)
+
+    # Create the actor that will inject load during the simulation
+    Actor.create("input", tremblay, variable_load, comm)
+
+    # runs the simulation
+    e.run()
diff --git a/examples/python/task-variable-load/task-variable-load.tesh b/examples/python/task-variable-load/task-variable-load.tesh
new file mode 100644 (file)
index 0000000..0aa185a
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env tesh
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/task-variable-load.py --platform ${platfdir}/small_platform.xml
+> --- Small load ---
+> [1.5204176120174615] CommTask(comm) finished (1)
+> [14.62726462889908] ExecTask(exec) finished (1)
+> [101.52041761201747] CommTask(comm) finished (2)
+> [114.62726462889908] ExecTask(exec) finished (2)
+> [201.52041761201744] CommTask(comm) finished (3)
+> [214.62726462889907] ExecTask(exec) finished (3)
+> --- Heavy load ---
+> [1301.5204176120174] CommTask(comm) finished (4)
+> [1303.0408352240347] CommTask(comm) finished (5)
+> [1304.561252836052] CommTask(comm) finished (6)
+> [1314.627264628899] ExecTask(exec) finished (4)
+> [1327.7341116457806] ExecTask(exec) finished (5)
+> [1340.8409586626622] ExecTask(exec) finished (6)
+
+
index 4065548..e590108 100644 (file)
@@ -3,8 +3,7 @@ set(_replay_sources    ${CMAKE_CURRENT_SOURCE_DIR}/replay/replay.cpp)
 set(_ampi_test_sources ${CMAKE_CURRENT_SOURCE_DIR}/ampi_test/ampi_test.cpp)
 
 # These tests are only used when MC is actived
-set(MC_tests bugged1 bugged2 bugged1_liveness only_send_deterministic mutual_exclusion non_termination1
-             non_termination2 non_termination3 non_termination4 sendsend)
+set(MC_tests bugged1 bugged2 only_send_deterministic mutual_exclusion sendsend)
 foreach(x ${MC_tests})
   if(NOT SIMGRID_HAVE_MC)
     set(_${x}_disable 1)
@@ -65,13 +64,10 @@ set(tesh_files    ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/energy/energy.tes
                                    ${CMAKE_CURRENT_SOURCE_DIR}/replay/replay.tesh                          PARENT_SCOPE)
 set(bin_files     ${bin_files}     ${CMAKE_CURRENT_SOURCE_DIR}/hostfile
                                    ${CMAKE_CURRENT_SOURCE_DIR}/energy/hostfile
-                                   ${CMAKE_CURRENT_SOURCE_DIR}/mc/promela_bugged1_liveness
-                                   ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_bugged1_liveness
                                    ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_bugged1
                                    ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_bugged2
                                    ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_only_send_deterministic
                                    ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_mutual_exclusion
-                                   ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_non_termination
                                    ${CMAKE_CURRENT_SOURCE_DIR}/simple-execute/hostfile_griffon             PARENT_SCOPE)
 set(txt_files     ${txt_files}     ${CMAKE_CURRENT_SOURCE_DIR}/replay/actions0.txt
                                    ${CMAKE_CURRENT_SOURCE_DIR}/replay/actions1.txt
index 383eef3..470836b 100644 (file)
@@ -15,9 +15,9 @@ namespace sg4 = simgrid::s4u;
  * in collective operations. But it doesn't happen in this example
  *
  * @param op MPI Operation (set by user at cb registering below)
- * @param size Message size (set by simgrid)
- * @param src Source host (set by simgrid)
- * @param dst Source host (set by simgrid)
+ * @param size Message size (set by SimGrid)
+ * @param src Source host (set by SimGrid)
+ * @param dst Source host (set by SimGrid)
  */
 static double smpi_cost_cb(SmpiOperation op, size_t /*size*/, const sg4::Host* src, const sg4::Host* dst)
 {
@@ -47,8 +47,7 @@ void load_platform(const sg4::Engine& /*e*/)
 
   const sg4::Link* link9 = root->create_split_duplex_link("9", "7.20975MBps")->set_latency("1.461517ms")->seal();
 
-  root->add_route(tremblay->get_netpoint(), jupiter->get_netpoint(), nullptr, nullptr,
-                  {{link9, sg4::LinkInRoute::Direction::UP}}, true);
+  root->add_route(tremblay, jupiter, {link9});
   root->seal();
 
   /* set cost callback for MPI_Send and MPI_Recv */
index 3aedd09..b9f0635 100644 (file)
 #include <mpi.h>
 #include <stdio.h>
 
-void multiply(float* a, float* b, float* c, int istart, int iend, int size);
-void multiply_sampled(float* a, float* b, float* c, int istart, int iend, int size);
-
-
-void multiply(float* a, float* b, float* c, int istart, int iend, int size)
+static void multiply(const float* a, const float* b, float* c, int istart, int iend, int size)
 {
     for (int i = istart; i <= iend; ++i) {
         for (int j = 0; j < size; ++j) {
-            for (int k = 0; k < size; ++k) {
-                c[i*size+j] += a[i*size+k] * b[k*size+j];
-            }
+          float sum = 0.0;
+          for (int k = 0; k < size; ++k) {
+            sum += a[i * size + k] * b[k * size + j];
+          }
+          c[i * size + j] += sum;
         }
     }
 }
 
-void multiply_sampled(float* a, float* b, float* c, int istart, int iend, int size)
+static void multiply_sampled(const float* a, const float* b, float* c, int istart, int iend, int size)
 {
     //for (int i = istart; i <= iend; ++i) {
     SMPI_SAMPLE_GLOBAL (int i = istart, i <= iend, ++i, 10, 0.005){
         for (int j = 0; j < size; ++j) {
-            for (int k = 0; k < size; ++k) {
-                c[i*size+j] += a[i*size+k] * b[k*size+j];
-            }
+          float sum = 0.0;
+          for (int k = 0; k < size; ++k) {
+            sum += a[i * size + k] * b[k * size + j];
+          }
+          c[i * size + j] += sum;
         }
     }
 }
index 280152a..a9c2bd6 100644 (file)
@@ -4,13 +4,13 @@
 
 p Test instrumentation of SMPI
 
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning --cfg=smpi/host-speed:1f -np 8 ${bindir:=.}/smpi_gemm 1000 native
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning --cfg=smpi/host-speed:1f -np 8 ${bindir:=.}/smpi_gemm 1000 native
 > [0.000000] [smpi/INFO] You requested to use 8 ranks, but there is only 5 processes in your hostfile...
 > Matrix Size : 1000x1000
 > Native mode
 > Performance= 220.56 GFlop/s, Time= 9.068 sec, Size= 2000000000 Ops
 
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning --cfg=smpi/host-speed:1f -np 8 ${bindir:=.}/smpi_gemm 1000 sampling
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning --cfg=smpi/host-speed:1f -np 8 ${bindir:=.}/smpi_gemm 1000 sampling
 > [0.000000] [smpi/INFO] You requested to use 8 ranks, but there is only 5 processes in your hostfile...
 > Matrix Size : 1000x1000
 > Sampling mode
diff --git a/examples/smpi/mc/bugged1_liveness.c b/examples/smpi/mc/bugged1_liveness.c
deleted file mode 100644 (file)
index 0b215f9..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Copyright (c) 2013-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/***************** Centralized Mutual Exclusion Algorithm *********************/
-/* This example implements a centralized mutual exclusion algorithm.          */
-/* Bug : CS requests of process 1 not satisfied                                      */
-/* LTL property checked : G(r->F(cs)); (r=request of CS, cs=CS ok)            */
-/******************************************************************************/
-
-/* Run :
-  /usr/bin/time -f "clock:%e user:%U sys:%S swapped:%W exitval:%x max:%Mk" "$@" \
-    ../../../smpi_script/bin/smpirun -hostfile hostfile_bugged1_liveness -platform ../../platforms/cluster_backbone.xml \
-    --cfg=contexts/factory:ucontext --cfg=model-check/reduction:none \
-    --cfg=model-check/property:promela_bugged1_liveness --cfg=smpi/send-is-detached-thresh:0 \
-    --cfg=contexts/stack-size:128 --cfg=model-check/visited:100000 --cfg=model-check/max-depth:100000 ./bugged1_liveness
-*/
-
-#include <stdio.h>
-#include <mpi.h>
-#include <simgrid/modelchecker.h>
-#include <xbt/dynar.h>
-
-#define GRANT_TAG 0
-#define REQUEST_TAG 1
-#define RELEASE_TAG 2
-
-int r;
-int cs;
-
-int main(int argc, char **argv){
-  int size;
-  int rank;
-  int recv_buff;
-  MPI_Status status;
-  xbt_dynar_t requests = xbt_dynar_new(sizeof(int), NULL);
-
-  /* Initialize MPI */
-  int err = MPI_Init(&argc, &argv);
-  if(err !=  MPI_SUCCESS){
-    printf("MPI initialization failed !\n");
-    exit(1);
-  }
-
-  MC_automaton_new_propositional_symbol_pointer("r", &r);
-  MC_automaton_new_propositional_symbol_pointer("cs", &cs);
-
-  MC_ignore(&status.count, sizeof status.count);
-
-  /* Get number of processes */
-  MPI_Comm_size(MPI_COMM_WORLD, &size);
-  /* Get id of this process */
-  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
-
-  if(rank == 0){ /* Coordinator */
-    int CS_used = 0;
-    while(1){
-      MPI_Recv(&recv_buff, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
-      if(status.MPI_TAG == REQUEST_TAG){
-        if(CS_used){
-          printf("CS already used.\n");
-          xbt_dynar_push(requests, &recv_buff);
-        }else{
-          if(recv_buff != size - 1){
-            printf("CS idle. Grant immediately.\n");
-            MPI_Send(&rank, 1, MPI_INT, recv_buff, GRANT_TAG, MPI_COMM_WORLD);
-            CS_used = 1;
-          }
-        }
-      }else{
-        if(!xbt_dynar_is_empty(requests)){
-          printf("CS release. Grant to queued requests (queue size: %lu)", xbt_dynar_length(requests));
-          xbt_dynar_shift(requests, &recv_buff);
-          if(recv_buff != size - 1){
-            MPI_Send(&rank, 1, MPI_INT, recv_buff, GRANT_TAG, MPI_COMM_WORLD);
-            CS_used = 1;
-          }else{
-            xbt_dynar_push(requests, &recv_buff);
-            CS_used = 0;
-          }
-        }else{
-          printf("CS release. Resource now idle.\n");
-          CS_used = 0;
-        }
-      }
-    }
-  }else{ /* Client */
-    while(1){
-      printf("%d asks the request.\n", rank);
-      MPI_Send(&rank, 1, MPI_INT, 0, REQUEST_TAG, MPI_COMM_WORLD);
-      if(rank == size - 1){
-        r = 1;
-        cs = 0;
-      }
-      MPI_Recv(&recv_buff, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
-      if(status.MPI_TAG == GRANT_TAG && rank == size - 1){
-        cs = 1;
-        r = 0;
-      }
-      printf("%d got the answer. Release it.\n", rank);
-      MPI_Send(&rank, 1, MPI_INT, 0, RELEASE_TAG, MPI_COMM_WORLD);
-      if(rank == size - 1){
-        r = 0;
-        cs = 0;
-      }
-    }
-  }
-
-  MPI_Finalize();
-
-  return 0;
-}
diff --git a/examples/smpi/mc/hostfile_bugged1_liveness b/examples/smpi/mc/hostfile_bugged1_liveness
deleted file mode 100644 (file)
index edbbeb8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-node-1.simgrid.org
-node-2.simgrid.org
-node-3.simgrid.org
diff --git a/examples/smpi/mc/hostfile_non_termination b/examples/smpi/mc/hostfile_non_termination
deleted file mode 100644 (file)
index c1627f2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-node-1.simgrid.org
-node-2.simgrid.org
\ No newline at end of file
index 0fb0a75..235860c 100644 (file)
@@ -27,8 +27,6 @@ int main(int argc, char **argv){
     exit(1);
   }
 
-  MC_ignore(&status.count, sizeof status.count);
-
   /* Get number of processes */
   MPI_Comm_size(MPI_COMM_WORLD, &size);
   /* Get id of this process */
diff --git a/examples/smpi/mc/non_termination1.c b/examples/smpi/mc/non_termination1.c
deleted file mode 100644 (file)
index a0ce7dd..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <stdio.h>
-#include <mpi.h>
-#include <simgrid/modelchecker.h>
-
-int x = 5;
-int y = 8;
-
-int main(int argc, char **argv) {
-  int recv_buff;
-  int size;
-  int rank;
-  MPI_Status status;
-
-  MPI_Init(&argc, &argv);
-
-  MPI_Comm_size(MPI_COMM_WORLD, &size);   /* Get nr of tasks */
-  MPI_Comm_rank(MPI_COMM_WORLD, &rank);   /* Get id of this process */
-
-  MC_ignore(&status.count, sizeof status.count);
-
-  if (rank == 0) {
-    while (1) {
-      MPI_Recv(&recv_buff, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
-    }
-  } else {
-    while (1) {
-      int old_x = x;
-      x = -y;
-      y = old_x;
-      printf("x = %d, y = %d\n", x, y);
-      MPI_Send(&rank, 1, MPI_INT, 0, 42, MPI_COMM_WORLD);
-    }
-  }
-
-  MPI_Finalize();
-
-  return 0;
-}
diff --git a/examples/smpi/mc/non_termination2.c b/examples/smpi/mc/non_termination2.c
deleted file mode 100644 (file)
index 5ccafb6..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <stdio.h>
-#include <mpi.h>
-#include <simgrid/modelchecker.h>
-
-int x;
-
-int main(int argc, char **argv) {
-  int recv_buff;
-  int size;
-  int rank;
-  MPI_Status status;
-
-  MPI_Init(&argc, &argv);
-
-  MPI_Comm_size(MPI_COMM_WORLD, &size);   /* Get nr of tasks */
-  MPI_Comm_rank(MPI_COMM_WORLD, &rank);   /* Get id of this process */
-
-  MC_ignore(&status.count, sizeof status.count);
-
-  if (rank == 0) {
-    while (1) {
-      MPI_Recv(&recv_buff, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
-    }
-  } else {
-    while (1) {
-      x = 2;
-      MPI_Send(&rank, 1, MPI_INT, 0, 42, MPI_COMM_WORLD);
-    }
-  }
-
-  MPI_Finalize();
-
-  return 0;
-}
diff --git a/examples/smpi/mc/non_termination3.c b/examples/smpi/mc/non_termination3.c
deleted file mode 100644 (file)
index 309f4d4..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <stdio.h>
-#include <mpi.h>
-#include <simgrid/modelchecker.h>
-
-int x = 0;
-int y = 0;
-
-int main(int argc, char **argv) {
-  int recv_x;
-  int recv_y;
-  int size;
-  int rank;
-  MPI_Status status;
-
-  MPI_Init(&argc, &argv);
-
-  MPI_Comm_size(MPI_COMM_WORLD, &size);   /* Get nr of tasks */
-  MPI_Comm_rank(MPI_COMM_WORLD, &rank);   /* Get id of this process */
-
-  MC_ignore(&status.count, sizeof status.count);
-
-  if (rank == 0) {
-    while (x<5) {
-      MPI_Recv(&recv_x, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
-      MPI_Recv(&recv_y, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
-    }
-  } else {
-    while (x<5) {
-      int old_x = x;
-      x = old_x - y;
-      MPI_Send(&x, 1, MPI_INT, 0, 42, MPI_COMM_WORLD);
-      y = old_x + y;
-      MPI_Send(&y, 1, MPI_INT, 0, 42, MPI_COMM_WORLD);
-    }
-  }
-
-  MPI_Finalize();
-
-  return 0;
-}
diff --git a/examples/smpi/mc/non_termination4.c b/examples/smpi/mc/non_termination4.c
deleted file mode 100644 (file)
index 7facb28..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <stdio.h>
-#include <mpi.h>
-#include <simgrid/modelchecker.h>
-
-int x = 20;
-
-int main(int argc, char **argv) {
-  int recv_x = 1;
-  int size;
-  int rank;
-  MPI_Status status;
-
-  MPI_Init(&argc, &argv);
-
-  MPI_Comm_size(MPI_COMM_WORLD, &size);   /* Get nr of tasks */
-  MPI_Comm_rank(MPI_COMM_WORLD, &rank);   /* Get id of this process */
-
-  MC_ignore(&status.count, sizeof status.count);
-
-  if(rank==0){
-    while (recv_x>=0) {
-      MPI_Recv(&recv_x, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
-    }
-  }else{
-    while (x >= 0) {
-      if (MC_random(0,1) == 0) {
-        x -= 1;
-      } else {
-        x += 1;
-      }
-      printf("x=%d\n", x);
-      MPI_Send(&x, 1, MPI_INT, 0, 42, MPI_COMM_WORLD);
-    }
-  }
-
-  MPI_Finalize();
-
-  return 0;
-}
index 447496d..4f070ab 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env tesh
 
 ! timeout 60
-$ ../../../smpi_script/bin/smpirun -wrapper "${bindir:=.}/../../../bin/simgrid-mc" --log=xbt_cfg.thresh:warning -hostfile ${srcdir:=.}/hostfile_only_send_deterministic  -platform ${srcdir:=.}/../../platforms/cluster_backbone.xml --cfg=model-check/communications-determinism:1 --cfg=smpi/buffering:zero --cfg=smpi/host-speed:1Gf ./smpi_only_send_deterministic
+$ $VALGRIND_NO_LEAK_CHECK ../../../smpi_script/bin/smpirun -wrapper "${bindir:=.}/../../../bin/simgrid-mc" --log=xbt_cfg.thresh:warning -hostfile ${srcdir:=.}/hostfile_only_send_deterministic  -platform ${srcdir:=.}/../../platforms/cluster_backbone.xml --cfg=model-check/communications-determinism:1 --cfg=smpi/buffering:zero --cfg=smpi/host-speed:1Gf ./smpi_only_send_deterministic
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > [0.000000] [mc_comm_determinism/INFO] Check communication determinism
 > [0.000000] [mc_comm_determinism/INFO] *******************************************************
@@ -10,4 +10,4 @@ $ ../../../smpi_script/bin/smpirun -wrapper "${bindir:=.}/../../../bin/simgrid-m
 > [0.000000] [mc_comm_determinism/INFO] The recv communications pattern of the actor 0 is different! Different source for communication #1
 > [0.000000] [mc_comm_determinism/INFO] Send-deterministic : Yes
 > [0.000000] [mc_comm_determinism/INFO] Recv-deterministic : No
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 242 unique states visited; 68 backtracks (612 transition replays, 303 states visited overall)
\ No newline at end of file
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 25 unique states visited; 6 backtracks (11 transition replays, 42 states visited overall)
diff --git a/examples/smpi/mc/promela_bugged1_liveness b/examples/smpi/mc/promela_bugged1_liveness
deleted file mode 100644 (file)
index 96b491d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-never { /* !G(r->Fcs) */
-T0_init :    /* init */
-       if
-       :: (1) -> goto T0_init
-       :: (!cs && r) -> goto accept_S2
-       fi;
-accept_S2 :    /* 1 */
-       if
-       :: (!cs) -> goto accept_S2
-       fi;
-}
index c770b80..3a62857 100644 (file)
@@ -2,58 +2,30 @@
 
 p Testing the permissive model
 ! timeout 60
-$ ../../../smpi_script/bin/smpirun -quiet -wrapper "${bindir:=.}/../../../bin/simgrid-mc" -np 2 -platform ${platfdir:=.}/cluster_backbone.xml --cfg=smpi/buffering:infty --log=xbt_cfg.thresh:warning ./smpi_sendsend
+$ $VALGRIND_NO_LEAK_CHECK ../../../smpi_script/bin/smpirun -quiet -wrapper "${bindir:=.}/../../../bin/simgrid-mc" -np 2 -platform ${platfdir:=.}/cluster_backbone.xml --cfg=smpi/buffering:infty --log=xbt_cfg.thresh:warning ./smpi_sendsend
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > Sent 0 to rank 1
 > Sent 1 to rank 0
 > rank 0 recv the data
 > rank 1 recv the data
-> Sent 0 to rank 1
-> Sent 1 to rank 0
-> rank 0 recv the data
-> rank 1 recv the data
-> Sent 0 to rank 1
-> Sent 1 to rank 0
-> rank 1 recv the data
-> rank 0 recv the data
 > Sent 1 to rank 0
-> Sent 0 to rank 1
-> rank 0 recv the data
-> rank 1 recv the data
-> Sent 1 to rank 0
-> Sent 0 to rank 1
-> rank 0 recv the data
-> rank 1 recv the data
-> Sent 1 to rank 0
-> Sent 0 to rank 1
-> rank 1 recv the data
-> rank 0 recv the data
-> Sent 1 to rank 0
-> Sent 0 to rank 1
-> rank 0 recv the data
-> rank 1 recv the data
-> Sent 1 to rank 0
-> Sent 0 to rank 1
-> rank 1 recv the data
-> rank 0 recv the data
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 30 unique states visited; 8 backtracks (56 transition replays, 19 states visited overall)
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 9 unique states visited; 1 backtracks (0 transition replays, 10 states visited overall)
 
 p Testing the paranoid model
 ! timeout 60
 ! expect return 3
-$ ../../../smpi_script/bin/smpirun -quiet -wrapper "${bindir:=.}/../../../bin/simgrid-mc" -np 2 -platform ${platfdir:=.}/cluster_backbone.xml --cfg=smpi/buffering:zero --log=xbt_cfg.thresh:warning ./smpi_sendsend
+$ $VALGRIND_NO_LEAK_CHECK ../../../smpi_script/bin/smpirun -quiet -wrapper "${bindir:=.}/../../../bin/simgrid-mc" -np 2 -platform ${platfdir:=.}/cluster_backbone.xml --cfg=smpi/buffering:zero --log=xbt_cfg.thresh:warning ./smpi_sendsend
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > [0.000000] [mc_global/INFO] **************************
 > [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
 > [0.000000] [mc_global/INFO] **************************
 > [0.000000] [ker_engine/INFO] 2 actors are still running, waiting for something.
 > [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
-> [0.000000] [ker_engine/INFO] Actor 1 (0@node-0.simgrid.org) simcall CommWait(comm_id:1 src:1 dst:-1 mbox:SMPI-2(id:2) srcbuf:1 dstbuf:- bufsize:4)
-> [0.000000] [ker_engine/INFO] Actor 2 (1@node-1.simgrid.org) simcall CommWait(comm_id:2 src:2 dst:-1 mbox:SMPI-1(id:0) srcbuf:2 dstbuf:- bufsize:4)
+> [0.000000] [ker_engine/INFO] Actor 1 (0@node-0.simgrid.org) simcall CommWait(comm_id:1 src:1 dst:-1 mbox:SMPI-2(id:2))
+> [0.000000] [ker_engine/INFO] Actor 2 (1@node-1.simgrid.org) simcall CommWait(comm_id:2 src:2 dst:-1 mbox:SMPI-1(id:3))
 > [0.000000] [mc_global/INFO] Counter-example execution trace:
-> [0.000000] [mc_global/INFO]   1: iSend(mbox=2)
-> [0.000000] [mc_global/INFO]   2: iSend(mbox=0)
-> [0.000000] [mc_global/INFO]   0: 
-> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;2;0'
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 3 unique states visited; 1 backtracks (3 transition replays, 0 states visited overall)
+> [0.000000] [mc_global/INFO]   Actor 1 in :0:() ==> simcall: iSend(mbox=2)
+> [0.000000] [mc_global/INFO]   Actor 2 in :0:() ==> simcall: iSend(mbox=3)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;2'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 3 unique states visited; 0 backtracks (0 transition replays, 3 states visited overall)
 > Execution failed with code 3.
index d6fff83..216f7f3 100644 (file)
@@ -22,7 +22,7 @@ static void action_blah(const simgrid::xbt::ReplayAction& /*args*/)
 
 int main(int argc, char* argv[])
 {
-  auto properties = simgrid::s4u::Actor::self()->get_properties();
+  const auto* properties = simgrid::s4u::Actor::self()->get_properties();
 
   const char* instance_id = properties->at("instance_id").c_str();
   const int rank          = static_cast<int>(xbt_str_parse_int(properties->at("rank").c_str(), "Cannot parse rank"));
index 97f399d..f865162 100644 (file)
@@ -42,8 +42,10 @@ int main(int argc, char *argv[])
     MPI_Send(&msg, 1, MPI_INT, dst, tag1, MPI_COMM_WORLD);
 
     /* Inject five seconds of fake computation time */
-    /* We are in a public file, not internal to simgrid, so _benched flavour is preferred, as it protects against accidental skip */
-    /* smpi_execute_benched here is mostly equivalent to sleep, which is intercepted by smpi and turned into smpi_sleep */
+    /* We are in a public file, not internal to SimGrid, so _benched flavour is preferred, as it protects against
+     * accidental skip */
+    /* smpi_execute_benched here is mostly equivalent to sleep, which is intercepted by smpi and turned into smpi_sleep
+     */
     /* Difference with sleep is only for energy consumption */
     smpi_execute_benched(5.0);
 
@@ -56,7 +58,8 @@ int main(int argc, char *argv[])
     msg++;
 
     /* Inject 762.96 Mflops of computation time - Host Jupiter is 76.296Mf per second, so this should amount to 10s */
-    /* We are in a public file, not internal to simgrid, so _benched flavour is preferred, as it protects against accidental skip */
+    /* We are in a public file, not internal to SimGrid, so _benched flavour is preferred, as it protects against
+     * accidental skip */
     smpi_execute_flops_benched(762960000);
 
     printf("[%d] After a nap, increment message's value to  '%d'\n", rank, msg);
index 0539a00..d81d9fa 100644 (file)
@@ -127,7 +127,10 @@ int main(int argc, char* argv[])
     SMPI_app_instance_start("alltoall_mpi", alltoall_mpi,
                             {e.host_by_name_or_null("Ginette"), e.host_by_name_or_null("Bourassa"),
                              e.host_by_name_or_null("Jupiter"), e.host_by_name_or_null("Fafard")});
+    SMPI_app_instance_join("alltoall_mpi");
+    XBT_INFO("This other alltoall_mpi instance terminated.");
   });
+
   e.run();
 
   XBT_INFO("Simulation time %g", simgrid::s4u::Engine::get_clock());
index 00d5dc8..ba6efdd 100644 (file)
@@ -50,4 +50,5 @@ $ ./masterworker_mailbox_smpi ${srcdir:=.}/../../platforms/small_platform_with_r
 > [Ginette:alltoall_mpi#0:(11) 10.036773] [smpi_masterworkers/INFO] after alltoall 0
 > [Bourassa:alltoall_mpi#1:(12) 10.046578] [smpi_masterworkers/INFO] after alltoall 1
 > [Fafard:alltoall_mpi#3:(14) 10.046865] [smpi_masterworkers/INFO] after alltoall 3
-> [Jupiter:alltoall_mpi#2:(13) 10.046865] [smpi_masterworkers/INFO] after alltoall 2
\ No newline at end of file
+> [Jupiter:alltoall_mpi#2:(13) 10.046865] [smpi_masterworkers/INFO] after alltoall 2
+> [Ginette:launcher:(10) 10.046865] [smpi_masterworkers/INFO] This other alltoall_mpi instance terminated.
\ No newline at end of file
index 9a0cbdc..20a4b07 100644 (file)
@@ -4,7 +4,7 @@
 
 p Test instrumentation of SMPI
 
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-file ${bindir:=.}/smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg --cfg=tracing/smpi/computing:yes --cfg=smpi/simulate-computation:no --cfg=tracing/smpi/sleeping:yes  -np 3 ${bindir:=.}/smpi_trace --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-file ${bindir:=.}/smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=tracing/smpi/computing:yes --cfg=smpi/simulate-computation:no --cfg=tracing/smpi/sleeping:yes  -np 3 ${bindir:=.}/smpi_trace --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
 
 ! output sort 19
 $ tail -n +3 ${bindir:=.}/smpi_trace.trace
@@ -1345,10 +1345,10 @@ $ tail -n +3 ${bindir:=.}/smpi_trace.trace
 
 $ rm -f ${bindir:=.}/smpi_trace.trace
 
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-resource -trace-file ${bindir:=.}/smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg --cfg=smpi/host-speed:1f -np 3 ${bindir:=.}/smpi_trace --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-resource -trace-file ${bindir:=.}/smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=smpi/host-speed:1f -np 3 ${bindir:=.}/smpi_trace --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
 
 $ rm -f ${bindir:=.}/smpi_trace.trace
 
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace --cfg=tracing/smpi/display-sizes:yes --cfg=tracing/smpi/computing:yes --cfg=tracing/smpi/internals:yes -trace-file ${bindir:=.}/smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg --cfg=smpi/host-speed:1f -np 3 ${bindir:=.}/smpi_trace --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace --cfg=tracing/smpi/display-sizes:yes --cfg=tracing/smpi/computing:yes --cfg=tracing/smpi/internals:yes -trace-file ${bindir:=.}/smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=smpi/host-speed:1f -np 3 ${bindir:=.}/smpi_trace --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
 
 $ rm -f ${bindir:=.}/smpi_trace.trace
index c0cd72d..541e177 100644 (file)
@@ -3,19 +3,19 @@
 # Go for the first test
 
 p SMPI test
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-resource -trace-file smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-resource -trace-file smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
 
 p Another SMPI test, with only -trace
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-file smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-file smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
 
 p Testing without trace parameters
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg -np 3 ${bindir:=.}//smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
 
 p Testing grouped tracing
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-grouped -trace-file smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace -trace-grouped -trace-file smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
 
 
 p Testing with parameters but without activating them with the safe switch (-trace)
-$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace-resource -trace-file smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml --cfg=path:${srcdir:=.}/../msg -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
+$ ${bindir:=.}/../../../smpi_script/bin/smpirun -trace-resource -trace-file smpi_trace.trace -hostfile ${srcdir:=.}/../hostfile -platform ${platfdir:=.}/small_platform.xml -np 3 ${bindir:=.}/smpi_trace_simple --log=smpi_config.thres:warning --log=xbt_cfg.thres:warning
 
 $ rm -f smpi_trace.trace
index 3159ccc..a3d8681 100644 (file)
@@ -5,14 +5,13 @@ find_package(Threads REQUIRED)
 #########################################################################
 
 foreach(x
-        mutex-simple
+        mutex-simple mutex-recursive
        producer-consumer)
 
   if("${CMAKE_SYSTEM}" MATCHES "Linux")
     add_executable       (pthread-${x} EXCLUDE_FROM_ALL pthread-${x}.c)
     set_target_properties(pthread-${x} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
     target_link_libraries(pthread-${x} PRIVATE Threads::Threads)
-    target_link_libraries(pthread-${x} PUBLIC "-Wl,-znorelro -Wl,-znoseparate-code") # TODO: convert to target_link_option once CMAKE_VERSION 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)
@@ -35,15 +34,16 @@ endforeach()
 foreach(x
         mutex-simpledeadlock)
 
-  if(SIMGRID_HAVE_MC AND ("${CMAKE_SYSTEM}" MATCHES "Linux")) # sthread is linux-only
+  if("${CMAKE_SYSTEM}" MATCHES "Linux") # sthread is linux-only
 
     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_VERSION is >3.13
 
-    add_dependencies(tests-mc pthread-${x})
-    ADD_TESH_FACTORIES(pthread-mc-${x} "^thread" --setenv libdir=${CMAKE_BINARY_DIR}/lib --cd ${CMAKE_BINARY_DIR}/examples/sthread ${CMAKE_CURRENT_SOURCE_DIR}/pthread-mc-${x}.tesh)
+    if(SIMGRID_HAVE_MC)
+      add_dependencies(tests-mc pthread-${x})
+      ADD_TESH_FACTORIES(pthread-mc-${x} "^thread" --setenv libdir=${CMAKE_BINARY_DIR}/lib --cd ${CMAKE_BINARY_DIR}/examples/sthread ${CMAKE_CURRENT_SOURCE_DIR}/pthread-mc-${x}.tesh)
+    endif()
   endif()
 
   set(tesh_files    ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/pthread-mc-${x}.tesh)
@@ -56,16 +56,17 @@ endforeach()
 foreach(example
         stdobject)
 
-  if(SIMGRID_HAVE_MC AND ("${CMAKE_SYSTEM}" MATCHES "Linux")) # sthread is linux-only
+  if("${CMAKE_SYSTEM}" MATCHES "Linux") # sthread is linux-only
 
     add_executable       (${example} EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.cpp)
     set_target_properties(${example} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
     target_link_libraries(${example} PRIVATE Threads::Threads)
-    target_link_libraries(${example} PUBLIC "-fPIC -Wl,-znorelro -Wl,-znoseparate-code") # TODO: convert to target_link_option once CMAKE_VERSION is >3.13
     set_target_properties(${example} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${example})
 
-    add_dependencies(tests-mc ${example})
-    ADD_TESH_FACTORIES(sthread-mc-${example} "^thread" --setenv libdir=${CMAKE_BINARY_DIR}/lib --cd ${CMAKE_BINARY_DIR}/examples/sthread/${example} ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.tesh)
+    if(SIMGRID_HAVE_MC)
+      add_dependencies(tests-mc ${example})
+      ADD_TESH_FACTORIES(sthread-mc-${example} "^thread" --setenv libdir=${CMAKE_BINARY_DIR}/lib --cd ${CMAKE_BINARY_DIR}/examples/sthread/${example} ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.tesh)
+    endif()
   endif()
 
   set(tesh_files    ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.tesh)
diff --git a/examples/sthread/pthread-mc-mutex-recursive.tesh b/examples/sthread/pthread-mc-mutex-recursive.tesh
new file mode 100644 (file)
index 0000000..4857129
--- /dev/null
@@ -0,0 +1,14 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-recursive
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
+> Got the lock on the default mutex.
+> Failed to relock the default mutex.
+> Got the lock on the recursive mutex.
+> Got the lock again on the recursive mutex.
+> Got the lock on the default mutex.
+> Failed to relock the default mutex.
+> Got the lock on the recursive mutex.
+> Got the lock again on the recursive mutex.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 17 unique states visited; 1 backtracks (3 transition replays, 21 states visited overall)
index 6c9b91c..b352717 100644 (file)
@@ -2,17 +2,13 @@
 # We ignore the LD_PRELOAD lines from the expected output because they contain the build path
 ! ignore .*LD_PRELOAD.*
 
-$ ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simple
-> [0.000000] [sthread/INFO] Starting the simulation.
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simple
 > All threads are started.
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > The thread 0 is terminating.
 > The thread 1 is terminating.
 > User's main is terminating.
-> The thread 0 is terminating.
-> The thread 1 is terminating.
-> User's main is terminating.
 > The thread 1 is terminating.
 > The thread 0 is terminating.
 > User's main is terminating.
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 23 unique states visited; 3 backtracks (27 transition replays, 2 states visited overall)
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 18 unique states visited; 2 backtracks (2 transition replays, 22 states visited overall)
index c6146c5..eaa6b2b 100644 (file)
@@ -1,23 +1,15 @@
 
-# This test raises a deadlock, thus the return code of 3
-! expect return 3
-
 # We ignore the LD_PRELOAD lines from the expected output because they contain the build path
 ! ignore .*LD_PRELOAD.*
 
-$ ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simpledeadlock
-> [0.000000] [sthread/INFO] Starting the simulation.
+# This test raises a deadlock, thus the return code of 3
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simpledeadlock
 > All threads are started.
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > The thread 0 is terminating.
 > The thread 1 is terminating.
 > User's main is terminating.
-> The thread 0 is terminating.
-> The thread 1 is terminating.
-> User's main is terminating.
-> The thread 0 is terminating.
-> The thread 1 is terminating.
-> User's main is terminating.
 > [0.000000] [mc_global/INFO] **************************
 > [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
 > [0.000000] [mc_global/INFO] **************************
@@ -27,12 +19,91 @@ $ ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir
 > [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall MUTEX_WAIT(mutex_id:1 owner:3)
 > [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
 > [0.000000] [mc_global/INFO] Counter-example execution trace:
-> [0.000000] [mc_global/INFO]   2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
-> [0.000000] [mc_global/INFO]   2: MUTEX_WAIT(mutex: 0, owner: 2)
-> [0.000000] [mc_global/INFO]   3: MUTEX_ASYNC_LOCK(mutex: 1, owner: 3)
-> [0.000000] [mc_global/INFO]   2: MUTEX_ASYNC_LOCK(mutex: 1, owner: 3)
-> [0.000000] [mc_global/INFO]   3: MUTEX_WAIT(mutex: 1, owner: 3)
-> [0.000000] [mc_global/INFO]   3: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
-> [0.000000] [mc_global/INFO]   0: 
-> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;2;3;2;3;3;0'
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 38 unique states visited; 4 backtracks (52 transition replays, 11 states visited overall)
\ No newline at end of file
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_WAIT(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_WAIT(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;2;3;2;3;3'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 21 unique states visited; 3 backtracks (11 transition replays, 35 states visited overall)
+
+
+# The return code of a replay is not modified
+! expect return 0
+! output display
+! setenv LD_PRELOAD=${libdir:=.}/libsthread.so
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/pthread-mutex-simpledeadlock --cfg=model-check/replay:'2;2;3;2;3;3'
+
+# The output contains build paths, and cannot be tested with tesh, unfortunately
+# Here, it will produce the following output (if you don't build out of the tree, you'll get another output):
+
+# $ LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simpledeadlock --cfg=model-check/replay:'2;2;3;2;3;3'
+# sthread is intercepting the execution of ./pthread-mutex-simpledeadlock
+# [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/replay' to '2;2;3;2;3;3'
+# [0.000000] [mc_record/INFO] path=2;2;3;2;3;3
+# All threads are started.
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# [0.000000] [mc_record/INFO] * Path chunk #1 '2/0' Actor thread 1(pid:2): MUTEX_ASYNC_LOCK(mutex_id:0 owner:none)
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# Backtrace (displayed in actor thread 1):
+#   ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:26
+#   ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+#   ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+#   ->  #3 thread_fun1 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:21
+# 
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# [0.000000] [mc_record/INFO] * Path chunk #2 '2/0' Actor thread 1(pid:2): MUTEX_WAIT(mutex_id:0 owner:2)
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# Backtrace (displayed in actor thread 1):
+#   ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:29
+#   ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+#   ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+#   ->  #3 thread_fun1 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:21
+# 
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# [0.000000] [mc_record/INFO] * Path chunk #3 '3/0' Actor thread 2(pid:3): MUTEX_ASYNC_LOCK(mutex_id:1 owner:none)
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# Backtrace (displayed in actor thread 2):
+#   ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:26
+#   ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+#   ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+#   ->  #3 thread_fun2 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:31
+# 
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# [0.000000] [mc_record/INFO] * Path chunk #4 '2/0' Actor thread 1(pid:2): MUTEX_ASYNC_LOCK(mutex_id:1 owner:3)
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# Backtrace (displayed in actor thread 1):
+#   ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:26
+#   ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+#   ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+#   ->  #3 thread_fun1 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:22
+# 
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# [0.000000] [mc_record/INFO] * Path chunk #5 '3/0' Actor thread 2(pid:3): MUTEX_WAIT(mutex_id:1 owner:3)
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# Backtrace (displayed in actor thread 2):
+#   ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:29
+#   ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+#   ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+#   ->  #3 thread_fun2 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:31
+# 
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# [0.000000] [mc_record/INFO] * Path chunk #6 '3/0' Actor thread 2(pid:3): MUTEX_ASYNC_LOCK(mutex_id:0 owner:2)
+# [0.000000] [mc_record/INFO] ***********************************************************************************
+# Backtrace (displayed in actor thread 2):
+#   ->  #0 simgrid::s4u::Mutex::lock() at ../../src/s4u/s4u_Mutex.cpp:26
+#   ->  #1 sthread_mutex_lock at ../../src/sthread/sthread_impl.cpp:188
+#   ->  #2 pthread_mutex_lock at ../../src/sthread/sthread.c:141
+#   ->  #3 thread_fun2 at ../../examples/sthread/pthread-mutex-simpledeadlock.c:32
+# 
+# [0.000000] [mc_record/INFO] The replay of the trace is complete. DEADLOCK detected.
+# [0.000000] [ker_engine/INFO] 3 actors are still running, waiting for something.
+# [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+# [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:2)
+# [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall MUTEX_WAIT(mutex_id:1 owner:3)
+# [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+# [0.000000] [sthread/INFO] All threads exited. Terminating the simulation.
+# [0.000000] ../../src/kernel/EngineImpl.cpp:265: [ker_engine/WARNING] Process called exit when leaving - Skipping cleanups
+# [0.000000] ../../src/kernel/EngineImpl.cpp:265: [ker_engine/WARNING] Process called exit when leaving - Skipping cleanups
+# 
index 0766ba3..2ec84f7 100644 (file)
@@ -1,8 +1,16 @@
 # We ignore the LD_PRELOAD lines from the expected output because they contain the build path
 ! ignore .*LD_PRELOAD.*
 
-$ ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/sleep-set:true --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q -c 2 -C 1 -p 2 -P 1
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/sleep-set' to 'true'
-> [0.000000] [sthread/INFO] Starting the simulation.
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q  -C 1 -P 1
 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 719 unique states visited; 83 backtracks (1854 transition replays, 1053 states visited overall)
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 203 unique states visited; 23 backtracks (396 transition replays, 622 states visited overall)
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:sdpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q  -C 1 -P 1
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'sdpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: sdpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 347 unique states visited; 45 backtracks (736 transition replays, 1128 states visited overall)
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q  -C 1 -P 1
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 133 unique states visited; 4 backtracks (58 transition replays, 195 states visited overall)
\ No newline at end of file
diff --git a/examples/sthread/pthread-mutex-recursive.c b/examples/sthread/pthread-mutex-recursive.c
new file mode 100644 (file)
index 0000000..63c9ccc
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright (c) 2002-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/* Code with both recursive and non-recursive mutexes */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// Structure to hold the mutex's name and pointer to the actual mutex
+typedef struct {
+  const char* name;
+  pthread_mutex_t* mutex;
+} ThreadData;
+
+static void* thread_function(void* arg)
+{
+  ThreadData* data       = (ThreadData*)arg;
+  pthread_mutex_t* mutex = data->mutex;
+  const char* name       = data->name;
+
+  pthread_mutex_lock(mutex);
+  fprintf(stderr, "Got the lock on the %s mutex.\n", name);
+
+  // Attempt to relock the mutex - This behavior depends on the mutex type
+  if (pthread_mutex_trylock(mutex) == 0) {
+    fprintf(stderr, "Got the lock again on the %s mutex.\n", name);
+    pthread_mutex_unlock(mutex);
+  } else {
+    fprintf(stderr, "Failed to relock the %s mutex.\n", name);
+  }
+
+  pthread_mutex_unlock(mutex);
+
+  // pthread_exit(NULL); TODO: segfaulting
+  return NULL;
+}
+
+int main()
+{
+  pthread_t thread1;
+  pthread_t thread2;
+  pthread_mutex_t mutex_dflt = PTHREAD_MUTEX_INITIALIZER; // Non-recursive mutex
+
+  pthread_mutexattr_t attr;
+  pthread_mutexattr_init(&attr);
+  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+  pthread_mutex_t mutex_rec;
+  pthread_mutex_init(&mutex_rec, &attr);
+
+  ThreadData data1 = {"default", &mutex_dflt};
+  ThreadData data2 = {"recursive", &mutex_rec};
+
+  pthread_create(&thread1, NULL, thread_function, &data1);
+  pthread_create(&thread2, NULL, thread_function, &data2);
+
+  pthread_join(thread1, NULL);
+  pthread_join(thread2, NULL);
+
+  pthread_mutex_destroy(&mutex_dflt);
+  pthread_mutex_destroy(&mutex_rec);
+
+  return 0;
+}
diff --git a/examples/sthread/pthread-mutex-recursive.tesh b/examples/sthread/pthread-mutex-recursive.tesh
new file mode 100644 (file)
index 0000000..0879b2c
--- /dev/null
@@ -0,0 +1,6 @@
+$ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.}/libsthread.so ./pthread-mutex-recursive
+> Got the lock on the default mutex.
+> Failed to relock the default mutex.
+> Got the lock on the recursive mutex.
+> Got the lock again on the recursive mutex.
+> [0.000000] [sthread/INFO] All threads exited. Terminating the simulation.
index 1d39141..a7dea6b 100644 (file)
@@ -1,3 +1,8 @@
+/* Copyright (c) 2002-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
 /* Simple test code with no bug  */
 
 #include <pthread.h>
index 29d66a9..f4b3f3c 100644 (file)
@@ -1,5 +1,4 @@
 $ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.}/libsthread.so ./pthread-mutex-simple
-> [0.000000] [sthread/INFO] Starting the simulation.
 > All threads are started.
 > The thread 0 is terminating.
 > The thread 1 is terminating.
index 09be6c1..92a04a1 100644 (file)
@@ -1,3 +1,8 @@
+/* Copyright (c) 2002-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
 /* Simple test code that may deadlock:
 
    Thread 1 locks mutex1 then mutex2 while thread 2 locks in reverse order.
index 52a0080..fe3fe5d 100644 (file)
@@ -45,9 +45,10 @@ static void* consumer(void* id)
   for (int i = 0; i < AmountConsumed; i++) {
     sem_wait(&full);
     pthread_mutex_lock(&mutex);
-    int item = buffer[out];
-    if (do_output)
+    if (do_output) {
+      int item = buffer[out];
       fprintf(stderr, "Consumer %d: Remove Item %d from %d\n", *((int*)id), item, out);
+    }
     out = (out + 1) % BufferSize;
     pthread_mutex_unlock(&mutex);
     sem_post(&empty);
index a54bed0..471fbe8 100644 (file)
@@ -1,5 +1,4 @@
 $ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.}/libsthread.so ./pthread-producer-consumer
-> [0.000000] [sthread/INFO] Starting the simulation.
 > Producer 1: Insert Item 0 at 0
 > Producer 2: Insert Item 0 at 1
 > Consumer 1: Remove Item 0 from 0
@@ -15,7 +14,6 @@ $ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.
 > [0.000000] [sthread/INFO] All threads exited. Terminating the simulation.
 
 $ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.}/libsthread.so ./pthread-producer-consumer -c 2 -C 1 -p 2 -P 1
-> [0.000000] [sthread/INFO] Starting the simulation.
 > Producer 1: Insert Item 0 at 0
 > Consumer 1: Remove Item 0 from 0
 > Producer 1: Insert Item 1 at 1
index 06e49c8..c2af786 100644 (file)
@@ -6,13 +6,15 @@
 std::vector<int> v = {1, 2, 3, 5, 8, 13};
 
 extern "C" {
-extern int sthread_access_begin(void* addr, const char* objname, const char* file, int line) __attribute__((weak));
-extern void sthread_access_end(void* addr, const char* objname, const char* file, int line) __attribute__((weak));
+extern int sthread_access_begin(void* addr, const char* objname, const char* file, int line, const char* func)
+    __attribute__((weak));
+extern void sthread_access_end(void* addr, const char* objname, const char* file, int line, const char* func)
+    __attribute__((weak));
 }
 
 #define STHREAD_ACCESS(obj)                                                                                            \
-  for (bool first = sthread_access_begin(static_cast<void*>(obj), #obj, __FILE__, __LINE__) || true; first;            \
-       sthread_access_end(static_cast<void*>(obj), #obj, __FILE__, __LINE__), first = false)
+  for (bool first = sthread_access_begin(static_cast<void*>(obj), #obj, __FILE__, __LINE__, __func__) || true; first;  \
+       sthread_access_end(static_cast<void*>(obj), #obj, __FILE__, __LINE__, __func__), first = false)
 
 static void thread_code()
 {
index 111458a..602c3f4 100644 (file)
@@ -4,9 +4,7 @@
 # We ignore the LD_PRELOAD lines from the expected output because they contain the build path
 ! ignore .*LD_PRELOAD.*
 
-$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/stdobject "--log=root.fmt:[%11.6r]%e(%a@%h)%e%m%n" --log=no_loc
-> [   0.000000] (maestro@) Configuration change: Set 'model-check/sleep-set' to 'true'
-> [   0.000000] (maestro@) Starting the simulation.
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/stdobject "--log=root.fmt:[%11.6r]%e(%a@%h)%e%m%n" --log=no_loc
 > starting two helpers...
 > waiting for helpers to finish...
 > [   0.000000] (maestro@) Start a DFS exploration. Reduction is: dpor.
@@ -17,12 +15,12 @@ $ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/sleep-set:true --cfg=mo
 > v = { 1, 2, 3, 5, 8, 13, 21, 21, }; 
 > [   0.000000] (maestro@) thread 1 takes &v
 > [   0.000000] (maestro@) thread 2 takes &v
-> [   0.000000] (maestro@) Unprotected concurent access to &v: thread 1 vs thread 2 (locations hidden because of --log=no_loc).
+> [   0.000000] (maestro@) Unprotected concurent access to &v: thread 1 from 1 location vs thread 2 (locations hidden because of --log=no_loc).
 > [   0.000000] (maestro@) **************************
 > [   0.000000] (maestro@) *** PROPERTY NOT VALID ***
 > [   0.000000] (maestro@) **************************
 > [   0.000000] (maestro@) Counter-example execution trace:
-> [   0.000000] (maestro@)   2: BeginObjectAccess(&v)
-> [   0.000000] (maestro@)   3: BeginObjectAccess(&v)
+> [   0.000000] (maestro@)   Actor 2 in simcall BeginObjectAccess(&v)
+> [   0.000000] (maestro@)   Actor 3 in simcall BeginObjectAccess(&v)
 > [   0.000000] (maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;3'
-> [   0.000000] (maestro@) DFS exploration ended. 7 unique states visited; 1 backtracks (9 transition replays, 1 states visited overall)
+> [   0.000000] (maestro@) DFS exploration ended. 7 unique states visited; 1 backtracks (1 transition replays, 9 states visited overall)
index ffa04c1..67afd1a 100644 (file)
@@ -1,5 +1,4 @@
 $ ./sthread-mutex-simple
-> [0.000000] [sthread/INFO] Starting the simulation.
 > All threads are started.
 > The thread 0 is terminating.
 > The thread 1 is terminating.
index 63a44e4..4b14e56 100644 (file)
@@ -185,7 +185,7 @@ public:
   const char* what() const noexcept { return msg_.c_str(); }
 
   XBT_ATTRIB_NORETURN static void do_throw();
-  XBT_ATTRIB_DEPRECATED_v337("Please manifest if you actually need this function") static bool try_n_catch(
+  XBT_ATTRIB_DEPRECATED_v338("Please manifest if you actually need this function") static bool try_n_catch(
       const std::function<void()>& try_block);
 
 private:
diff --git a/include/simgrid/activity_set.h b/include/simgrid/activity_set.h
new file mode 100644 (file)
index 0000000..9f80ad7
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (c) 2018-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef INCLUDE_SIMGRID_ACTIVITY_SET_H
+#define INCLUDE_SIMGRID_ACTIVITY_SET_H
+
+#include <simgrid/forward.h>
+#include <sys/types.h> /* ssize_t */
+
+/* C interface */
+SG_BEGIN_DECL
+
+XBT_PUBLIC sg_activity_set_t sg_activity_set_init();
+XBT_PUBLIC void sg_activity_set_push(sg_activity_set_t as, sg_activity_t acti);
+XBT_PUBLIC void sg_activity_set_erase(sg_activity_set_t as, sg_activity_t acti);
+XBT_PUBLIC size_t sg_activity_set_size(sg_activity_set_t as);
+XBT_PUBLIC int sg_activity_set_empty(sg_activity_set_t as);
+
+XBT_PUBLIC sg_activity_t sg_activity_set_test_any(sg_activity_set_t as);
+XBT_PUBLIC void sg_activity_set_wait_all(sg_activity_set_t as);
+/** Returns true if it terminated successfully (or false on timeout) */
+XBT_PUBLIC int sg_activity_set_wait_all_for(sg_activity_set_t as, double timeout);
+XBT_PUBLIC sg_activity_t sg_activity_set_wait_any(sg_activity_set_t as);
+XBT_PUBLIC sg_activity_t sg_activity_set_wait_any_for(sg_activity_set_t as, double timeout);
+XBT_PUBLIC void sg_activity_set_delete(sg_activity_set_t as);
+
+/** You must call this function manually on activities extracted from an activity_set with waitany and friends */
+XBT_PUBLIC void sg_activity_unref(sg_activity_t acti);
+
+SG_END_DECL
+
+#endif /* INCLUDE_SIMGRID_ACTIVITY_SET_H */
index ee5f5e7..538122f 100644 (file)
 /* C interface */
 SG_BEGIN_DECL
 
+XBT_PUBLIC int sg_comm_isinstance(sg_activity_t acti);
+
 XBT_PUBLIC void sg_comm_detach(sg_comm_t comm, void (*clean_function)(void*));
 XBT_PUBLIC int sg_comm_test(sg_comm_t comm);
 XBT_PUBLIC sg_error_t sg_comm_wait(sg_comm_t comm);
 XBT_PUBLIC sg_error_t sg_comm_wait_for(sg_comm_t comm, double timeout);
-XBT_PUBLIC void sg_comm_wait_all(sg_comm_t* comms, size_t count);
-XBT_PUBLIC size_t sg_comm_wait_all_for(sg_comm_t* comms, size_t count, double timeout);
-XBT_PUBLIC ssize_t sg_comm_wait_any_for(sg_comm_t* comms, size_t count, double timeout);
-XBT_PUBLIC ssize_t sg_comm_wait_any(sg_comm_t* comms, size_t count);
 XBT_PUBLIC void sg_comm_unref(sg_comm_t comm);
 
+#ifndef DOXYGEN
+XBT_ATTRIB_DEPRECATED_v339("Please use sg_activity_set_t instead") XBT_PUBLIC
+    void sg_comm_wait_all(sg_comm_t* comms, size_t count);
+XBT_ATTRIB_DEPRECATED_v339("Please use sg_activity_set_t instead") XBT_PUBLIC
+    ssize_t sg_comm_wait_any_for(sg_comm_t* comms, size_t count, double timeout);
+XBT_ATTRIB_DEPRECATED_v339("Please use sg_activity_set_t instead") XBT_PUBLIC
+    ssize_t sg_comm_wait_any(sg_comm_t* comms, size_t count);
+#endif
+
 SG_END_DECL
 
 #endif /* INCLUDE_SIMGRID_COMM_H_ */
index d3ff02b..b5b6524 100644 (file)
@@ -51,9 +51,9 @@ XBT_PUBLIC void simgrid_set_maestro(void (*code)(void*), void* data);
 
 /** @brief Allow other libraries to react to the --help flag, too
  *
- * When finding --help on the command line, simgrid usually stops right after displaying its help message.
- * If you are writing a library using simgrid, you may want to display your own help message before everything stops.
- * If so, just call this function before having simgrid parsing the command line, and you will be given the control
+ * When finding --help on the command line, SimGrid usually stops right after displaying its help message.
+ * If you are writing a library using SimGrid, you may want to display your own help message before everything stops.
+ * If so, just call this function before having SimGrid parsing the command line, and you will be given the control
  * even if the user is asking for help.
  */
 XBT_PUBLIC void sg_config_continue_after_help();
index 42e413b..565684c 100644 (file)
@@ -12,6 +12,8 @@
 /* C interface */
 SG_BEGIN_DECL
 
+XBT_PUBLIC int sg_exec_isinstance(sg_activity_t acti);
+
 XBT_PUBLIC void sg_exec_set_bound(sg_exec_t exec, double bound);
 XBT_PUBLIC const char* sg_exec_get_name(const_sg_exec_t exec);
 XBT_PUBLIC void sg_exec_set_name(sg_exec_t exec, const char* name);
@@ -24,8 +26,11 @@ XBT_PUBLIC void sg_exec_cancel(sg_exec_t exec);
 XBT_PUBLIC int sg_exec_test(sg_exec_t exec);
 XBT_PUBLIC sg_error_t sg_exec_wait(sg_exec_t exec);
 XBT_PUBLIC sg_error_t sg_exec_wait_for(sg_exec_t exec, double timeout);
-XBT_PUBLIC ssize_t sg_exec_wait_any_for(sg_exec_t* execs, size_t count, double timeout);
-XBT_PUBLIC ssize_t sg_exec_wait_any(sg_exec_t* execs, size_t count);
+
+XBT_ATTRIB_DEPRECATED_v339("Please use sg_activity_set_t instead") XBT_PUBLIC ssize_t
+    sg_exec_wait_any_for(sg_exec_t* execs, size_t count, double timeout);
+XBT_ATTRIB_DEPRECATED_v339("Please use sg_activity_set_t instead") XBT_PUBLIC ssize_t
+    sg_exec_wait_any(sg_exec_t* execs, size_t count);
 
 SG_END_DECL
 
index dae9277..e2a0606 100644 (file)
@@ -19,8 +19,14 @@ namespace s4u {
 class Activity;
 /** Smart pointer to a simgrid::s4u::Activity */
 using ActivityPtr = boost::intrusive_ptr<Activity>;
-XBT_PUBLIC void intrusive_ptr_release(const Activity* actor);
-XBT_PUBLIC void intrusive_ptr_add_ref(const Activity* actor);
+XBT_PUBLIC void intrusive_ptr_release(const Activity* act);
+XBT_PUBLIC void intrusive_ptr_add_ref(const Activity* act);
+
+class ActivitySet;
+/** Smart pointer to a simgrid::s4u::Activity */
+using ActivitySetPtr = boost::intrusive_ptr<ActivitySet>;
+XBT_PUBLIC void intrusive_ptr_release(const ActivitySet* as);
+XBT_PUBLIC void intrusive_ptr_add_ref(const ActivitySet* as);
 
 class Actor;
 /** Smart pointer to a simgrid::s4u::Actor */
@@ -31,8 +37,8 @@ XBT_PUBLIC void intrusive_ptr_add_ref(const Actor* actor);
 class Barrier;
 /** Smart pointer to a simgrid::s4u::Barrier */
 using BarrierPtr = boost::intrusive_ptr<Barrier>;
-XBT_PUBLIC void intrusive_ptr_release(Barrier* m);
-XBT_PUBLIC void intrusive_ptr_add_ref(Barrier* m);
+XBT_PUBLIC void intrusive_ptr_release(Barrier* b);
+XBT_PUBLIC void intrusive_ptr_add_ref(Barrier* b);
 
 class Comm;
 /** Smart pointer to a simgrid::s4u::Comm */
@@ -70,6 +76,14 @@ class SplitDuplexLink;
 
 class Mailbox;
 
+class Mess;
+/** Smart pointer to a simgrid::s4u::Mess */
+using MessPtr = boost::intrusive_ptr<Mess>;
+XBT_PUBLIC void intrusive_ptr_release(Mess* c);
+XBT_PUBLIC void intrusive_ptr_add_ref(Mess* c);
+
+class MessageQueue;
+
 class Mutex;
 XBT_PUBLIC void intrusive_ptr_release(const Mutex* m);
 XBT_PUBLIC void intrusive_ptr_add_ref(const Mutex* m);
@@ -91,6 +105,19 @@ XBT_PUBLIC void intrusive_ptr_release(const Semaphore* m);
 XBT_PUBLIC void intrusive_ptr_add_ref(const Semaphore* m);
 
 class Disk;
+
+class Task;
+/** Smart pointer to a simgrid::s4u::Task */
+using TaskPtr = boost::intrusive_ptr<Task>;
+XBT_PUBLIC void intrusive_ptr_release(Task* o);
+XBT_PUBLIC void intrusive_ptr_add_ref(Task* o);
+class ExecTask;
+using ExecTaskPtr = boost::intrusive_ptr<ExecTask>;
+class CommTask;
+using CommTaskPtr = boost::intrusive_ptr<CommTask>;
+class IoTask;
+using IoTaskPtr = boost::intrusive_ptr<IoTask>;
+
 /**
  * @brief Callback to dynamically change the resource's capacity
  *
@@ -117,6 +144,8 @@ using ActorCodeFactory = std::function<ActorCode(std::vector<std::string> args)>
 
 class Simcall;
 class SimcallObserver;
+class MutexObserver;
+class ConditionVariableObserver;
 class ObjectAccessSimcallObserver;
 class ObjectAccessSimcallItem;
 } // namespace actor
@@ -139,6 +168,8 @@ namespace activity {
   using ConditionVariableImplPtr = boost::intrusive_ptr<ConditionVariableImpl>;
   XBT_PUBLIC void intrusive_ptr_add_ref(ConditionVariableImpl* cond);
   XBT_PUBLIC void intrusive_ptr_release(ConditionVariableImpl* cond);
+  class ConditionVariableAcquisitionImpl;
+  using ConditionVariableAcquisitionImplPtr = boost::intrusive_ptr<ConditionVariableAcquisitionImpl>;
 
   class CommImpl;
   using CommImplPtr = boost::intrusive_ptr<CommImpl>;
@@ -146,6 +177,8 @@ namespace activity {
   using ExecImplPtr = boost::intrusive_ptr<ExecImpl>;
   class IoImpl;
   using IoImplPtr = boost::intrusive_ptr<IoImpl>;
+  class MessImpl;
+  using MessImplPtr = boost::intrusive_ptr<MessImpl>;
   class MutexImpl;
   using MutexImplPtr = boost::intrusive_ptr<MutexImpl>;
   class MutexAcquisitionImpl;
@@ -164,6 +197,7 @@ namespace activity {
   using SleepImplPtr = boost::intrusive_ptr<SleepImpl>;
 
   class MailboxImpl;
+  class MessageQueueImpl;
 }
 namespace context {
 class Context;
@@ -178,6 +212,7 @@ class System;
 }
 namespace resource {
 class Action;
+class CpuAction;
 class CpuImpl;
 class Model;
 class Resource;
@@ -190,6 +225,7 @@ class StandardLinkImpl;
 class SplitDuplexLinkImpl;
 class NetworkAction;
 class DiskImpl;
+using DiskImplPtr = boost::intrusive_ptr<DiskImpl>;
 class DiskModel;
 class VirtualMachineImpl;
 class VMModel;
@@ -214,6 +250,8 @@ class RemoteApp;
 } // namespace simgrid
 
 using s4u_Actor             = simgrid::s4u::Actor;
+using s4u_Activity          = simgrid::s4u::Activity;
+using s4u_ActivitySet       = simgrid::s4u::ActivitySet;
 using s4u_Barrier           = simgrid::s4u::Barrier;
 using s4u_Comm              = simgrid::s4u::Comm;
 using s4u_Exec              = simgrid::s4u::Exec;
@@ -222,28 +260,19 @@ using s4u_Link              = simgrid::s4u::Link;
 using s4u_File              = simgrid::s4u::File;
 using s4u_ConditionVariable = simgrid::s4u::ConditionVariable;
 using s4u_Mailbox           = simgrid::s4u::Mailbox;
+using s4u_MessageQueue      = simgrid::s4u::MessageQueue;
 using s4u_Mutex             = simgrid::s4u::Mutex;
 using s4u_Semaphore         = simgrid::s4u::Semaphore;
 using s4u_Disk              = simgrid::s4u::Disk;
 using s4u_NetZone           = simgrid::s4u::NetZone;
 using s4u_VM                = simgrid::s4u::VirtualMachine;
 
-using smx_timer_t
-    XBT_ATTRIB_DEPRECATED_v335("Please use simgrid::kernel::timer::Timer*") = simgrid::kernel::timer::Timer*;
-using smx_actor_t
-    XBT_ATTRIB_DEPRECATED_v335("Please use simgrid::kernel::actor::ActorImpl*") = simgrid::kernel::actor::ActorImpl*;
 using smx_activity_t = simgrid::kernel::activity::ActivityImpl*;
-using smx_cond_t XBT_ATTRIB_DEPRECATED_v335("Please use simgrid::kernel::activity::ConditionVariableImpl*") =
-    simgrid::kernel::activity::ConditionVariableImpl*;
-using smx_mailbox_t XBT_ATTRIB_DEPRECATED_v335("Please use simgrid::kernel::activity::MailboxImpl*") =
-    simgrid::kernel::activity::MailboxImpl*;
-using smx_mutex_t XBT_ATTRIB_DEPRECATED_v335("Please use simgrid::kernel::activity::MutexImpl*") =
-    simgrid::kernel::activity::MutexImpl*;
-using smx_sem_t XBT_ATTRIB_DEPRECATED_v335("Please use simgrid::kernel::activity::SemaphoreImpl*") =
-    simgrid::kernel::activity::SemaphoreImpl*;
 #else
 
 typedef struct s4u_Actor s4u_Actor;
+typedef struct s4u_Activity s4u_Activity;
+typedef struct s4u_ActivitySet s4u_ActivitySet;
 typedef struct s4u_Barrier s4u_Barrier;
 typedef struct s4u_Comm s4u_Comm;
 typedef struct s4u_Exec s4u_Exec;
@@ -252,34 +281,28 @@ typedef struct s4u_Link s4u_Link;
 typedef struct s4u_File s4u_File;
 typedef struct s4u_ConditionVariable s4u_ConditionVariable;
 typedef struct s4u_Mailbox s4u_Mailbox;
+typedef struct s4u_MessageQueue s4u_MessageQueue;
 typedef struct s4u_Mutex s4u_Mutex;
 typedef struct s4u_Semaphore s4u_Semaphore;
 typedef struct s4u_Disk s4u_Disk;
 typedef struct s4u_NetZone s4u_NetZone;
 typedef struct s4u_VM s4u_VM;
 
-XBT_ATTRIB_DEPRECATED_v335("Please stop using this type alias") typedef struct s_smx_timer* smx_timer_t;
-XBT_ATTRIB_DEPRECATED_v335("Please stop using this type alias") typedef struct s_smx_actor* smx_actor_t;
 typedef struct s_smx_activity* smx_activity_t;
-XBT_ATTRIB_DEPRECATED_v335("Please stop using this type alias") typedef struct s_smx_cond_t* smx_cond_t;
-XBT_ATTRIB_DEPRECATED_v335("Please stop using this type alias") typedef struct s_smx_mailbox* smx_mailbox_t;
-XBT_ATTRIB_DEPRECATED_v335("Please stop using this type alias") typedef struct s_smx_mutex* smx_mutex_t;
-XBT_ATTRIB_DEPRECATED_v335("Please stop using this type alias") typedef struct s_smx_sem* smx_sem_t;
 
 #endif
 
 /** Pointer to a SimGrid barrier object */
 typedef s4u_Barrier* sg_bar_t;
-/** Constant pointer to a SimGrid barrier object */
-XBT_ATTRIB_DEPRECATED_v335("Please stop using this type alias") typedef const s4u_Barrier* const_sg_bar_t;
 typedef s4u_Comm* sg_comm_t;
-XBT_ATTRIB_DEPRECATED_v335("Please stop using this type alias") typedef const s4u_Comm* const_sg_comm_t;
 typedef s4u_Exec* sg_exec_t;
 typedef const s4u_Exec* const_sg_exec_t;
 typedef s4u_ConditionVariable* sg_cond_t;
 typedef const s4u_ConditionVariable* const_sg_cond_t;
 typedef s4u_Mailbox* sg_mailbox_t;
 typedef const s4u_Mailbox* const_sg_mailbox_t;
+typedef s4u_MessageQueue* sg_messagequeue_t;
+typedef const s4u_MessageQueue* const_sg_messagequeue_t;
 typedef s4u_Mutex* sg_mutex_t;
 typedef const s4u_Mutex* const_sg_mutex_t;
 typedef s4u_Semaphore* sg_sem_t;
@@ -303,13 +326,23 @@ typedef s4u_Actor* sg_actor_t;
 /** Pointer to a constant actor object */
 typedef const s4u_Actor* const_sg_actor_t;
 
+/** Pointer to an activity object */
+typedef s4u_Activity* sg_activity_t;
+/** Pointer to a constant activity object */
+typedef const s4u_Activity* const_sg_activity_t;
+
+/** Pointer to an activity set object */
+typedef s4u_ActivitySet* sg_activity_set_t;
+/** Pointer to a constant activity set object */
+typedef const s4u_ActivitySet* const_sg_activity_set_t;
+
 /** @ingroup m_datatypes_management_details
- * @brief Type for any simgrid size
+ * @brief Type for any SimGrid size
  */
 typedef unsigned long long sg_size_t;
 
 /** @ingroup m_datatypes_management_details
- * @brief Type for any simgrid offset
+ * @brief Type for any SimGrid offset
  */
 typedef long long sg_offset_t;
 
index e828dce..57c0a94 100644 (file)
@@ -115,9 +115,6 @@ XBT_PUBLIC double sg_host_get_route_latency(const_sg_host_t from, const_sg_host_
 XBT_PUBLIC double sg_host_get_route_bandwidth(const_sg_host_t from, const_sg_host_t to);
 XBT_PUBLIC void sg_host_sendto(sg_host_t from, sg_host_t to, double byte_amount);
 
-XBT_ATTRIB_DEPRECATED_v335("Please manifest if you actually need this function") XBT_PUBLIC
-    void sg_host_dump(const_sg_host_t ws);
-
 XBT_PUBLIC void sg_host_get_actor_list(const_sg_host_t host, xbt_dynar_t whereto);
 SG_END_DECL
 
index 7fee147..91ff4e9 100644 (file)
@@ -7,14 +7,12 @@
 #define INSTR_H_
 
 #include <simgrid/engine.h>
-#include <xbt/dynar.h> // XBT_ATTRIB_DEPRECATED_v334
 
 #ifdef __cplusplus
 #include <set>
 #include <string>
 
-namespace simgrid {
-namespace instr {
+namespace simgrid::instr {
 /* User-variables related functions*/
 /* for host variables */
 XBT_PUBLIC void declare_host_variable(const std::string& variable, const std::string& color = "");
@@ -67,8 +65,7 @@ XBT_PUBLIC const std::set<std::string, std::less<>>& get_tracing_categories();
 XBT_PUBLIC void platform_graph_export_graphviz(const std::string& output_filename);
 /* Function used by graphicator (transform a SimGrid platform file in a CSV file with the network topology) */
 XBT_PUBLIC void platform_graph_export_csv(const std::string& output_filename);
-} // namespace instr
-} // namespace simgrid
+} // namespace simgrid::instr
 
 #endif
 SG_BEGIN_DECL
@@ -82,92 +79,6 @@ XBT_PUBLIC void TRACE_host_set_state(const char* host, const char* state, const
 XBT_PUBLIC void TRACE_host_push_state(const char* host, const char* state, const char* value);
 XBT_PUBLIC void TRACE_host_pop_state(const char* host, const char* state);
 
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::platform_graph_export_graphviz") XBT_PUBLIC
-    int TRACE_platform_graph_export_graphviz(const char* filename);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_tracing_category") XBT_PUBLIC
-    void TRACE_category(const char* category);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_tracing_category") XBT_PUBLIC
-    void TRACE_category_with_color(const char* category, const char* color);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::get_tracing_categories") XBT_PUBLIC xbt_dynar_t
-    TRACE_get_categories();
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_mark") XBT_PUBLIC
-    void TRACE_declare_mark(const char* mark_type);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_mark_value") XBT_PUBLIC
-    void TRACE_declare_mark_value_with_color(const char* mark_type, const char* mark_value, const char* mark_color);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_mark_value") XBT_PUBLIC
-    void TRACE_declare_mark_value(const char* mark_type, const char* mark_value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::mark") XBT_PUBLIC
-    void TRACE_mark(const char* mark_type, const char* mark_value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::get_marks") XBT_PUBLIC xbt_dynar_t TRACE_get_marks();
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_vm_variable") XBT_PUBLIC
-    void TRACE_vm_variable_declare(const char* variable);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_vm_variable") XBT_PUBLIC
-    void TRACE_vm_variable_declare_with_color(const char* variable, const char* color);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::set_vm_variable") XBT_PUBLIC
-    void TRACE_vm_variable_set(const char* vm, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::add_vm_variable") XBT_PUBLIC
-    void TRACE_vm_variable_add(const char* vm, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::sub_vm_variable") XBT_PUBLIC
-    void TRACE_vm_variable_sub(const char* vm, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::set_vm_variable") XBT_PUBLIC
-    void TRACE_vm_variable_set_with_time(double time, const char* vm, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::add_vm_variable") XBT_PUBLIC
-    void TRACE_vm_variable_add_with_time(double time, const char* vm, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::sub_vm_variable") XBT_PUBLIC
-    void TRACE_vm_variable_sub_with_time(double time, const char* vm, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_host_variable") XBT_PUBLIC
-    void TRACE_host_variable_declare(const char* variable);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_host_variable") XBT_PUBLIC
-    void TRACE_host_variable_declare_with_color(const char* variable, const char* color);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::set_host_variable") XBT_PUBLIC
-    void TRACE_host_variable_set(const char* host, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::add_host_variable") XBT_PUBLIC
-    void TRACE_host_variable_add(const char* host, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::sub_host_variable") XBT_PUBLIC
-    void TRACE_host_variable_sub(const char* host, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::set_host_variable") XBT_PUBLIC
-    void TRACE_host_variable_set_with_time(double time, const char* host, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::add_host_variable") XBT_PUBLIC
-    void TRACE_host_variable_add_with_time(double time, const char* host, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::sub_host_variable") XBT_PUBLIC
-    void TRACE_host_variable_sub_with_time(double time, const char* host, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::get_host_variables") XBT_PUBLIC xbt_dynar_t
-    TRACE_get_host_variables();
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_link_variable") XBT_PUBLIC
-    void TRACE_link_variable_declare(const char* var);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::declare_link_variable") XBT_PUBLIC
-    void TRACE_link_variable_declare_with_color(const char* var, const char* color);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::set_link_variable") XBT_PUBLIC
-    void TRACE_link_variable_set(const char* link, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::add_link_variable") XBT_PUBLIC
-    void TRACE_link_variable_add(const char* link, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::sub_link_variable") XBT_PUBLIC
-    void TRACE_link_variable_sub(const char* link, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::set_link_variable") XBT_PUBLIC
-    void TRACE_link_variable_set_with_time(double time, const char* link, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::add_link_variable") XBT_PUBLIC
-    void TRACE_link_variable_add_with_time(double time, const char* link, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::sub_link_variable") XBT_PUBLIC
-    void TRACE_link_variable_sub_with_time(double time, const char* link, const char* variable, double value);
-
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::set_link_variable") XBT_PUBLIC
-    void TRACE_link_srcdst_variable_set(const char* src, const char* dst, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::add_link_variable") XBT_PUBLIC
-    void TRACE_link_srcdst_variable_add(const char* src, const char* dst, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr:sub_link_variable") XBT_PUBLIC
-    void TRACE_link_srcdst_variable_sub(const char* src, const char* dst, const char* variable, double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::set_link_variable") XBT_PUBLIC
-    void TRACE_link_srcdst_variable_set_with_time(double time, const char* src, const char* dst, const char* variable,
-                                                  double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::add_link_variable") XBT_PUBLIC
-    void TRACE_link_srcdst_variable_add_with_time(double time, const char* src, const char* dst, const char* variable,
-                                                  double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr:sub_link_variable") XBT_PUBLIC
-    void TRACE_link_srcdst_variable_sub_with_time(double time, const char* src, const char* dst, const char* variable,
-                                                  double value);
-XBT_ATTRIB_DEPRECATED_v334("Please use simgrid::instr::get_link_variables") XBT_PUBLIC xbt_dynar_t
-    TRACE_get_link_variables();
-
 SG_END_DECL
 
 #endif /* INSTR_H_ */
index 8e72a2d..8ec4f7c 100644 (file)
@@ -9,10 +9,7 @@
 #include <simgrid/forward.h>
 #include <functional>
 
-namespace simgrid {
-namespace kernel {
-namespace profile {
-
+namespace simgrid::kernel::profile {
 
 /** @brief Modeling of the availability profile (due to an external load) or the churn
  *
@@ -75,8 +72,6 @@ public:
   static Profile* from_callback(const std::string& name, const std::function<UpdateCb>& cb, double repeat_delay);
 };
 
-} // namespace profile
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::profile
 
 #endif /* SIMGRID_KERNEL_PROFILEBUILDER_HPP */
index 3a98068..010a66f 100644 (file)
@@ -12,9 +12,7 @@
 
 #include <boost/heap/fibonacci_heap.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace timer {
+namespace simgrid::kernel::timer {
 
 inline auto& kernel_timers() // avoid static initialization order fiasco
 {
@@ -48,8 +46,6 @@ public:
   static bool execute_all();
 };
 
-} // namespace timer
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::timer
 
 #endif /* SRC_KERNEL_TIMER_TIMER_HPP_ */
index 613ae78..48b1143 100644 (file)
 #include <boost/heap/pairing_heap.hpp>
 #include <boost/optional.hpp>
 #include <string>
+#include <string_view>
 
 static constexpr double NO_MAX_DURATION = -1.0;
 
-namespace simgrid {
-namespace kernel {
-namespace resource {
+namespace simgrid::kernel::resource {
 
 using heap_element_type = std::pair<double, Action*>;
 using heap_type =
@@ -68,7 +67,6 @@ class XBT_PUBLIC Action {
 
   double cost_;
   Model* model_;
-  void* data_                       = nullptr; /**< for your convenience - XBT_ATTRIB_DEPRECATED_v334 */
   activity::ActivityImpl* activity_ = nullptr;
 
   /* LMM */
@@ -157,17 +155,6 @@ public:
   /** @brief Get the finish time of the current action */
   double get_finish_time() const { return finish_time_; }
 
-  /** @brief Get the user data associated to the current action */
-  XBT_ATTRIB_DEPRECATED_v334("Please manifest if you actually need this function") void* get_data() const
-  {
-    return data_;
-  }
-  /** @brief Set the user data associated to the current action */
-  XBT_ATTRIB_DEPRECATED_v334("Please manifest if you actually need this function") void set_data(void* data)
-  {
-    data_ = data;
-  }
-
   /** @brief Get the user data associated to the current action */
   activity::ActivityImpl* get_activity() const { return activity_; }
   /** @brief Set the user data associated to the current action */
@@ -227,7 +214,7 @@ public:
   /** @brief Get the tracing category associated to the current action */
   const std::string& get_category() const { return category_; }
   /** @brief Set the tracing category of the current Action */
-  void set_category(const std::string& category) { category_ = category; }
+  void set_category(std::string_view category) { category_ = category; }
 
   /** @brief Get the sharing_penalty (RTT or 1/thread_count) of the current Action */
   double get_sharing_penalty() const { return sharing_penalty_; };
@@ -273,7 +260,5 @@ public:
   void set_suspend_state(Action::SuspendStates state) { suspended_ = state; }
 };
 
-} // namespace resource
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::resource
 #endif
index 87f8eee..3a5affb 100644 (file)
@@ -10,9 +10,7 @@
 #include <simgrid/kernel/resource/Action.hpp>
 #include <unordered_map>
 
-namespace simgrid {
-namespace kernel {
-namespace resource {
+namespace simgrid::kernel::resource {
 
 class XBT_PUBLIC Model {
 public:
@@ -110,8 +108,6 @@ private:
   ActionHeap action_heap_;
 };
 
-} // namespace resource
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::resource
 
 #endif
index b08bba7..8fc4512 100644 (file)
@@ -11,9 +11,7 @@
 
 #include <unordered_map>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /**
  * @brief Placeholder for old ClusterZone class
@@ -150,8 +148,6 @@ public:
     return node_pos_with_loopback(id) + (has_limiter_ ? 1 : 0);
   }
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_CLUSTER_HPP_ */
index fa4c176..dbaef58 100644 (file)
@@ -8,9 +8,7 @@
 
 #include <simgrid/kernel/routing/RoutedZone.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief NetZone with an explicit routing computed on need with Dijkstra
@@ -53,8 +51,6 @@ public:
   void add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
                  const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) override;
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_DIJKSTRA_HPP_ */
index 558af8d..acb1122 100644 (file)
@@ -9,9 +9,7 @@
 #include <simgrid/kernel/routing/ClusterZone.hpp>
 #include <simgrid/s4u/Link.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 class DragonflyRouter {
 public:
@@ -109,7 +107,5 @@ private:
   unsigned int num_links_per_link_     = 1; // splitduplex -> 2, only for local link
   std::vector<DragonflyRouter> routers_;
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 #endif
index 7240493..f5fd334 100644 (file)
@@ -9,9 +9,7 @@
 #include <simgrid/kernel/routing/NetZoneImpl.hpp>
 #include <xbt/asserts.h>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief NetZone with no routing, useful with the constant network model
@@ -32,8 +30,6 @@ public:
   void get_graph(const s_xbt_graph_t* graph, std::map<std::string, xbt_node_t, std::less<>>* /*nodes*/,
                  std::map<std::string, xbt_edge_t, std::less<>>* /*edges*/) override;
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_NONE_HPP_ */
index a0623a2..fabeea2 100644 (file)
@@ -8,9 +8,7 @@
 
 #include <simgrid/kernel/routing/ClusterZone.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 class XBT_PRIVATE FatTreeLink;
 
@@ -159,8 +157,6 @@ public:
   void build_upper_levels(const s4u::ClusterCallbacks& set_callbacks);
   void generate_dot_file(const std::string& filename = "fat_tree.dot") const;
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif
index a384746..6cfaa76 100644 (file)
@@ -8,9 +8,7 @@
 
 #include <simgrid/kernel/routing/RoutedZone.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief NetZone with an explicit routing computed at initialization with Floyd-Warshal
@@ -39,8 +37,6 @@ public:
   void add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
                  const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) override;
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_FLOYD_HPP_ */
index 5e34451..3a83895 100644 (file)
@@ -8,9 +8,7 @@
 
 #include <simgrid/kernel/routing/RoutedZone.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief NetZone with an explicit routing provided by the user
@@ -33,8 +31,6 @@ public:
   void add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
                  const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) override;
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_FULL_HPP_ */
index 566eee3..aca2452 100644 (file)
@@ -16,8 +16,7 @@ namespace simgrid {
 
 extern template class XBT_PUBLIC xbt::Extendable<kernel::routing::NetPoint>;
 
-namespace kernel {
-namespace routing {
+namespace kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief Network cards are the vertices in the graph representing the network, used to compute paths between nodes.
@@ -54,8 +53,7 @@ private:
   NetPoint::Type component_type_;
   NetZoneImpl* englobing_zone_ = nullptr;
 };
-} // namespace routing
-} // namespace kernel
+} // namespace kernel::routing
 } // namespace simgrid
 
 XBT_PUBLIC simgrid::kernel::routing::NetPoint* sg_netpoint_by_name_or_null(const char* name);
index b7d16fb..ed13e52 100644 (file)
@@ -16,9 +16,7 @@
 #include <unordered_set>
 #include <vector>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 class Route {
 public:
@@ -76,12 +74,13 @@ class XBT_PUBLIC NetZoneImpl : public xbt::PropertyHolder {
   s4u::NetZone piface_;
 
   // our content, as known to our graph routing algorithm (maps vertex_id -> vertex)
-  std::vector<kernel::routing::NetPoint*> vertices_;
+  std::vector<NetPoint*> vertices_;
   std::map<std::string, resource::StandardLinkImpl*, std::less<>> links_;
   /* save split-duplex links separately, keep links_ with only LinkImpl* seen by the user
    * members of a split-duplex are saved in the links_ */
   std::map<std::string, std::unique_ptr<resource::SplitDuplexLinkImpl>, std::less<>> split_duplex_links_;
   std::map<std::string, resource::HostImpl*, std::less<>> hosts_;
+  std::map<std::string, NetPoint*, std::less<>> gateways_;
 
   NetZoneImpl* parent_ = nullptr;
   std::vector<NetZoneImpl*> children_; // sub-netzones
@@ -89,7 +88,7 @@ class XBT_PUBLIC NetZoneImpl : public xbt::PropertyHolder {
   bool sealed_ = false; // We cannot add more content when sealed
 
   std::map<std::pair<const NetPoint*, const NetPoint*>, BypassRoute*> bypass_routes_; // src x dst -> route
-  routing::NetPoint* netpoint_ = nullptr; // Our representative in the parent NetZone
+  NetPoint* netpoint_ = nullptr; // Our representative in the parent NetZone
 
 protected:
   explicit NetZoneImpl(const std::string& name);
@@ -144,7 +143,7 @@ public:
   const s4u::NetZone* get_iface() const { return &piface_; }
   s4u::NetZone* get_iface() { return &piface_; }
   unsigned int get_table_size() const { return vertices_.size(); }
-  std::vector<kernel::routing::NetPoint*> get_vertices() const { return vertices_; }
+  std::vector<NetPoint*> get_vertices() const { return vertices_; }
   NetZoneImpl* get_parent() const { return parent_; }
   /** @brief Returns the list of direct children (no grand-children). This returns the internal data, no copy.
    * Don't mess with it.*/
@@ -158,7 +157,12 @@ public:
   const char* get_cname() const { return name_.c_str(); };
 
   /** @brief Gets the netpoint associated to this netzone */
-  kernel::routing::NetPoint* get_netpoint() const { return netpoint_; }
+  NetPoint* get_netpoint() const { return netpoint_; }
+
+  void set_gateway(const std::string& name, NetPoint* router);
+  /** @brief Gets the gateway associated to this netzone */
+  NetPoint* get_gateway() const;
+  NetPoint* get_gateway(const std::string& name) const { return gateways_.at(name); }
 
   std::vector<s4u::Host*> get_all_hosts() const;
   size_t get_host_count() const;
@@ -287,8 +291,6 @@ private:
   virtual resource::StandardLinkImpl* do_create_link(const std::string& name, const std::vector<double>& bandwidths);
   void add_child(NetZoneImpl* new_zone);
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_NETZONEIMPL_HPP */
index a4e9b67..cf96ee0 100644 (file)
@@ -8,9 +8,7 @@
 
 #include <simgrid/kernel/routing/NetZoneImpl.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief NetZone with an explicit routing (abstract class)
@@ -59,8 +57,6 @@ protected:
   void add_route_check_params(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
                               const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) const;
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_GENERIC_HPP_ */
index dcf740c..dc533e0 100644 (file)
@@ -11,9 +11,7 @@
 #include <unordered_map>
 #include <unordered_set>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief NetZone where components are connected following a star topology
@@ -93,8 +91,6 @@ private:
                              bool symmetrical) const;
   std::unordered_map<unsigned long, StarRoute> routes_;
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_KERNEL_ROUTING_STARZONE_HPP_ */
index af661d3..4eeed3e 100644 (file)
@@ -10,9 +10,7 @@
 
 #include <vector>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  * @brief NetZone using a Torus topology
@@ -32,7 +30,5 @@ public:
   static std::vector<unsigned long> parse_topo_parameters(const std::string& topo_parameters);
 };
 
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 #endif
index 0af8f0e..c64353a 100644 (file)
@@ -9,9 +9,7 @@
 #include <simgrid/kernel/routing/StarZone.hpp>
 #include <xbt/Extendable.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief NetZone modeling peers connected to the cloud through a private link
@@ -60,8 +58,6 @@ public:
   std::vector<double> coords;
 };
 } // namespace vivaldi
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_VIVALDI_HPP_ */
index 2f25143..d2c6108 100644 (file)
@@ -8,9 +8,7 @@
 
 #include <simgrid/kernel/routing/RoutedZone.hpp>
 
-namespace simgrid {
-namespace kernel {
-namespace routing {
+namespace simgrid::kernel::routing {
 
 /** @ingroup ROUTING_API
  *  @brief NetZone modeling a Wifi zone
@@ -33,8 +31,6 @@ public:
   void get_local_route(const NetPoint* src, const NetPoint* dst, Route* into, double* latency) override;
   NetPoint* get_access_point() const { return access_point_; }
 };
-} // namespace routing
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::routing
 
 #endif /* SIMGRID_ROUTING_WIFI_HPP_ */
index e2ca778..09566a3 100644 (file)
@@ -23,12 +23,6 @@ XBT_PUBLIC void MC_assert(int);
  *  It is off in simulation or when replaying MC traces (see MC_record_replay_is_active()) */
 XBT_PUBLIC int MC_is_active();
 
-XBT_PUBLIC void MC_automaton_new_propositional_symbol_pointer(const char* id, int* value);
-
-XBT_PUBLIC void MC_ignore(void* addr, size_t size);
-XBT_PUBLIC void MC_ignore_heap(void* address, size_t size);
-XBT_PUBLIC void MC_unignore_heap(void* address, size_t size);
-
 SG_END_DECL
 
 #endif /* SIMGRID_MODELCHECKER_H */
index b6af5a4..d4438e4 100644 (file)
@@ -22,8 +22,7 @@ XBT_LOG_EXTERNAL_CATEGORY(producer_consumer);
 
 /** Stock implementation of a generic monitored queue to solve the producer-consumer problem */
 
-namespace simgrid {
-namespace plugin {
+namespace simgrid::plugin {
 
 template <typename T> class ProducerConsumer;
 template <typename T> using ProducerConsumerPtr = boost::intrusive_ptr<ProducerConsumer<T>>;
@@ -104,7 +103,7 @@ public:
    */
   ProducerConsumer* set_max_queue_size(unsigned int max_queue_size)
   {
-    const std::lock_guard<s4u::Mutex> lock(*mutex_);
+    const std::scoped_lock lock(*mutex_);
     max_queue_size_ = max_queue_size;
     return this;
   }
@@ -141,7 +140,7 @@ public:
    */
   s4u::CommPtr put_async(T* data, size_t simulated_size_in_bytes)
   {
-    std::unique_lock<s4u::Mutex> lock(*mutex_);
+    std::unique_lock lock(*mutex_);
     s4u::CommPtr comm = nullptr;
     XBT_CVERB(producer_consumer, (size() < max_queue_size_) ? "can put" : "must wait");
 
@@ -178,7 +177,7 @@ public:
    */
   s4u::CommPtr get_async(T** data)
   {
-    std::unique_lock<s4u::Mutex> lock(*mutex_);
+    std::unique_lock lock(*mutex_);
     s4u::CommPtr comm = nullptr;
     XBT_CVERB(producer_consumer, empty() ? "must wait" : "can get");
     while (empty())
@@ -214,7 +213,6 @@ public:
   }
 };
 
-} // namespace plugin
-} // namespace simgrid
+} // namespace simgrid::plugin
 
 #endif // SIMGRID_PLUGIN_PRODUCERCONSUMER_HPP
diff --git a/include/simgrid/plugins/battery.hpp b/include/simgrid/plugins/battery.hpp
new file mode 100644 (file)
index 0000000..fc39505
--- /dev/null
@@ -0,0 +1,149 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_PLUGINS_BATTERY_HPP_
+#define SIMGRID_PLUGINS_BATTERY_HPP_
+
+#include <cmath>
+#include <memory>
+#include <simgrid/kernel/resource/Model.hpp>
+#include <simgrid/s4u/Activity.hpp>
+#include <xbt/Extendable.hpp>
+
+namespace simgrid::plugins {
+
+class Battery;
+using BatteryPtr = boost::intrusive_ptr<Battery>;
+XBT_PUBLIC void intrusive_ptr_release(Battery* o);
+XBT_PUBLIC void intrusive_ptr_add_ref(Battery* o);
+
+class BatteryModel : public kernel::resource::Model {
+  std::vector<BatteryPtr> batteries_;
+
+public:
+  explicit BatteryModel();
+
+  void add_battery(BatteryPtr b);
+  void update_actions_state(double now, double delta) override;
+  double next_occurring_event(double now) override;
+};
+
+class Battery {
+
+  friend BatteryModel;
+
+public:
+  enum Flow { CHARGE, DISCHARGE };
+
+  class Handler {
+    friend Battery;
+
+  public:
+    enum Persistancy { PERSISTANT, ONESHOT };
+
+  private:
+    double state_of_charge_;
+    Flow flow_;
+    double time_delta_ = -1;
+    std::function<void()> callback_;
+    Persistancy persistancy_;
+
+  public:
+    Handler(double state_of_charge, Flow flow, Persistancy p, std::function<void()> callback);
+    static std::shared_ptr<Handler> init(double state_of_charge, Flow flow, Persistancy p,
+                                         std::function<void()> callback);
+
+    /** @ingroup plugin_battery
+     *  @return The state of charge at which the Handler will happen.
+     *  @note For Battery::Handler objects
+     */
+    double get_state_of_charge() { return state_of_charge_; }
+    /** @ingroup plugin_battery
+     *  @return The flow in which the Handler will happen, either when the Battery is charging or discharging.
+     *  @note For Battery::Handler objects
+     */
+    Flow get_flow() { return flow_; }
+    /** @ingroup plugin_battery
+     *  @return The time delta until the Handler happen.
+     -1 means that is will never happen with the current state the Battery,
+     for instance when there is no load connected to the Battery.
+     *  @note For Battery::Handler objects
+    */
+    double get_time_delta() { return time_delta_; }
+    /** @ingroup plugin_battery
+     *  @return The callback to trigger when the Handler happen.
+     *  @note For Battery::Handler objects
+     */
+    std::function<void()> get_callback() { return callback_; }
+    /** @ingroup plugin_battery
+     *  @return true if its a recurrent Handler.
+     *  @note For Battery::Handler objects
+     */
+    Persistancy get_persistancy() { return persistancy_; }
+  };
+
+private:
+  static std::shared_ptr<BatteryModel> battery_model_;
+
+  std::string name_;
+  double nominal_charge_power_w_    = -INFINITY;
+  double nominal_discharge_power_w_ = INFINITY;
+  double charge_efficiency_         = 1;
+  double discharge_efficiency_      = 1;
+  double initial_capacity_wh_       = 0;
+  double energy_budget_j_           = 0;
+
+  std::map<const s4u::Host*, bool> host_loads_                      = {};
+  std::map<const std::string, std::pair<bool, double>> named_loads_ = {};
+  std::vector<std::shared_ptr<Handler>> handlers_;
+
+  double capacity_wh_       = 0;
+  double energy_stored_j_   = 0;
+  double energy_provided_j_ = 0;
+  double energy_consumed_j_ = 0;
+  double last_updated_      = 0;
+
+  explicit Battery() = default;
+  explicit Battery(const std::string& name, double state_of_charge, double nominal_charge_power_w,
+                   double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
+                   double initial_capacity_wh, int cycles);
+  static void init_plugin();
+  void update();
+  double next_occurring_handler();
+
+  std::atomic_int_fast32_t refcount_{0};
+#ifndef DOXYGEN
+  friend void intrusive_ptr_release(Battery* o)
+  {
+    if (o->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
+      std::atomic_thread_fence(std::memory_order_acquire);
+      delete o;
+    }
+  }
+  friend void intrusive_ptr_add_ref(Battery* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); }
+#endif
+
+public:
+  static BatteryPtr init();
+  static BatteryPtr init(const std::string& name, double state_of_charge, double nominal_charge_power_w,
+                         double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
+                         double initial_capacity_wh, int cycles);
+  void set_load(const std::string& name, double power_w);
+  void set_load(const std::string& name, bool active);
+  void connect_host(s4u::Host* host, bool active = true);
+  std::string get_name() const { return name_; }
+  double get_state_of_charge();
+  double get_state_of_health();
+  double get_capacity();
+  double get_energy_provided();
+  double get_energy_consumed();
+  double get_energy_stored(std::string unit = "J");
+  std::shared_ptr<Handler> schedule_handler(double state_of_charge, Flow flow, Handler::Persistancy p,
+                                            std::function<void()> callback);
+  std::vector<std::shared_ptr<Handler>> get_handlers();
+  void delete_handler(std::shared_ptr<Handler> handler);
+};
+} // namespace simgrid::plugins
+#endif
\ No newline at end of file
diff --git a/include/simgrid/plugins/chiller.hpp b/include/simgrid/plugins/chiller.hpp
new file mode 100644 (file)
index 0000000..78d1db0
--- /dev/null
@@ -0,0 +1,107 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+#ifndef SIMGRID_PLUGINS_CHILLER_H_
+#define SIMGRID_PLUGINS_CHILLER_H_
+
+#include <simgrid/kernel/resource/Model.hpp>
+#include <simgrid/s4u/Activity.hpp>
+#include <xbt/Extendable.hpp>
+
+namespace simgrid::plugins {
+
+/** @ingroup plugin_chiller */
+class Chiller;
+/** @ingroup plugin_chiller */
+using ChillerPtr = boost::intrusive_ptr<Chiller>;
+XBT_PUBLIC void intrusive_ptr_release(Chiller* o);
+XBT_PUBLIC void intrusive_ptr_add_ref(Chiller* o);
+
+class ChillerModel : public kernel::resource::Model {
+  std::vector<ChillerPtr> chillers_;
+
+public:
+  explicit ChillerModel();
+
+  void add_chiller(ChillerPtr b);
+  void update_actions_state(double now, double delta) override;
+  double next_occurring_event(double now) override;
+};
+
+class Chiller {
+
+  friend ChillerModel;
+
+private:
+  static std::shared_ptr<ChillerModel> chiller_model_;
+
+  std::string name_;
+  double air_mass_kg_;
+  double specific_heat_j_per_kg_per_c_;
+  double alpha_;
+  double cooling_efficiency_;
+  double temp_in_c_;
+  double temp_out_c_;
+  double goal_temp_c_;
+  double max_power_w_;
+
+  std::set<const s4u::Host*> hosts_ = {};
+  bool active_                      = true;
+  double power_w_                   = 0;
+  double energy_consumed_j_         = 0;
+  double last_updated_              = 0;
+
+  explicit Chiller(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
+                   double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w);
+
+  static void init_plugin();
+  void update();
+
+  std::atomic_int_fast32_t refcount_{0};
+#ifndef DOXYGEN
+  friend void intrusive_ptr_release(Chiller* o)
+  {
+    if (o->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
+      std::atomic_thread_fence(std::memory_order_acquire);
+      delete o;
+    }
+  }
+  friend void intrusive_ptr_add_ref(Chiller* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); }
+#endif
+
+  static xbt::signal<void(Chiller*)> on_power_change;
+  xbt::signal<void(Chiller*)> on_this_power_change;
+
+public:
+  static ChillerPtr init(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
+                         double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w);
+
+  ChillerPtr set_name(std::string name);
+  ChillerPtr set_air_mass(double air_mass_kg);
+  ChillerPtr set_specific_heat(double specific_heat_j_per_kg_per_c);
+  ChillerPtr set_alpha(double alpha);
+  ChillerPtr set_cooling_efficiency(double cooling_efficiency);
+  ChillerPtr set_goal_temp(double goal_temp_c);
+  ChillerPtr set_max_power(double max_power_w);
+  ChillerPtr set_active(bool active);
+  ChillerPtr add_host(simgrid::s4u::Host* host);
+  ChillerPtr remove_host(simgrid::s4u::Host* host);
+
+  std::string get_name() { return name_; }
+  const char* get_cname() { return name_.c_str(); }
+  double get_air_mass() { return air_mass_kg_; }
+  double get_specific_heat() { return specific_heat_j_per_kg_per_c_; }
+  double get_alpha() { return alpha_; }
+  double get_cooling_efficiency() { return cooling_efficiency_; }
+  double get_goal_temp() { return goal_temp_c_; }
+  double get_max_power() { return max_power_w_; }
+  bool is_active() { return active_; }
+  double get_temp_in() { return temp_in_c_; }
+  double get_power() { return power_w_; }
+  double get_energy_consumed() { return energy_consumed_j_; }
+  double get_time_to_goal_temp() const;
+};
+
+} // namespace simgrid::plugins
+#endif
diff --git a/include/simgrid/plugins/jbod.hpp b/include/simgrid/plugins/jbod.hpp
new file mode 100644 (file)
index 0000000..202ec3c
--- /dev/null
@@ -0,0 +1,97 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_PLUGIN_JBOD_HPP
+#define SIMGRID_PLUGIN_JBOD_HPP
+#include <simgrid/s4u/Host.hpp>
+#include <simgrid/s4u/Io.hpp>
+
+namespace simgrid::plugin {
+
+class Jbod;
+using JbodPtr = boost::intrusive_ptr<Jbod>;
+class JbodIo;
+using JbodIoPtr = boost::intrusive_ptr<JbodIo>;
+
+class Jbod {
+public:
+  enum class RAID {RAID0 = 0, RAID1 = 1, RAID4 = 4 , RAID5 = 5, RAID6 = 6};
+  s4u::Host* get_controller() const { return controller_; }
+  int get_parity_disk_idx() { return parity_disk_idx_; }
+  void update_parity_disk_idx() { parity_disk_idx_ = (parity_disk_idx_- 1) % num_disks_; }
+
+  int get_next_read_disk_idx() { return (++read_disk_idx_) % num_disks_; }
+
+  JbodIoPtr read_async(sg_size_t size);
+  sg_size_t read(sg_size_t size);
+
+  JbodIoPtr write_async(sg_size_t size);
+  sg_size_t write(sg_size_t size);
+
+  static JbodPtr create_jbod(s4u::NetZone* zone, const std::string& name, double speed, unsigned int num_disks,
+                             RAID raid_level, double read_bandwidth, double write_bandwidth);
+
+protected:
+  void set_controller(s4u::Host* host) { controller_ = host; }
+  void set_num_disks(unsigned int num_disks) { num_disks_ = num_disks; }
+  void set_parity_disk_idx(unsigned int index) { parity_disk_idx_ = index; }
+  void set_read_disk_idx(int index) { read_disk_idx_ = index; }
+  void set_raid_level(RAID raid_level) { raid_level_ = raid_level; }
+
+private:
+  s4u::Host* controller_;
+  unsigned int num_disks_;
+  RAID raid_level_;
+  unsigned int parity_disk_idx_;
+  int read_disk_idx_;
+  std::atomic_int_fast32_t refcount_{1};
+#ifndef DOXYGEN
+  friend void intrusive_ptr_release(Jbod* jbod)
+  {
+    if (jbod->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
+      std::atomic_thread_fence(std::memory_order_acquire);
+      delete jbod;
+    }
+  }
+  friend void intrusive_ptr_add_ref(Jbod* jbod) { jbod->refcount_.fetch_add(1, std::memory_order_relaxed); }
+#endif
+};
+
+class JbodIo {
+  const Jbod* jbod_;
+  s4u::CommPtr transfer_;
+  s4u::ExecPtr parity_block_comp_;
+  std::vector<s4u::IoPtr> pending_ios_;
+  s4u::Io::OpType type_;
+  std::atomic_int_fast32_t refcount_{0};
+public:
+
+  explicit JbodIo(const Jbod* jbod, const s4u::CommPtr transfer, const s4u::ExecPtr parity_block_comp,
+                  const std::vector<s4u::IoPtr>& pending_ios, s4u::Io::OpType type)
+    : jbod_(jbod), transfer_(transfer), parity_block_comp_(parity_block_comp), pending_ios_(pending_ios), type_(type)
+    {}
+
+  void wait();
+
+#ifndef DOXYGEN
+  friend void intrusive_ptr_release(JbodIo* io)
+  {
+    if (io->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
+      std::atomic_thread_fence(std::memory_order_acquire);
+      delete io;
+    }
+  }
+  friend void intrusive_ptr_add_ref(JbodIo* io) { io->refcount_.fetch_add(1, std::memory_order_relaxed); }
+#endif
+};
+
+/* Refcounting functions */
+XBT_PUBLIC void intrusive_ptr_release(const Jbod* io);
+XBT_PUBLIC void intrusive_ptr_add_ref(const Jbod* io);
+XBT_PUBLIC void intrusive_ptr_release(const JbodIo* io);
+XBT_PUBLIC void intrusive_ptr_add_ref(const JbodIo* io);
+
+} // namespace simgrid::plugin
+#endif
index db406d3..f639047 100644 (file)
@@ -13,7 +13,7 @@
 #include <xbt/base.h>
 
 namespace simgrid {
-/** Returns the ns3 node from a simgrid host */
+/** Returns the ns3 node from a SimGrid host */
 XBT_PUBLIC ns3::Ptr<ns3::Node> get_ns3node_from_sghost(const simgrid::s4u::Host* host);
 }; // namespace simgrid
 
diff --git a/include/simgrid/plugins/solar_panel.hpp b/include/simgrid/plugins/solar_panel.hpp
new file mode 100644 (file)
index 0000000..849c366
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+#ifndef SIMGRID_PLUGINS_SOLAR_PANEL_H_
+#define SIMGRID_PLUGINS_SOLAR_PANEL_H_
+
+#include <simgrid/kernel/resource/Model.hpp>
+#include <simgrid/s4u/Activity.hpp>
+#include <xbt/Extendable.hpp>
+
+namespace simgrid::plugins {
+
+/** @ingroup plugin_solar_panel */
+class SolarPanel;
+/** @ingroup plugin_solar_panel */
+using SolarPanelPtr = boost::intrusive_ptr<SolarPanel>;
+XBT_PUBLIC void intrusive_ptr_release(SolarPanel* o);
+XBT_PUBLIC void intrusive_ptr_add_ref(SolarPanel* o);
+
+class SolarPanel {
+
+  std::string name_;
+  double area_m2_;
+  double conversion_efficiency_;
+  double solar_irradiance_w_per_m2_;
+  double min_power_w_;
+  double max_power_w_;
+  double power_w_ = -1;
+
+  explicit SolarPanel(std::string name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2,
+                      double min_power_w, double max_power_w);
+  void update();
+
+  std::atomic_int_fast32_t refcount_{0};
+#ifndef DOXYGEN
+  friend void intrusive_ptr_release(SolarPanel* o)
+  {
+    if (o->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
+      std::atomic_thread_fence(std::memory_order_acquire);
+      delete o;
+    }
+  }
+  friend void intrusive_ptr_add_ref(SolarPanel* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); }
+#endif
+
+  static xbt::signal<void(SolarPanel*)> on_power_change;
+  xbt::signal<void(SolarPanel*)> on_this_power_change;
+
+public:
+  static SolarPanelPtr init(const std::string& name, double area_m2, double conversion_efficiency,
+                            double solar_irradiance_w_per_m2, double min_power_w, double max_power_w);
+
+  SolarPanelPtr set_name(std::string name);
+  SolarPanelPtr set_area(double area_m2);
+  SolarPanelPtr set_conversion_efficiency(double e);
+  SolarPanelPtr set_solar_irradiance(double solar_irradiance_w_per_m2);
+  SolarPanelPtr set_min_power(double power_w);
+  SolarPanelPtr set_max_power(double power_w);
+
+  std::string get_name() const { return name_; }
+  const char* get_cname() const { return name_.c_str(); }
+  double get_area() const { return area_m2_; }
+  double get_conversion_efficiency() const { return conversion_efficiency_; }
+  double get_solar_irradiance() const { return solar_irradiance_w_per_m2_; }
+  double get_min_power() const { return min_power_w_; }
+  double get_max_power() const { return max_power_w_; }
+  double get_power() const { return power_w_; }
+
+  /** Add a callback fired after this solar panel power changed. */
+  void on_this_power_change_cb(const std::function<void(SolarPanel*)>& func) { on_this_power_change.connect(func); };
+  /** Add a callback fired after a solar panel power changed.
+   * Triggered after the on_this_power_change function.**/
+  static void on_power_change_cb(const std::function<void(SolarPanel*)>& cb) { on_power_change.connect(cb); }
+};
+} // namespace simgrid::plugins
+#endif
index f694696..8ddbf1a 100644 (file)
 #include <simgrid/s4u/Host.hpp>
 #include <simgrid/s4u/Link.hpp>
 #include <simgrid/s4u/Mailbox.hpp>
+#include <simgrid/s4u/Mess.hpp>
+#include <simgrid/s4u/MessageQueue.hpp>
 #include <simgrid/s4u/Mutex.hpp>
 #include <simgrid/s4u/NetZone.hpp>
 #include <simgrid/s4u/Semaphore.hpp>
 #include <simgrid/s4u/VirtualMachine.hpp>
 
+#include <simgrid/s4u/ActivitySet.hpp>
+#include <simgrid/s4u/Task.hpp>
+
 #include <simgrid/Exception.hpp>
 
 #endif /* SIMGRID_S4U_S4U_H */
index bc02713..8b9f485 100644 (file)
@@ -12,6 +12,7 @@
 #include <simgrid/forward.h>
 #include <stdexcept>
 #include <string>
+#include <string_view>
 #include <vector>
 #include <xbt/Extendable.hpp>
 #include <xbt/asserts.h>
@@ -33,9 +34,11 @@ namespace s4u {
  */
 class XBT_PUBLIC Activity : public xbt::Extendable<Activity> {
 #ifndef DOXYGEN
+  friend ActivitySet;
   friend Comm;
   friend Exec;
   friend Io;
+  friend Mess;
   friend kernel::activity::ActivityImpl;
   friend std::vector<ActivityPtr> create_DAG_from_dot(const std::string& filename);
   friend std::vector<ActivityPtr> create_DAG_from_DAX(const std::string& filename);
@@ -74,8 +77,8 @@ protected:
   {
     if(this == a)
       throw std::invalid_argument("Cannot be its own successor");
-    auto p = std::find_if(successors_.begin(), successors_.end(), [a](ActivityPtr const& i){ return i.get() == a.get(); });
-    if (p != successors_.end())
+
+    if (std::any_of(begin(successors_), end(successors_), [a](ActivityPtr const& i) { return i.get() == a.get(); }))
       throw std::invalid_argument("Dependency already exists");
 
     successors_.push_back(a);
@@ -87,12 +90,13 @@ protected:
     if(this == a)
       throw std::invalid_argument("Cannot ask to remove itself from successors list");
 
-    auto p = std::find_if(successors_.begin(), successors_.end(), [a](ActivityPtr const& i){ return i.get() == a.get(); });
-    if (p != successors_.end()){
-      successors_.erase(p);
-      a->dependencies_.erase({this});
-    } else
+    auto p =
+        std::find_if(successors_.begin(), successors_.end(), [a](ActivityPtr const& i) { return i.get() == a.get(); });
+    if (p == successors_.end())
       throw std::invalid_argument("Dependency does not exist. Can not be removed.");
+
+    successors_.erase(p);
+    a->dependencies_.erase({this});
   }
 
   static std::set<Activity*>* vetoed_activities_;
@@ -102,27 +106,18 @@ protected:
    * It is forbidden to change the amount of work once the Activity is started */
   Activity* set_remaining(double remains);
 
-private:
-  static xbt::signal<void(Activity&)> on_veto;
-  static xbt::signal<void(Activity const&)> on_completion;
-  static xbt::signal<void(Activity const&)> on_suspended;
-  static xbt::signal<void(Activity const&)> on_resumed;
+  virtual void fire_on_start() const           = 0;
+  virtual void fire_on_this_start() const      = 0;
+  virtual void fire_on_completion() const      = 0;
+  virtual void fire_on_this_completion() const = 0;
+  virtual void fire_on_suspend() const         = 0;
+  virtual void fire_on_this_suspend() const    = 0;
+  virtual void fire_on_resume() const          = 0;
+  virtual void fire_on_this_resume() const     = 0;
+  virtual void fire_on_veto()                  = 0;
+  virtual void fire_on_this_veto()             = 0;
 
 public:
-  /*! Add a callback fired each time that the activity fails to start because of a veto (e.g., unsolved dependency or no
-   * resource assigned) */
-  static void on_veto_cb(const std::function<void(Activity&)>& cb) { on_veto.connect(cb); }
-  /*! Add a callback fired when the activity completes (either normally, cancelled or failed) */
-  static void on_completion_cb(const std::function<void(Activity const&)>& cb) { on_completion.connect(cb); }
-  /*! Add a callback fired when the activity is suspended */
-  static void on_suspended_cb(const std::function<void(Activity const&)>& cb) { on_suspended.connect(cb); }
-  /*! Add a callback fired when the activity is resumed after being suspended */
-  static void on_resumed_cb(const std::function<void(Activity const&)>& cb) { on_resumed.connect(cb); }
-
-  XBT_ATTRIB_DEPRECATED_v334("All start() are vetoable now. Please use start() ") void vetoable_start()
-  {
-    start();
-  }
   void start()
   {
     state_ = State::STARTING;
@@ -132,14 +127,19 @@ public:
     } else {
       if (vetoed_activities_ != nullptr)
         vetoed_activities_->insert(this);
-      on_veto(*this);
+      fire_on_veto();
+      fire_on_this_veto();
     }
   }
 
   void complete(Activity::State state)
   {
+    // Ensure that the current activity remains alive until the end of the function, even if its last reference is
+    // released by the on_completion() callbacks.
+    ActivityPtr keepalive(this);
     state_ = state;
-    on_completion(*this);
+    fire_on_completion();
+    fire_on_this_completion();
     if (state == State::FINISHED)
       release_dependencies();
   }
@@ -159,8 +159,6 @@ public:
   virtual Activity* do_start() = 0;
   /** Tests whether the given activity is terminated yet. */
   virtual bool test();
-  /*! take a vector s4u::ActivityPtr and return the rank of the first finished one (or -1 if none is done). */
-  static ssize_t test_any(const std::vector<ActivityPtr>& activities);
 
   /** Blocks the current actor until the activity is terminated */
   Activity* wait() { return wait_for(-1.0); }
@@ -170,11 +168,6 @@ public:
   /** Blocks the current actor until the activity is terminated, or until the time limit is reached\n
    * Raises: timeout exception. */
   void wait_until(double time_limit);
-  /*! take a vector of s4u::ActivityPtr and return when one of them is finished.
-   * The return value is the rank of the first finished ActivityPtr. */
-  static ssize_t wait_any(const std::vector<ActivityPtr>& activities) { return wait_any_for(activities, -1); }
-  /*! Same as wait_any, but with a timeout. If the timeout occurs, parameter last is returned.*/
-  static ssize_t wait_any_for(const std::vector<ActivityPtr>& activities, double timeout);
 
   /** Cancel that activity */
   Activity* cancel();
@@ -206,6 +199,9 @@ public:
   kernel::activity::ActivityImpl* get_impl() const { return pimpl_.get(); }
 
 #ifndef DOXYGEN
+  static ssize_t deprecated_wait_any_for(const std::vector<ActivityPtr>& activities, double timeout); // XBT_ATTRIB_DEPRECATED_v339
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static ssize_t test_any(const std::vector<ActivityPtr>& activities);
+
   friend void intrusive_ptr_release(Activity* a)
   {
     if (a->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
@@ -237,7 +233,61 @@ template <class AnyActivity> class Activity_T : public Activity {
   std::string name_             = "unnamed";
   std::string tracing_category_ = "";
 
+  inline static xbt::signal<void(AnyActivity const&)> on_start;
+  xbt::signal<void(AnyActivity const&)> on_this_start;
+  inline static xbt::signal<void(AnyActivity const&)> on_completion;
+  xbt::signal<void(AnyActivity const&)> on_this_completion;
+  inline static xbt::signal<void(AnyActivity const&)> on_suspend;
+  xbt::signal<void(AnyActivity const&)> on_this_suspend;
+  inline static xbt::signal<void(AnyActivity const&)> on_resume;
+  xbt::signal<void(AnyActivity const&)> on_this_resume;
+  inline static xbt::signal<void(AnyActivity&)> on_veto;
+  xbt::signal<void(AnyActivity&)> on_this_veto;
+
+protected:
+  void fire_on_start() const override { on_start(static_cast<const AnyActivity&>(*this)); }
+  void fire_on_this_start() const override { on_this_start(static_cast<const AnyActivity&>(*this)); }
+  void fire_on_completion() const override { on_completion(static_cast<const AnyActivity&>(*this)); }
+  void fire_on_this_completion() const override { on_this_completion(static_cast<const AnyActivity&>(*this)); }
+  void fire_on_suspend() const override { on_suspend(static_cast<const AnyActivity&>(*this)); }
+  void fire_on_this_suspend() const override { on_this_suspend(static_cast<const AnyActivity&>(*this)); }
+  void fire_on_resume() const override { on_resume(static_cast<const AnyActivity&>(*this)); }
+  void fire_on_this_resume() const override { on_this_resume(static_cast<const AnyActivity&>(*this)); }
+  void fire_on_veto() override { on_veto(static_cast<AnyActivity&>(*this)); }
+  void fire_on_this_veto() override { on_this_veto(static_cast<AnyActivity&>(*this)); }
+
 public:
+  /*! \static Add a callback fired when any activity starts (no veto) */
+  static void on_start_cb(const std::function<void(AnyActivity const&)>& cb) { on_start.connect(cb); }
+  /*!  Add a callback fired when this specific activity starts (no veto) */
+  void on_this_start_cb(const std::function<void(AnyActivity const&)>& cb) { on_this_start.connect(cb); }
+  /*! \static Add a callback fired when any activity completes (either normally, cancelled or failed) */
+  static void on_completion_cb(const std::function<void(AnyActivity const&)>& cb) { on_completion.connect(cb); }
+  /*! Add a callback fired when this specific activity completes (either normally, cancelled or failed) */
+  void on_this_completion_cb(const std::function<void(AnyActivity const&)>& cb) { on_this_completion.connect(cb); }
+  /*! \static Add a callback fired when any activity is suspended */
+  static void on_suspend_cb(const std::function<void(AnyActivity const&)>& cb) { on_suspend.connect(cb); }
+  /*! Add a callback fired when this specific activity is suspended */
+  void on_this_suspend_cb(const std::function<void(AnyActivity const&)>& cb) { on_this_suspend.connect(cb); }
+  /*! \static Add a callback fired when any activity is resumed after being suspended */
+  static void on_resume_cb(const std::function<void(AnyActivity const&)>& cb) { on_resume.connect(cb); }
+  /*! Add a callback fired when this specific activity is resumed after being suspended */
+  void on_this_resume_cb(const std::function<void(AnyActivity const&)>& cb) { on_this_resume.connect(cb); }
+  /*! \static Add a callback fired each time that any activity fails to start because of a veto (e.g., unsolved
+   *  dependency or no resource assigned) */
+  static void on_veto_cb(const std::function<void(AnyActivity&)>& cb) { on_veto.connect(cb); }
+  /*! Add a callback fired each time that this specific activity fails to start because of a veto (e.g., unsolved
+   *  dependency or no resource assigned) */
+  void on_this_veto_cb(const std::function<void(AnyActivity&)>& cb) { on_this_veto.connect(cb); }
+
+#ifndef DOXYGEN
+  XBT_ATTRIB_DEPRECATED_v338("Please use on_suspend_cb() instead") static void on_suspended_cb(const std::function<void(Activity const&)>& cb) { on_suspend.connect(cb); }
+  XBT_ATTRIB_DEPRECATED_v338("Please use on_resume_cb() instead") static void on_resumed_cb(const std::function<void(Activity const&)>& cb) { on_resume.connect(cb); }
+
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static ssize_t wait_any(const std::vector<ActivityPtr>& activities) { return deprecated_wait_any_for(activities, -1); }
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static ssize_t wait_any_for(const std::vector<ActivityPtr>& activities, double timeout) { return deprecated_wait_any_for(activities, timeout); }
+#endif
+
   AnyActivity* add_successor(ActivityPtr a)
   {
     Activity::add_successor(a);
@@ -248,7 +298,7 @@ public:
     Activity::remove_successor(a);
     return static_cast<AnyActivity*>(this);
   }
-  AnyActivity* set_name(const std::string& name)
+  AnyActivity* set_name(std::string_view name)
   {
     name_ = name;
     return static_cast<AnyActivity*>(this);
@@ -256,28 +306,15 @@ public:
   const std::string& get_name() const override { return name_; }
   const char* get_cname() const override { return name_.c_str(); }
 
-  AnyActivity* set_tracing_category(const std::string& category)
+  AnyActivity* set_tracing_category(std::string_view category)
   {
-    xbt_assert(get_state() == State::INITED, "Cannot change the tracing category of an activity after its start");
+    xbt_assert(get_state() == State::INITED || get_state() == State::STARTING,
+               "Cannot change the tracing category of an activity after its start");
     tracing_category_ = category;
     return static_cast<AnyActivity*>(this);
   }
   const std::string& get_tracing_category() const { return tracing_category_; }
 
-  XBT_ATTRIB_DEPRECATED_v334("Please use Activity::set_data()") AnyActivity* set_user_data(void* data)
-  {
-    set_data(data);
-    return static_cast<AnyActivity*>(this);
-  }
-
-  XBT_ATTRIB_DEPRECATED_v334("Please use Activity::get_data<>()") void* get_user_data() const
-  {
-    return get_data<void>();
-  }
-  XBT_ATTRIB_DEPRECATED_v334("All start() are vetoable now. Please use start() ") AnyActivity* vetoable_start()
-  {
-    return start();
-  }
   AnyActivity* start()
   {
     Activity::start();
@@ -286,7 +323,9 @@ public:
 
   AnyActivity* cancel() { return static_cast<AnyActivity*>(Activity::cancel()); }
   AnyActivity* wait() { return wait_for(-1.0); }
-  virtual AnyActivity* wait_for(double timeout) { return static_cast<AnyActivity*>(Activity::wait_for(timeout)); }
+  virtual AnyActivity* wait_for(double timeout) {
+    return static_cast<AnyActivity*>(Activity::wait_for(timeout));
+  }
 
 #ifndef DOXYGEN
   /* The refcounting is done in the ancestor class, Activity, but we want each of the classes benefiting of the CRTP
diff --git a/include/simgrid/s4u/ActivitySet.hpp b/include/simgrid/s4u/ActivitySet.hpp
new file mode 100644 (file)
index 0000000..10ec7c8
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright (c) 2006-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_S4U_ACTIVITYSET_HPP
+#define SIMGRID_S4U_ACTIVITYSET_HPP
+
+#include <simgrid/forward.h>
+#include <simgrid/s4u/Activity.hpp>
+
+#include <vector>
+
+namespace simgrid {
+
+extern template class XBT_PUBLIC xbt::Extendable<s4u::ActivitySet>;
+
+namespace s4u {
+/** @brief ActivitiesSet
+ *
+ * This class is a container of activities, allowing to wait for the completion of any or all activities in the set.
+ * This is somehow similar to the select(2) system call under UNIX, allowing you to wait for the next event about these
+ * activities.
+ */
+class XBT_PUBLIC ActivitySet : public xbt::Extendable<ActivitySet> {
+  std::atomic_int_fast32_t refcount_{1};
+  std::vector<ActivityPtr> activities_; // Use vectors, not sets for better reproductibility accross architectures
+  std::vector<ActivityPtr> failed_activities_;
+
+  void handle_failed_activities();
+
+public:
+  ActivitySet()  = default;
+  ActivitySet(const std::vector<ActivityPtr> init) : activities_(init) {}
+  ~ActivitySet() = default;
+
+  /** Add an activity to the set */
+  void push(ActivityPtr a) { activities_.push_back(a); }
+  /** Remove that activity from the set (no-op if the activity is not in the set) */
+  void erase(ActivityPtr a);
+
+  /** Get the amount of activities in the set. Failed activities (if any) are not counted */
+  int size() { return activities_.size(); }
+  /** Return whether the set is empty. Failed activities (if any) are not counted */
+  int empty() { return activities_.empty(); }
+
+  /** Wait for the completion of all activities in the set, but not longer than the provided timeout
+   *
+   * On timeout, an exception is raised.
+   *
+   * In any case, the completed activities remain in the set. Use test_any() to retrieve them.
+   */
+  void wait_all_for(double timeout);
+  /** Wait for the completion of all activities in the set. The set is NOT emptied afterward. */
+  void wait_all() { wait_all_for(-1); }
+  /** Returns the first terminated activity if any, or ActivityPtr(nullptr) if no activity is terminated */
+  ActivityPtr test_any();
+
+  /** Wait for the completion of one activity from the set, but not longer than the provided timeout.
+   *
+   *  See wait_any() for details.
+   *
+   * @return the first terminated activity, which is automatically removed from the set.
+   */
+
+  ActivityPtr wait_any_for(double timeout);
+  /** Wait for the completion of one activity from the set.
+   *
+   * If an activity fails during that time, an exception is raised, and the failed exception is marked as failed in the
+   * set. Use get_failed_activity() to retrieve it.
+   *
+   * If more than one activity failed, the other ones are also removed from the set. Use get_failed_activity() several
+   * time to retrieve them all.
+   *
+   * @return the first terminated activity, which is automatically removed from the set. If more than one activity
+   * terminated at the same timestamp, then the other ones are still in the set. Use either test_any() or wait_any() to
+   * retrieve the other ones.
+   */
+  ActivityPtr wait_any() { return wait_any_for(-1); }
+
+  /** Return one of the failed activity of the set that was revealed during the previous wait operation, or
+   * ActivityPtr() if no failed activity exist in the set. */
+  ActivityPtr get_failed_activity();
+  /** Return whether the set contains any failed activity. */
+  bool has_failed_activities() { return not failed_activities_.empty(); }
+
+  // boost::intrusive_ptr<ActivitySet> support:
+  friend void intrusive_ptr_add_ref(ActivitySet* as)
+  {
+    XBT_ATTRIB_UNUSED auto previous = as->refcount_.fetch_add(1);
+    xbt_assert(previous != 0);
+  }
+
+  friend void intrusive_ptr_release(ActivitySet* as)
+  {
+    if (as->refcount_.fetch_sub(1) == 1)
+      delete as;
+  }
+};
+
+} // namespace s4u
+} // namespace simgrid
+
+#endif
index acdcafe..f3af5b9 100644 (file)
@@ -209,37 +209,60 @@ public:
   int get_refcount() const;
 
   // ***** Actor creation *****
-  /** Retrieve a reference to myself */
+  /** \static
+   * Retrieve a reference to myself
+   */
   static Actor* self();
 
 private:
   static xbt::signal<void(Actor&)> on_creation;
   static xbt::signal<void(Actor const&)> on_suspend;
+  xbt::signal<void(Actor const&)> on_this_suspend;
   static xbt::signal<void(Actor const&)> on_resume;
+  xbt::signal<void(Actor const&)> on_this_resume;
   static xbt::signal<void(Actor const&)> on_sleep;
+  xbt::signal<void(Actor const&)> on_this_sleep;
   static xbt::signal<void(Actor const&)> on_wake_up;
+  xbt::signal<void(Actor const&)> on_this_wake_up;
   static xbt::signal<void(const Actor&, const Host& previous_location)> on_host_change;
+  xbt::signal<void(const Actor&, const Host& previous_location)> on_this_host_change;
   static xbt::signal<void(Actor const&)> on_termination;
+  xbt::signal<void(Actor const&)> on_this_termination;
   static xbt::signal<void(Actor const&)> on_destruction;
+  xbt::signal<void(Actor const&)> on_this_destruction;
 
 public:
-  /** Add a callback fired when a new actor has been created **/
+  /** \static Add a callback fired when a new actor has been created **/
   static void on_creation_cb(const std::function<void(Actor&)>& cb) { on_creation.connect(cb); }
-  /** Add a callback fired when an actor has been suspended**/
+  /** \static Add a callback fired when any actor is suspended (right before the suspend) **/
   static void on_suspend_cb(const std::function<void(Actor const&)>& cb) { on_suspend.connect(cb); }
-  /** Add a callback fired when an actor has been resumed **/
+  /** Add a callback fired when this specific actor is suspended (right before the suspend) **/
+  void on_this_suspend_cb(const std::function<void(Actor const&)>& cb) { on_this_suspend.connect(cb); }
+  /** \static Add a callback fired when any actor is resumed (right before the resume) **/
   static void on_resume_cb(const std::function<void(Actor const&)>& cb) { on_resume.connect(cb); }
-  /** Add a callback fired when an actor starts sleeping **/
+  /** Add a callback fired when this specific actor is resumed (right before the resume) **/
+  void on_this_resume_cb(const std::function<void(Actor const&)>& cb) { on_this_resume.connect(cb); }
+  /** \static Add a callback fired when any actor starts sleeping **/
   static void on_sleep_cb(const std::function<void(Actor const&)>& cb) { on_sleep.connect(cb); }
-  /** Add a callback fired when an actor wakes up from a sleep **/
+  /** Add a callback fired when this specific actor starts sleeping **/
+  void on_this_sleep_cb(const std::function<void(Actor const&)>& cb) { on_this_sleep.connect(cb); }
+  /** \static Add a callback fired when any actor wakes up from a sleep **/
   static void on_wake_up_cb(const std::function<void(Actor const&)>& cb) { on_wake_up.connect(cb); }
-  /** Add a callback fired when an actor is has been migrated to another host **/
+  /** Add a callback fired when this specific actor wakes up from a sleep **/
+  void on_this_wake_up_cb(const std::function<void(Actor const&)>& cb) { on_this_wake_up.connect(cb); }
+  /** \static Add a callback fired when any actor is has been migrated to another host **/
   static void on_host_change_cb(const std::function<void(const Actor&, const Host& previous_location)>& cb)
   {
     on_host_change.connect(cb);
   }
+  /** Add a callback fired when this specific actor is has been migrated to another host **/
+  void on_this_host_change_cb(const std::function<void(const Actor&, const Host& previous_location)>& cb)
+  {
+    on_this_host_change.connect(cb);
+  }
 
-  /** Add a callback fired when an actor terminates its code.
+  /** \static
+   *  Add a callback fired when any actor terminates its code.
    *  @beginrst
    *  The actor may continue to exist if it is still referenced in the simulation, but it's not active anymore.
    *  If you want to free extra data when the actor's destructor is called, use :cpp:func:`Actor::on_destruction_cb`.
@@ -247,19 +270,28 @@ public:
    *  @endrst
    */
   static void on_termination_cb(const std::function<void(Actor const&)>& cb) { on_termination.connect(cb); }
-  /** Add a callback fired when an actor is about to disappear (its destructor was called).
-   *  This signal is fired for any destructed actor, which is mostly useful when designing plugins and extensions.
-   *  If you want to react to the end of the actor's code, use Actor::on_termination instead.
-   *  If you want to register to the termination of a given actor, use this_actor::on_exit() instead.*/
+  /** Add a callback fired when this specific actor terminates its code.
+   *  @beginrst
+   *  The actor may continue to exist if it is still referenced in the simulation, but it's not active anymore.
+   *  If you want to free extra data when the actor's destructor is called, use :cpp:func:`Actor::on_this_destruction_cb`.
+   *  @endrst
+   */
+  void on_this_termination_cb(const std::function<void(Actor const&)>& cb) { on_this_termination.connect(cb); }
+  /** \static  Add a callback fired when an actor is about to disappear (its destructor was called).
+   *  This signal is fired for any destructed actor, which is mostly useful when designing plugins and extensions. */
   static void on_destruction_cb(const std::function<void(Actor const&)>& cb) { on_destruction.connect(cb); }
+  /** Add a callback fired when this specific actor is about to disappear (its destructor was called). */
+  void on_this_destruction_cb(const std::function<void(Actor const&)>& cb) { on_this_destruction.connect(cb); }
 
-  /** Create an actor from a @c std::function<void()>.
+  /** \static
+   *  Create an actor from a @c std::function<void()>.
    *  If the actor is restarted, it gets a fresh copy of the function.
    *  @verbatim embed:rst:inline See the :ref:`example <s4u_ex_actors_create>`. @endverbatim */
   static ActorPtr create(const std::string& name, s4u::Host* host, const std::function<void()>& code);
-  /** Create an actor, but don't start it yet.
+  /** \static
+   *  Create an actor, but don't start it yet.
    *
-   * This is useful to set some properties or extension before actually starting it */
+   *  This is useful to set some properties or extension before actually starting it */
   static ActorPtr init(const std::string& name, s4u::Host* host);
   ActorPtr set_stacksize(unsigned stacksize);
   /** Start a previously initialized actor */
@@ -280,14 +312,16 @@ public:
 
   ActorPtr start(const std::function<void()>& code, std::vector<std::string> args);
 
-  /** Create an actor from a callable thing.
+  /** \static
+   * Create an actor from a callable thing.
    *  @verbatim embed:rst:inline See the :ref:`example <s4u_ex_actors_create>`. @endverbatim */
   template <class F> static ActorPtr create(const std::string& name, s4u::Host* host, F code)
   {
     return create(name, host, std::function<void()>(std::move(code)));
   }
 
-  /** Create an actor using a callable thing and its arguments.
+  /** \static
+   * Create an actor using a callable thing and its arguments.
    *
    * Note that the arguments will be copied, so move-only parameters are forbidden.
    * @verbatim embed:rst:inline See the :ref:`example <s4u_ex_actors_create>`. @endverbatim */
@@ -303,7 +337,8 @@ public:
     return create(name, host, std::bind(std::move(code), std::move(args)...));
   }
 
-  /** Create actor from function name and a vector of strings as arguments.
+  /** \static
+   *  Create actor from function name and a vector of strings as arguments.
    *  @verbatim embed:rst:inline See the :ref:`example <s4u_ex_actors_create>`. @endverbatim */
   static ActorPtr create(const std::string& name, s4u::Host* host, const std::string& function,
                          std::vector<std::string> args);
@@ -318,6 +353,7 @@ public:
 
   /** Returns whether or not this actor has been daemonized or not **/
   bool is_daemon() const;
+
   static bool is_maestro();
 
   /** Retrieves the name of that actor as a C++ string */
@@ -391,7 +427,9 @@ public:
    */
   void kill();
 
-  /** Retrieves the actor that have the given PID (or nullptr if not existing) */
+  /** \static
+    * Retrieves the actor that have the given PID (or nullptr if not existing)
+  */
   static ActorPtr by_pid(aid_t pid);
 
   /** Wait for the actor to finish.
@@ -410,7 +448,9 @@ public:
   /** Kill that actor and restart it from start. */
   Actor* restart();
 
-  /** Kill all actors (but the issuer). Being killed is not something that actors can delay or avoid. */
+  /** \static
+   * Kill all actors (but the issuer). Being killed is not something that actors can delay or avoid.
+  */
   static void kill_all();
 
   /** Returns the internal implementation of this actor */
index c031859..2d6db86 100644 (file)
@@ -15,8 +15,7 @@
 #include <atomic>
 #include <future>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 class XBT_PUBLIC Barrier {
   kernel::activity::BarrierImpl* pimpl_;
@@ -30,7 +29,7 @@ public:
   Barrier& operator=(Barrier const&) = delete;
 #endif
 
-  /** Creates a barrier for the given amount of actors */
+  /** \static Creates a barrier for the given amount of actors */
   static BarrierPtr create(unsigned int expected_actors);
   /** Blocks into the barrier. Every waiting actors will be unlocked once the expected amount of actors reaches the barrier */
   int wait();
@@ -43,7 +42,6 @@ public:
   friend XBT_PUBLIC void intrusive_ptr_release(Barrier* barrier);
 #endif
 };
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif
index 8d1d856..57f6443 100644 (file)
 #include <string>
 #include <vector>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 /** @brief Communication async
  *
  * Represents all asynchronous communications, that you can test or wait onto.
  */
 class XBT_PUBLIC Comm : public Activity_T<Comm> {
   friend Mailbox; // Factory of comms
+  friend kernel::activity::CommImpl;
   /* specified for normal mailbox-based communications*/
   Mailbox* mailbox_                   = nullptr;
   kernel::actor::ActorImpl* sender_   = nullptr;
@@ -39,23 +39,40 @@ class XBT_PUBLIC Comm : public Activity_T<Comm> {
   Comm() = default;
   Comm* do_start() override;
 
-public:
-  /* signals and related callbacks */
-#ifndef DOXYGEN
-  /* FIXME signals should be private */
   static xbt::signal<void(Comm const&)> on_send;
+  xbt::signal<void(Comm const&)> on_this_send;
   static xbt::signal<void(Comm const&)> on_recv;
-  static xbt::signal<void(Comm const&)> on_start;
-#endif
+  xbt::signal<void(Comm const&)> on_this_recv;
+
+protected:
+  void fire_on_completion() const override {
+    /* The completion signal of a Comm has to be thrown only once and not by the sender AND the receiver.
+       then Comm::on_completion is thrown in the kernel in CommImpl::finish.
+     */
+  }
+  void fire_on_this_completion() const override {
+    /* The completion signal of a Comm has to be thrown only once and not by the sender AND the receiver.
+       then Comm::on_this_completion is thrown in the kernel in CommImpl::finish.
+     */
+  }
+  /* These ensure that the on_completion signals are really thrown */
+  void fire_on_completion_for_real() const { Activity_T<Comm>::fire_on_completion(); }
+  void fire_on_this_completion_for_real() const { Activity_T<Comm>::fire_on_this_completion(); }
 
+public:
+  /*! \static Add a callback fired when the send of any Comm is posted  */
   static void on_send_cb(const std::function<void(Comm const&)>& cb) { on_send.connect(cb); }
+  /*! Add a callback fired when the send of this specific Comm is posted  */
+  void on_this_send_cb(const std::function<void(Comm const&)>& cb) { on_this_send.connect(cb); }
+  /*! \static Add a callback fired when the recv of any Comm is posted  */
   static void on_recv_cb(const std::function<void(Comm const&)>& cb) { on_recv.connect(cb); }
-  static void on_start_cb(const std::function<void(Comm const&)>& cb) { on_start.connect(cb); }
-  /* More callbacks */
+  /*! Add a callback fired when the recv of this specific Comm is posted  */
+  void on_this_recv_cb(const std::function<void(Comm const&)>& cb) { on_this_recv.connect(cb); }
+
   CommPtr set_copy_data_callback(const std::function<void(kernel::activity::CommImpl*, void*, size_t)>& callback);
-  XBT_ATTRIB_DEPRECATED_v337("Please manifest if you actually need this function") static void copy_buffer_callback(
+  XBT_ATTRIB_DEPRECATED_v338("Please manifest if you actually need this function") static void copy_buffer_callback(
       kernel::activity::CommImpl*, void*, size_t);
-  XBT_ATTRIB_DEPRECATED_v337("Please manifest if you actually need this function") static void copy_pointer_callback(
+  XBT_ATTRIB_DEPRECATED_v338("Please manifest if you actually need this function") static void copy_pointer_callback(
       kernel::activity::CommImpl*, void*, size_t);
 
   ~Comm() override;
@@ -70,7 +87,8 @@ public:
                    const std::function<void(simgrid::kernel::activity::CommImpl*, void*, size_t)>& copy_data_fun,
                    void* data, double timeout, double rate);
 
-  /* "One-sided" communications. This way of communicating bypasses the mailbox and actors mechanism. It creates a
+  /* \static
+   * "One-sided" communications. This way of communicating bypasses the mailbox and actors mechanism. It creates a
    * communication (vetoabled, asynchronous, or synchronous) directly between two hosts. There is really no limit on
    * the hosts involved. In particular, the actor creating such a communication does not have to be on one of the
    * involved hosts! Enjoy the comfort of the simulator :)
@@ -133,6 +151,9 @@ public:
   void* get_dst_data() const { return dst_buff_; }
   /** Retrieve the size of the received data. Not to be mixed with @ref Activity::get_remaining()  */
   size_t get_dst_data_size() const { return dst_buff_size_; }
+  /** Retrieve the payload associated to the communication. You can only do that once the comm is (gracefully)
+   * terminated, and it is only setup by the default copy_data callback (not the SMPI one) */
+  void* get_payload() const;
 
   /* Common functions */
 
@@ -149,6 +170,7 @@ public:
 
   bool is_assigned() const override;
   Actor* get_sender() const;
+  Actor* get_receiver() const;
 
   /* Comm life cycle */
   /** Start the comm, and ignore its result. It can be completely forgotten after that. */
@@ -162,22 +184,19 @@ public:
 
   Comm* wait_for(double timeout) override;
 
-  /*! take a vector s4u::CommPtr and return the rank of the first finished one (or -1 if none is done). */
-  static ssize_t test_any(const std::vector<CommPtr>& comms);
+#ifndef DOXYGEN
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static ssize_t wait_any(const std::vector<CommPtr>& comms) { return deprecated_wait_any_for(comms, -1); }
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static ssize_t wait_any_for(const std::vector<CommPtr>& comms, double timeout) { return deprecated_wait_any_for(comms, timeout); }
 
-  /*! take a vector s4u::CommPtr and return when one of them is finished.
-   * The return value is the rank of the first finished CommPtr. */
-  static ssize_t wait_any(const std::vector<CommPtr>& comms) { return wait_any_for(comms, -1); }
-  /*! Same as wait_any, but with a timeout. Return -1 if the timeout occurs.*/
-  static ssize_t wait_any_for(const std::vector<CommPtr>& comms, double timeout);
+  static ssize_t deprecated_wait_any_for(const std::vector<CommPtr>& comms,
+                                         double timeout); // XBT_ATTRIB_DEPRECATED_v339
 
-  /*! take a vector s4u::CommPtr and return when all of them is finished. */
-  static void wait_all(const std::vector<CommPtr>& comms);
-  /*! Same as wait_all, but with a timeout. Return the number of terminated comm (less than comms.size() if the timeout
-   * occurs). */
-  static size_t wait_all_for(const std::vector<CommPtr>& comms, double timeout);
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static ssize_t test_any(const std::vector<CommPtr>& comms);
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static void wait_all(const std::vector<CommPtr>& comms);
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static size_t
+      wait_all_for(const std::vector<CommPtr>& comms, double timeout);
+#endif
 };
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif /* SIMGRID_S4U_COMM_HPP */
index 56c74c3..448b4a8 100644 (file)
@@ -14,8 +14,7 @@
 
 #include <future>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 /**
  * @beginrst
@@ -44,7 +43,7 @@ private:
 #endif
 
 public:
-  /** Create a new condition variable and return a smart pointer
+  /** \static Create a new condition variable and return a smart pointer
    *
    * @beginrst
    * You should only manipulate :cpp:type:`simgrid::s4u::ConditionVariablePtr`, as created by this function (see also :ref:`s4u_raii`).
@@ -66,29 +65,9 @@ public:
   std::cv_status wait_until(const std::unique_lock<s4u::Mutex>& lock, double timeout_time);
   /// Wait for the given amount of seconds (specified as a plain double)
   std::cv_status wait_for(const std::unique_lock<s4u::Mutex>& lock, double duration);
-  /// Wait until predicate is true, or the given instant (specified as a plain double)
-  template <class P> bool wait_until(const std::unique_lock<s4u::Mutex>& lock, double timeout_time, P pred)
-  {
-    while (not pred())
-      if (this->wait_until(lock, timeout_time) == std::cv_status::timeout)
-        return pred();
-    return true;
-  }
-  /// As long as the predicate is false, wait for the given amount of seconds (specified as a plain double)
-  template <class P> bool wait_for(const std::unique_lock<s4u::Mutex>& lock, double duration, P pred)
-  {
-    return this->wait_until(lock, Engine::get_clock() + duration, std::move(pred));
-  }
 
   // Wait function taking a C++ style time:
 
-  /// As long as the predicate is false, wait for the given amount of seconds (specified in C++ style)
-  template <class Rep, class Period, class P>
-  bool wait_for(const std::unique_lock<s4u::Mutex>& lock, std::chrono::duration<Rep, Period> duration, P pred)
-  {
-    auto seconds = std::chrono::duration_cast<SimulationClockDuration>(duration);
-    return this->wait_for(lock, seconds.count(), pred);
-  }
   /// Wait for the given amount of seconds (specified in C++ style)
   template <class Rep, class Period>
   std::cv_status wait_for(const std::unique_lock<s4u::Mutex>& lock, std::chrono::duration<Rep, Period> duration)
@@ -103,13 +82,6 @@ public:
     auto timeout_native = std::chrono::time_point_cast<SimulationClockDuration>(timeout_time);
     return this->wait_until(lock, timeout_native.time_since_epoch().count());
   }
-  /** Wait until predicate is true, or the given instant (specified in C++ style) */
-  template <class Duration, class P>
-  bool wait_until(const std::unique_lock<s4u::Mutex>& lock, const SimulationTimePoint<Duration>& timeout_time, P pred)
-  {
-    auto timeout_native = std::chrono::time_point_cast<SimulationClockDuration>(timeout_time);
-    return this->wait_until(lock, timeout_native.time_since_epoch().count(), std::move(pred));
-  }
 
   /** Unblock one actor blocked on that condition variable. If none was blocked, nothing happens. */
   void notify_one();
@@ -117,7 +89,6 @@ public:
   void notify_all();
 };
 
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif
index 1f8c31d..eec006c 100644 (file)
@@ -79,6 +79,13 @@ public:
   Disk* set_state_profile(kernel::profile::Profile* profile);
   Disk* set_read_bandwidth_profile(kernel::profile::Profile* profile);
   Disk* set_write_bandwidth_profile(kernel::profile::Profile* profile);
+  /**
+   * @brief Set the max amount of operations (either read or write) that can take place on this disk at the same time
+   *
+   * Use -1 to set no limit.
+   */
+  Disk* set_concurrency_limit(int limit);
+  int get_concurrency_limit() const;
 
   IoPtr io_init(sg_size_t size, s4u::Io::OpType type) const;
 
@@ -126,17 +133,35 @@ public:
   Disk* seal();
 
   /* The signals */
-  /** @brief Add a callback fired when a new Disk is created */
+  /** @brief \static Add a callback fired when a new Disk is created */
   static void on_creation_cb(const std::function<void(Disk&)>& cb) { on_creation.connect(cb); }
-  /** @brief Add a callback fired when a Disk is destroyed */
+  /** @brief \static Add a callback fired when any Disk is destroyed */
   static void on_destruction_cb(const std::function<void(Disk const&)>& cb) { on_destruction.connect(cb); }
-  /** @brief Add a callback fired when a Disk's state changes */
-  static void on_state_change_cb(const std::function<void(Disk const&)>& cb) { on_state_change.connect(cb); }
+  /** @brief Add a callback fired when this specific Disk is destroyed */
+  void on_this_destruction_cb(const std::function<void(Disk const&)>& cb) { on_this_destruction.connect(cb); }
+  /** @brief \static Add a callback fired when any Disk is turned on or off */
+  static void on_onoff_cb(const std::function<void(Disk const&)>& cb)
+  {
+    on_onoff.connect(cb);
+  }
+  /** @brief Add a callback fired when this specific Disk is turned on or off */
+  void on_this_onoff_cb(const std::function<void(Disk const&)>& cb)
+  {
+    on_this_onoff.connect(cb);
+  }
+
+  XBT_ATTRIB_DEPRECATED_v338("Please use on_onoff_cb() instead") static void on_state_change_cb(
+      const std::function<void(Disk const&)>& cb)
+  {
+    on_onoff.connect(cb);
+  }
 
 private:
   static xbt::signal<void(Disk&)> on_creation;
   static xbt::signal<void(Disk const&)> on_destruction;
-  static xbt::signal<void(Disk const&)> on_state_change;
+  xbt::signal<void(Disk const&)> on_this_destruction;
+  static xbt::signal<void(Disk const&)> on_onoff;
+  xbt::signal<void(Disk const&)> on_this_onoff;
 };
 
 } // namespace s4u
index 742bb36..2bdb4a9 100644 (file)
@@ -18,8 +18,7 @@
 #include <utility>
 #include <vector>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 /** @brief Simulation engine
  *
  * This is a singleton containing all the main functions of the simulation.
@@ -41,9 +40,6 @@ public:
   ~Engine();
 #endif
 
-  /** Finalize the default engine and all its dependencies */
-  XBT_ATTRIB_DEPRECATED_v335("Users are not supposed to shutdown the Engine") void shutdown();
-
   /** Run the simulation until its end */
   void run() const;
 
@@ -97,8 +93,8 @@ public:
   /** @verbatim embed:rst:inline Bind an actor name that could be found in :ref:`pf_tag_actor` tag to a class name passed as a template parameter. See the :ref:`example <s4u_ex_actors_create>`. @endverbatim */
   template <class F> void register_actor(const std::string& name)
   {
-    kernel::actor::ActorCodeFactory code_factory = [](std::vector<std::string> args) {
-      return kernel::actor::ActorCode([args = std::move(args)]() mutable {
+    kernel::actor::ActorCodeFactory code_factory = [](std::vector<std::string> args_factory) {
+      return kernel::actor::ActorCode([args = std::move(args_factory)]() mutable {
         F code(std::move(args));
         code();
       });
@@ -108,8 +104,8 @@ public:
   /** @verbatim embed:rst:inline Bind an actor name that could be found in :ref:`pf_tag_actor` tag to a function name passed as a parameter. See the :ref:`example <s4u_ex_actors_create>`. @endverbatim */
   template <class F> void register_actor(const std::string& name, F code)
   {
-    kernel::actor::ActorCodeFactory code_factory = [code](std::vector<std::string> args) {
-      return kernel::actor::ActorCode([code, args = std::move(args)]() mutable { code(std::move(args)); });
+    kernel::actor::ActorCodeFactory code_factory = [code](std::vector<std::string> args_factory) {
+      return kernel::actor::ActorCode([code, args = std::move(args_factory)]() mutable { code(std::move(args)); });
     };
     register_function(name, code_factory);
   }
@@ -159,6 +155,7 @@ public:
   Link* link_by_name_or_null(const std::string& name) const;
 
   Mailbox* mailbox_by_name_or_create(const std::string& name) const;
+  MessageQueue* message_queue_by_name_or_create(const std::string& name) const;
 
   size_t get_actor_count() const;
   std::vector<ActorPtr> get_all_actors() const;
@@ -193,7 +190,7 @@ public:
   /** @brief Retrieves all netzones of the type indicated by the template argument */
   template <class T> std::vector<T*> get_filtered_netzones() const
   {
-    static_assert(std::is_base_of<kernel::routing::NetZoneImpl, T>::value,
+    static_assert(std::is_base_of_v<kernel::routing::NetZoneImpl, T>,
                   "Filtering netzones is only possible for subclasses of kernel::routing::NetZoneImpl");
     std::vector<T*> res;
     get_filtered_netzones_recursive(get_netzone_root(), &res);
@@ -210,7 +207,7 @@ public:
   /** @brief set a configuration variable
    *
    * @beginrst
-   * Do --help on any simgrid binary to see the list of currently existing configuration variables
+   * Do --help on any SimGrid binary to see the list of currently existing configuration variables
    * (see also :ref:`options`).
    * @endrst
    *
@@ -272,7 +269,7 @@ std::vector<ActivityPtr> create_DAG_from_json(const std::string& filename);
 template <class T>
 XBT_PRIVATE void get_filtered_netzones_recursive(const s4u::NetZone* current, std::vector<T*>* whereto)
 {
-  static_assert(std::is_base_of<kernel::routing::NetZoneImpl, T>::value,
+  static_assert(std::is_base_of_v<kernel::routing::NetZoneImpl, T>,
                 "Filtering netzones is only possible for subclasses of kernel::routing::NetZoneImpl");
   for (auto const& elem : current->get_children()) {
     get_filtered_netzones_recursive(elem, whereto);
@@ -282,7 +279,6 @@ XBT_PRIVATE void get_filtered_netzones_recursive(const s4u::NetZone* current, st
   }
 }
 #endif
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif /* SIMGRID_S4U_ENGINE_HPP */
index cd514ea..8167b87 100644 (file)
@@ -11,8 +11,7 @@
 #include <simgrid/s4u/Actor.hpp>
 #include <xbt/ex.h>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 /** Computation Activity, representing the asynchronous executions.
  *
@@ -43,24 +42,14 @@ protected:
 
   void reset() const;
 
-  static xbt::signal<void(Exec const&)> on_start;
-
 public:
 #ifndef DOXYGEN
   Exec(Exec const&) = delete;
   Exec& operator=(Exec const&) = delete;
 #endif
-  /*! Signal fired each time that an execution actually starts (no veto) */
-  static void on_start_cb(const std::function<void(Exec const&)>& cb) { on_start.connect(cb); }
-
+  /*! \static Initiate the creation of an Exec. Setters have to be called afterwards */
   static ExecPtr init();
 
-  /*! take a vector of s4u::ExecPtr and return when one of them is finished.
-   * The return value is the rank of the first finished ExecPtr. */
-  static ssize_t wait_any(const std::vector<ExecPtr>& execs) { return wait_any_for(execs, -1); }
-  /*! Same as wait_any, but with a timeout. If the timeout occurs, parameter last is returned.*/
-  static ssize_t wait_any_for(const std::vector<ExecPtr>& execs, double timeout);
-
   /** @brief On sequential executions, returns the amount of flops that remain to be done; This cannot be used on
    * parallel executions. */
   double get_remaining() const override;
@@ -86,9 +75,17 @@ public:
   double get_cost() const;
   bool is_parallel() const { return parallel_; }
   bool is_assigned() const override;
+
+#ifndef DOXYGEN
+  static ssize_t deprecated_wait_any_for(const std::vector<ExecPtr>& execs, double timeout); // XBT_ATTRIB_DEPRECATED_v339
+
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static ssize_t
+      wait_any(const std::vector<ExecPtr>& execs) { return deprecated_wait_any_for(execs, -1); }
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") static ssize_t
+      wait_any_for(const std::vector<ExecPtr>& execs, double timeout) { return deprecated_wait_any_for(execs, timeout); }
+#endif
 };
 
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif /* SIMGRID_S4U_EXEC_HPP */
index b13b561..28ce469 100644 (file)
@@ -7,6 +7,7 @@
 #define SIMGRID_S4U_HOST_HPP
 
 #include <simgrid/forward.h>
+#include <simgrid/kernel/resource/Action.hpp>
 #include <xbt/Extendable.hpp>
 #include <xbt/signal.hpp>
 
@@ -46,6 +47,14 @@ class XBT_PUBLIC Host : public xbt::Extendable<Host> {
 
   kernel::resource::CpuImpl* pimpl_cpu_      = nullptr;
   kernel::routing::NetPoint* pimpl_netpoint_ = nullptr;
+#ifndef DOXYGEN
+  friend kernel::resource::CpuAction; // signal exec_state_changed
+#endif
+
+  static xbt::signal<void(Host&)> on_creation;
+  static xbt::signal<void(Host const&)> on_destruction;
+  xbt::signal<void(Host const&)> on_this_destruction;
+  static xbt::signal<void(kernel::resource::CpuAction&, kernel::resource::Action::State)> on_exec_state_change;
 
 public:
   explicit Host(kernel::resource::HostImpl* pimpl) : pimpl_(pimpl) {}
@@ -54,22 +63,52 @@ protected:
   virtual ~Host(); // Call destroy() instead of manually deleting it.
   Host* set_netpoint(kernel::routing::NetPoint* netpoint);
 
-  static xbt::signal<void(Host&)> on_creation;
-  static xbt::signal<void(Host const&)> on_destruction;
-
 public:
   static xbt::signal<void(Host const&)> on_speed_change;
-  static xbt::signal<void(Host const&)> on_state_change;
+  xbt::signal<void(Host const&)> on_this_speed_change;
+  static xbt::signal<void(Host const&)> on_onoff;
+  xbt::signal<void(Host const&)> on_this_onoff;
+
 #endif
-  /** Add a callback fired on each newly created host */
+  /** \static Add a callback fired on each newly created host */
   static void on_creation_cb(const std::function<void(Host&)>& cb) { on_creation.connect(cb); }
-  /** Add a callback fired when the machine is turned on or off (called AFTER the change) */
-  static void on_state_change_cb(const std::function<void(Host const&)>& cb) { on_state_change.connect(cb); }
-  /** Add a callback fired when the speed of the machine is changed (called AFTER the change)
+  /** \static Add a callback fired when any machine is turned on or off (called AFTER the change) */
+  static void on_onoff_cb(const std::function<void(Host const&)>& cb)
+  {
+    on_onoff.connect(cb);
+  }
+  XBT_ATTRIB_DEPRECATED_v338("Please use on_onoff_cb() instead") static void on_state_change_cb(
+      const std::function<void(Host const&)>& cb)
+  {
+    on_onoff.connect(cb);
+  }
+  /** Add a callback fired when this specific machine is turned on or off (called AFTER the change) */
+  void on_this_onoff_cb(const std::function<void(Host const&)>& cb)
+  {
+    on_this_onoff.connect(cb);
+  }
+  /** \static Add a callback fired when the speed of any machine is changed (called AFTER the change)
    * (either because of a pstate switch or because of an external load event coming from the profile) */
   static void on_speed_change_cb(const std::function<void(Host const&)>& cb) { on_speed_change.connect(cb); }
-  /** Add a callback fired just before destructing a host */
+  /** Add a callback fired when the speed of this specific machine is changed (called AFTER the change)
+   * (either because of a pstate switch or because of an external load event coming from the profile) */
+  void on_this_speed_change_cb(const std::function<void(Host const&)>& cb)
+  {
+    on_this_speed_change.connect(cb);
+  }
+  /** \static Add a callback fired just before destructing any host */
   static void on_destruction_cb(const std::function<void(Host const&)>& cb) { on_destruction.connect(cb); }
+  /** Add a callback fired just before destructing this specific host */
+  void on_this_destruction_cb(const std::function<void(Host const&)>& cb)
+  {
+    on_this_destruction.connect(cb);
+  }
+  /** \static Add a callback fired when the state of any exec activity changes */
+  static void on_exec_state_change_cb(
+      const std::function<void(kernel::resource::CpuAction&, kernel::resource::Action::State previous)>& cb)
+  {
+    on_exec_state_change.connect(cb);
+  }
 
   virtual void destroy();
 #ifndef DOXYGEN
@@ -78,11 +117,11 @@ public:
   Host& operator=(Host const&) = delete;
 #endif
 
-  /** Retrieve a host from its name, or return nullptr */
+  /** \static Retrieve a host from its name, or return nullptr */
   static Host* by_name_or_null(const std::string& name);
-  /** Retrieve a host from its name, or die */
+  /** \static Retrieve a host from its name, or die */
   static Host* by_name(const std::string& name);
-  /** Retrieves the host on which the running actor is located */
+  /** \static Retrieves the host on which the running actor is located */
   static Host* current();
 
   /** Retrieves the name of that host as a C++ string */
@@ -133,7 +172,15 @@ public:
   Host* set_state_profile(kernel::profile::Profile* p);
   Host* set_speed_profile(kernel::profile::Profile* p);
 
-  /** @brief Convert the CPU's speed from string to double */
+  /**
+   * @brief Set the max amount of executions that can take place on this host at the same time
+   *
+   * Use -1 to set no limit.
+   */
+  Host* set_concurrency_limit(int limit);
+  int get_concurrency_limit() const;
+
+  /** \static @brief Convert the CPU's speed from string to double */
   static std::vector<double> convert_pstate_speed_vector(const std::vector<std::string>& speed_per_state);
   /**
    * @brief Set the CPU's speed
@@ -231,6 +278,7 @@ public:
 
   void route_to(const Host* dest, std::vector<Link*>& links, double* latency) const;
   void route_to(const Host* dest, std::vector<kernel::resource::StandardLinkImpl*>& links, double* latency) const;
+  std::pair<std::vector<Link*>, double> route_to(const Host* dest) const;
 
   /**
    * @brief Seal this host
index 8c626f7..0709a3b 100644 (file)
@@ -11,8 +11,7 @@
 
 #include <string>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 /** I/O Activity, representing the asynchronous disk access.
  *
@@ -25,23 +24,23 @@ class XBT_PUBLIC Io : public Activity_T<Io> {
   friend kernel::EngineImpl;
 #endif
 
-  static xbt::signal<void(Io const&)> on_start;
-
 protected:
   explicit Io(kernel::activity::IoImplPtr pimpl);
   Io* do_start() override;
 
+  static ssize_t deprecated_wait_any_for(const std::vector<IoPtr>& ios, double timeout); // XBT_ATTRIB_DEPRECATED_v339
+
 public:
   enum class OpType { READ, WRITE };
 
-  static void on_start_cb(const std::function<void(Io const&)>& cb) { on_start.connect(cb); }
-
+   /*! \static Initiate the creation of an I/O. Setters have to be called afterwards */
   static IoPtr init();
-  /*! take a vector of s4u::IoPtr and return when one of them is finished.
-   * The return value is the rank of the first finished IoPtr. */
-  static ssize_t wait_any(const std::vector<IoPtr>& ios) { return wait_any_for(ios, -1); }
-  /*! Same as wait_any, but with a timeout. If the timeout occurs, parameter last is returned.*/
-  static ssize_t wait_any_for(const std::vector<IoPtr>& ios, double timeout);
+#ifndef DOXYGEN
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") 
+  static ssize_t wait_any(const std::vector<IoPtr>& ios) { return deprecated_wait_any_for(ios, -1); }
+  XBT_ATTRIB_DEPRECATED_v339("Please use ActivitySet instead") 
+  static ssize_t wait_any_for(const std::vector<IoPtr>& ios, double timeout) { return deprecated_wait_any_for(ios, timeout); }
+#endif
 
   double get_remaining() const override;
   sg_size_t get_performed_ioops() const;
@@ -64,7 +63,6 @@ public:
   bool is_assigned() const override;
 };
 
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif /* SIMGRID_S4U_IO_HPP */
index 2195c69..c2ac18e 100644 (file)
@@ -45,11 +45,25 @@ protected:
 #endif
 
 public:
-  enum class SharingPolicy { NONLINEAR = 4, WIFI = 3, SPLITDUPLEX = 2, SHARED = 1, FATPIPE = 0 };
+  /** Specifies how a given link is shared between concurrent communications */
+  enum class SharingPolicy {
+    /// This policy takes a callback that specifies the maximal capacity as a function of the number of usage. See the
+    /// examples with 'degradation' in their name.
+    NONLINEAR = 4,
+    /// Pseudo-sharing policy requesting wifi-specific sharing.
+    WIFI = 3,
+    /// Each link is split in 2, UP and DOWN, one per direction. These links are SHARED.
+    SPLITDUPLEX = 2,
+    /// The bandwidth is shared between all comms using that link, regardless of their direction.
+    SHARED = 1,
+    /// Each comm can use the link fully, with no sharing (only a maximum). This is intended to represent the backbone
+    /// links that cannot be saturated by concurrent links, but have a maximal bandwidth.
+    FATPIPE = 0
+  };
 
   kernel::resource::StandardLinkImpl* get_impl() const;
 
-  /** @brief Retrieve a link from its name */
+  /** \static @brief Retrieve a link from its name */
   static Link* by_name(const std::string& name);
   static Link* by_name_or_null(const std::string& name);
 
@@ -130,7 +144,11 @@ public:
   void set_host_wifi_rate(const s4u::Host* host, int level) const;
 
   /** @brief Returns the current load (in bytes per second) */
-  double get_usage() const;
+  double get_load() const;
+
+#ifndef DOXYGEN
+  XBT_ATTRIB_DEPRECATED_v338("Please use get_load() instead") double get_usage() const { return get_load(); }
+#endif
 
   /** @brief Check if the Link is used (at least one flow uses the link) */
   bool is_used() const;
@@ -150,29 +168,56 @@ public:
 private:
 #ifndef DOXYGEN
   static xbt::signal<void(Link&)> on_creation;
-  static xbt::signal<void(Link const&)> on_state_change;
+  static xbt::signal<void(Link const&)> on_onoff;
+  xbt::signal<void(Link const&)> on_this_onoff;
   static xbt::signal<void(Link const&)> on_bandwidth_change;
+  xbt::signal<void(Link const&)> on_this_bandwidth_change;
   static xbt::signal<void(kernel::resource::NetworkAction&, kernel::resource::Action::State)>
       on_communication_state_change;
   static xbt::signal<void(Link const&)> on_destruction;
+  xbt::signal<void(Link const&)> on_this_destruction;
 #endif
 
 public:
   /* The signals */
-  /** @brief Add a callback fired when a new Link is created */
+  /** \static @brief Add a callback fired when a new Link is created */
   static void on_creation_cb(const std::function<void(Link&)>& cb) { on_creation.connect(cb); }
-  /** @brief Add a callback fired when the state of a Link changes (when it is turned on or off) */
-  static void on_state_change_cb(const std::function<void(Link const&)>& cb) { on_state_change.connect(cb); }
-  /** @brief Add a callback fired when the bandwidth of a Link changes */
+  /** \static @brief Add a callback fired when any Link is turned on or off */
+  static void on_onoff_cb(const std::function<void(Link const&)>& cb)
+  {
+    on_onoff.connect(cb);
+  }
+  /** @brief Add a callback fired when this specific Link is turned on or off */
+  void on_this_onoff_cb(const std::function<void(Link const&)>& cb)
+  {
+    on_this_onoff.connect(cb);
+  }
+  /** \static @brief Add a callback fired when the bandwidth of any Link changes */
   static void on_bandwidth_change_cb(const std::function<void(Link const&)>& cb) { on_bandwidth_change.connect(cb); }
-  /** @brief Add a callback fired when a communication changes it state (ready/done/cancel) */
+  /** @brief Add a callback fired when the bandwidth of this specific Link changes */
+  void on_this_bandwidth_change_cb(const std::function<void(Link const&)>& cb)
+  {
+    on_this_bandwidth_change.connect(cb);
+  }
+  /** \static @brief Add a callback fired when a communication changes it state (ready/done/cancel) */
   static void on_communication_state_change_cb(
       const std::function<void(kernel::resource::NetworkAction&, kernel::resource::Action::State)>& cb)
   {
     on_communication_state_change.connect(cb);
   }
-  /** @brief Add a callback fired when a Link is destroyed */
+  /** \static @brief Add a callback fired when any Link is destroyed */
   static void on_destruction_cb(const std::function<void(Link const&)>& cb) { on_destruction.connect(cb); }
+  /** @brief Add a callback fired when this specific Link is destroyed */
+  void on_this_destruction_cb(const std::function<void(Link const&)>& cb)
+  {
+    on_this_destruction.connect(cb);
+  }
+
+  XBT_ATTRIB_DEPRECATED_v338("Please use on_onoff_cb() instead") static void on_state_change_cb(
+      const std::function<void(Link const&)>& cb)
+  {
+    on_onoff.connect(cb);
+  }
 };
 
 /**
@@ -190,7 +235,7 @@ public:
   /** @brief Get the link direction down */
   Link* get_link_down() const;
 
-  /** @brief Retrieve a link from its name */
+  /** \static @brief Retrieve a link from its name */
   static SplitDuplexLink* by_name(const std::string& name);
 };
 
index 75201ec..b8eddff 100644 (file)
@@ -14,8 +14,7 @@
 #include <memory>
 #include <string>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 /** @brief Mailboxes: Network rendez-vous points. */
 class XBT_PUBLIC Mailbox {
@@ -39,7 +38,7 @@ public:
   /** @brief Retrieves the name of that mailbox as a C string */
   const char* get_cname() const;
 
-  /** Retrieve the mailbox associated to the given name. Mailboxes are created on demand. */
+  /** \static Retrieve the mailbox associated to the given name. Mailboxes are created on demand. */
   static Mailbox* by_name(const std::string& name);
 
   /** Returns whether the mailbox contains queued communications */
@@ -119,6 +118,9 @@ public:
   CommPtr get_init();
   /** Creates and start an async data reception to that mailbox */
   template <typename T> CommPtr get_async(T** data);
+  /** Creates and start an async data reception to that mailbox. Since the data location is not provided, you'll have to
+   * use Comm::get_payload once the comm terminates */
+  CommPtr get_async();
 
   /** Blocking data reception */
   template <typename T> T* get();
@@ -151,7 +153,6 @@ template <typename T> T* Mailbox::get(double timeout)
   get_async<T>(&res)->wait_for(timeout);
   return res;
 }
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif /* SIMGRID_S4U_MAILBOX_HPP */
diff --git a/include/simgrid/s4u/Mess.hpp b/include/simgrid/s4u/Mess.hpp
new file mode 100644 (file)
index 0000000..81dcee9
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_S4U_MESS_HPP
+#define SIMGRID_S4U_MESS_HPP
+
+#include <simgrid/forward.h>
+#include <simgrid/s4u/Activity.hpp>
+
+#include <string>
+#include <vector>
+
+namespace simgrid::s4u {
+
+class XBT_PUBLIC Mess : public Activity_T<Mess> {
+#ifndef DOXYGEN
+  friend MessageQueue; // Factory of messages
+  friend kernel::activity::MessImpl;
+#endif
+  MessageQueue* queue_  = nullptr;
+  void* payload_        = nullptr;
+  size_t dst_buff_size_ = 0;
+  void* dst_buff_       = nullptr;
+
+  Mess() = default;
+  Mess* do_start() override;
+
+  static xbt::signal<void(Mess const&)> on_send;
+  xbt::signal<void(Mess const&)> on_this_send;
+  static xbt::signal<void(Mess const&)> on_recv;
+  xbt::signal<void(Mess const&)> on_this_recv;
+
+  /* These ensure that the on_completion signals are really thrown */
+  void fire_on_completion_for_real() const { Activity_T<Mess>::fire_on_completion(); }
+  void fire_on_this_completion_for_real() const { Activity_T<Mess>::fire_on_this_completion(); }
+
+public:
+#ifndef DOXYGEN
+  Mess(Mess const&) = delete;
+  Mess& operator=(Mess const&) = delete;
+#endif
+
+  MessPtr set_queue(MessageQueue* queue);
+  MessageQueue* get_queue() const { return queue_; }
+
+  /** Retrieve the payload associated to the communication. You can only do that once the comm is (gracefully)
+   * terminated */
+  void* get_payload() const { return payload_; }
+  MessPtr set_payload(void* data);
+  MessPtr set_dst_data(void** buff, size_t size);
+  Actor* get_sender() const;
+  Actor* get_receiver() const;
+
+  bool is_assigned() const override { return true; };
+
+  Mess* wait_for(double timeout) override;
+
+  kernel::actor::ActorImpl* sender_   = nullptr;
+  kernel::actor::ActorImpl* receiver_ = nullptr;
+};
+} // namespace simgrid::s4u
+
+#endif /* SIMGRID_S4U_MESS_HPP */
diff --git a/include/simgrid/s4u/MessageQueue.hpp b/include/simgrid/s4u/MessageQueue.hpp
new file mode 100644 (file)
index 0000000..dc00941
--- /dev/null
@@ -0,0 +1,112 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_S4U_MESSAGEQUEUE_HPP
+#define SIMGRID_S4U_MESSAGEQUEUE_HPP
+
+#include <simgrid/forward.h>
+#include <simgrid/s4u/Mess.hpp>
+#include <smpi/forward.hpp>
+
+#include <string>
+
+namespace simgrid::s4u {
+
+class XBT_PUBLIC MessageQueue {
+#ifndef DOXYGEN
+  friend Mess;
+  friend kernel::activity::MessageQueueImpl;
+#endif
+
+  kernel::activity::MessageQueueImpl* const pimpl_;
+
+  explicit MessageQueue(kernel::activity::MessageQueueImpl * mqueue) : pimpl_(mqueue) {}
+  ~MessageQueue() = default;
+
+protected:
+  kernel::activity::MessageQueueImpl* get_impl() const { return pimpl_; }
+
+public:
+  /** @brief Retrieves the name of that message queue as a C++ string */
+  const std::string& get_name() const;
+  /** @brief Retrieves the name of that message queue as a C string */
+  const char* get_cname() const;
+
+  /** \static Retrieve the message queye associated to the given name. Message queues are created on demand. */
+  static MessageQueue* by_name(const std::string& name);
+
+  /** Returns whether the message queue contains queued messages */
+  bool empty() const;
+
+  /* Returns the number of queued messages */
+  size_t size() const;
+
+  /** Gets the first element in the queue (without dequeuing it), or nullptr if none is there */
+  kernel::activity::MessImplPtr front() const;
+
+  /** Creates (but don't start) a data transmission to that message queue */
+  MessPtr put_init();
+  /** Creates (but don't start) a data transmission to that message queue.
+   *
+   * Please note that if you send a pointer to some data, you must ensure that your data remains live until
+   * consumption, or the receiver will get a pointer to a garbled memory area.
+   */
+  MessPtr put_init(void* payload);
+  /** Creates and start a data transmission to that mailbox.
+   *
+   * Please note that if you send a pointer to some data, you must ensure that your data remains live until
+   * consumption, or the receiver will get a pointer to a garbled memory area.
+   */
+  MessPtr put_async(void* payload);
+
+  /** Blocking data transmission.
+   *
+   * Please note that if you send a pointer to some data, you must ensure that your data remains live until
+   * consumption, or the receiver will get a pointer to a garbled memory area.
+   */
+  void put(void* payload);
+  /** Blocking data transmission with timeout */
+  void put(void* payload, double timeout);
+
+  /** Creates (but don't start) a data reception onto that message queue. */
+  MessPtr get_init();
+  /** Creates and start an async data reception to that message queue */
+  template <typename T> MessPtr get_async(T** data);
+  /** Creates and start an async data reception to that mailbox. Since the data location is not provided, you'll have to
+   * use Mess::get_payload once the messaging operation terminates */
+  MessPtr get_async();
+
+  /** Blocking data reception */
+  template <typename T> T* get();
+  template <typename T> std::unique_ptr<T> get_unique() { return std::unique_ptr<T>(get<T>()); }
+
+  /** Blocking data reception with timeout */
+  template <typename T> T* get(double timeout);
+  template <typename T> std::unique_ptr<T> get_unique(double timeout) { return std::unique_ptr<T>(get<T>(timeout)); }
+};
+
+template <typename T> MessPtr MessageQueue::get_async(T** data)
+{
+  MessPtr res = get_init()->set_dst_data(reinterpret_cast<void**>(data), sizeof(void*));
+  res->start();
+  return res;
+}
+
+template <typename T> T* MessageQueue::get()
+{
+  T* res = nullptr;
+  get_async<T>(&res)->wait();
+  return res;
+}
+
+template <typename T> T* MessageQueue::get(double timeout)
+{
+  T* res = nullptr;
+  get_async<T>(&res)->wait_for(timeout);
+  return res;
+}
+} // namespace simgrid::s4u
+
+#endif /* SIMGRID_S4U_MESSAGEQUEUE_HPP */
index 60eb8d0..29d9ed1 100644 (file)
@@ -6,13 +6,15 @@
 #ifndef SIMGRID_S4U_MUTEX_HPP
 #define SIMGRID_S4U_MUTEX_HPP
 
+#include "simgrid/s4u/Actor.hpp"
 #include <simgrid/forward.h>
 #include <xbt/asserts.h>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 /** @brief A classical mutex, but blocking in the simulation world.
+ *
+ * S4U mutexes are not recursive. If an actor tries to lock the same object twice, it deadlocks with itself.
  *
  * @beginrst
  * It is strictly impossible to use a real mutex, such as
@@ -48,14 +50,16 @@ class XBT_PUBLIC Mutex {
 #endif
 
 public:
-  /** Constructs a new mutex */
-  static MutexPtr create();
+  /** \static Constructs a new mutex */
+  static MutexPtr create(bool recursive = false);
+
   void lock();
   void unlock();
   bool try_lock();
+
+  Actor* get_owner();
 };
 
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif /* SIMGRID_S4U_MUTEX_HPP */
index 63a1c23..6805270 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef SIMGRID_S4U_NETZONE_HPP
 #define SIMGRID_S4U_NETZONE_HPP
 
+#include "simgrid/s4u/Host.hpp"
 #include <simgrid/forward.h>
 #include <simgrid/s4u/Link.hpp>
 #include <xbt/graph.h>
@@ -18,8 +19,7 @@
 #include <utility>
 #include <vector>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 /** @brief Networking Zones
  *
@@ -58,7 +58,13 @@ public:
   const char* get_property(const std::string& key) const;
   void set_property(const std::string& key, const std::string& value);
   /** @brief Get the netpoint associated to this netzone */
-  kernel::routing::NetPoint* get_netpoint();
+  kernel::routing::NetPoint* get_netpoint() const;
+  /** @brief Get the gateway associated to this netzone */
+  kernel::routing::NetPoint* get_gateway() const;
+  kernel::routing::NetPoint* get_gateway(const std::string& name) const;
+  void set_gateway(const s4u::Host* router) { set_gateway(router->get_netpoint()); }
+  void set_gateway(kernel::routing::NetPoint* router);
+  void set_gateway(const std::string& name, kernel::routing::NetPoint* router);
 
   void extract_xbt_graph(const s_xbt_graph_t* graph, std::map<std::string, xbt_node_t, std::less<>>* nodes,
                          std::map<std::string, xbt_edge_t, std::less<>>* edges);
@@ -66,6 +72,24 @@ public:
   /* Add content to the netzone, at parsing time. It should be sealed afterward. */
   unsigned long add_component(kernel::routing::NetPoint* elm); /* A host, a router or a netzone, whatever */
 
+  /**
+   * @brief Add a route between 2 netzones, and same in other direction
+   * @param src Source netzone
+   * @param dst Destination netzone
+   * @param links List of links
+   */
+  void add_route(const NetZone* src, const NetZone* dst, const std::vector<const Link*>& links);
+
+/**
+   * @brief Add a route between 2 netzones, and same in other direction
+   * @param src Source netzone
+   * @param dst Destination netzone
+   * @param link_list List of links and their direction used in this communication
+   * @param symmetrical Bi-directional communication
+   */
+  void add_route(const NetZone* src, const NetZone* dst, const std::vector<LinkInRoute>& link_list, bool symmetrical = true);
+
+#ifndef DOXYGEN
   /**
    * @brief Add a route between 2 netpoints
    *
@@ -80,8 +104,44 @@ public:
    * @param link_list List of links and their direction used in this communication
    * @param symmetrical Bi-directional communication
    */
-  void add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst, kernel::routing::NetPoint* gw_src,
-                 kernel::routing::NetPoint* gw_dst, const std::vector<LinkInRoute>& link_list, bool symmetrical = true);
+  XBT_ATTRIB_DEPRECATED_v339("Please call add_route either from Host to Host or NetZone to NetZone") void add_route(
+      kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst, kernel::routing::NetPoint* gw_src,
+      kernel::routing::NetPoint* gw_dst, const std::vector<LinkInRoute>& link_list, bool symmetrical = true);
+  /**
+   * @brief Add a route between 2 netpoints, and same in other direction
+   *
+   * Create a route:
+   * - route between 2 hosts/routers in same netzone, no gateway is needed
+   * - route between 2 netzones, connecting 2 gateways.
+   *
+   * @param src Source netzone's netpoint
+   * @param dst Destination netzone' netpoint
+   * @param gw_src Netpoint of the gateway in the source netzone
+   * @param gw_dst Netpoint of the gateway in the destination netzone
+   * @param link_list List of links
+   */
+  XBT_ATTRIB_DEPRECATED_v339("Please call add_route either from Host to Host or NetZone to NetZone") void add_route(
+      kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst, kernel::routing::NetPoint* gw_src,
+      kernel::routing::NetPoint* gw_dst, const std::vector<const Link*>& links);
+#endif
+
+  /**
+   * @brief Add a route between 2 hosts
+   *
+   * @param src Source host
+   * @param dst Destination host
+   * @param link_list List of links and their direction used in this communication
+   * @param symmetrical Bi-directional communication
+   */
+  void add_route(const Host* src, const Host* dst, const std::vector<LinkInRoute>& link_list, bool symmetrical = true);
+  /**
+   * @brief Add a route between 2 hosts
+   *
+   * @param src Source host
+   * @param dst Destination host
+   * @param links List of links. The UP direction will be used on src->dst and DOWN direction on dst->src
+   */
+  void add_route(const Host* src, const Host* dst, const std::vector<const Link*>& links);
 
   void add_bypass_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                         kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
@@ -94,7 +154,9 @@ private:
 #endif
 
 public:
+  /** \static Add a callback fired on each newly created NetZone */
   static void on_creation_cb(const std::function<void(NetZone const&)>& cb) { on_creation.connect(cb); }
+  /** \static Add a callback fired on each newly sealed NetZone */
   static void on_seal_cb(const std::function<void(NetZone const&)>& cb) { on_seal.connect(cb); }
 
   /**
@@ -189,8 +251,29 @@ struct ClusterCallbacks {
    * @param id: Internal identifier of the element
    * @return pair<NetPoint*, NetPoint*>: returns a pair of netpoint and gateway.
    */
+  // XBT_ATTRIB_DEPRECATED_v339
   using ClusterNetPointCb = std::pair<kernel::routing::NetPoint*, kernel::routing::NetPoint*>(
       NetZone* zone, const std::vector<unsigned long>& coord, unsigned long id);
+
+   /**
+   * @brief Callback used to set the NetZone located at some leaf of clusters (Torus, FatTree, etc)
+   *
+   * @param zone: The parent zone, needed for creating new resources (hosts, links)
+   * @param coord: the coordinates of the element
+   * @param id: Internal identifier of the element
+   * @return NetZone*: returns newly created netzone
+   */
+  using ClusterNetZoneCb = NetZone*(NetZone* zone, const std::vector<unsigned long>& coord, unsigned long id);
+  /**
+   * @brief Callback used to set the Host located at some leaf of clusters (Torus, FatTree, etc)
+   *
+   * @param zone: The parent zone, needed for creating new resources (hosts, links)
+   * @param coord: the coordinates of the element
+   * @param id: Internal identifier of the element
+   * @return Host*: returns newly created host
+   */
+  using ClusterHostCb = Host*(NetZone* zone, const std::vector<unsigned long>& coord, unsigned long id);
+
   /**
    * @brief Callback used to set the links for some leaf of the cluster (Torus, FatTree, etc)
    *
@@ -208,14 +291,36 @@ struct ClusterCallbacks {
    */
   using ClusterLinkCb = Link*(NetZone* zone, const std::vector<unsigned long>& coord, unsigned long id);
 
-  std::function<ClusterNetPointCb> netpoint;
+  bool by_netzone_ = false;
+  bool is_by_netzone() const { return by_netzone_; }
+  bool by_netpoint_ = false; // XBT_ATTRIB_DEPRECATED_v339
+  bool is_by_netpoint() const { return by_netpoint_; } // XBT_ATTRIB_DEPRECATED_v339
+  std::function<ClusterNetPointCb> netpoint; // XBT_ATTRIB_DEPRECATED_v339
+  std::function<ClusterHostCb> host;
+  std::function<ClusterNetZoneCb> netzone;
   std::function<ClusterLinkCb> loopback = {};
   std::function<ClusterLinkCb> limiter  = {};
+  explicit ClusterCallbacks(const std::function<ClusterNetZoneCb>& set_netzone)
+      : by_netzone_(true), netzone(set_netzone){/* nothing to do */};
+
+  ClusterCallbacks(const std::function<ClusterNetZoneCb>& set_netzone,
+                   const std::function<ClusterLinkCb>& set_loopback, const std::function<ClusterLinkCb>& set_limiter)
+      :  by_netzone_(true), netzone(set_netzone), loopback(set_loopback), limiter(set_limiter){/* nothing to do */};
+
+  explicit ClusterCallbacks(const std::function<ClusterHostCb>& set_host)
+      : host(set_host) {/* nothing to do */};
+
+  ClusterCallbacks(const std::function<ClusterHostCb>& set_host,
+                   const std::function<ClusterLinkCb>& set_loopback, const std::function<ClusterLinkCb>& set_limiter)
+      :  host(set_host), loopback(set_loopback), limiter(set_limiter){/* nothing to do */};
+
+  XBT_ATTRIB_DEPRECATED_v339("Please use callback with either a Host/NetZone creation function as first parameter")
   explicit ClusterCallbacks(const std::function<ClusterNetPointCb>& set_netpoint)
-      : netpoint(set_netpoint){/*nothing to do */};
+      : by_netpoint_(true), netpoint(set_netpoint){/* nothing to do */};
+  XBT_ATTRIB_DEPRECATED_v339("Please use callback with either a Host/NetZone creation function as first parameter")
   ClusterCallbacks(const std::function<ClusterNetPointCb>& set_netpoint,
                    const std::function<ClusterLinkCb>& set_loopback, const std::function<ClusterLinkCb>& set_limiter)
-      : netpoint(set_netpoint), loopback(set_loopback), limiter(set_limiter){/*nothing to do */};
+      : by_netpoint_(true), netpoint(set_netpoint), loopback(set_loopback), limiter(set_limiter){/* nothing to do */};
 };
 /**
  * @brief Create a torus zone
@@ -329,7 +434,6 @@ XBT_PUBLIC NetZone* create_dragonfly_zone(const std::string& name, const NetZone
                                           const DragonflyParams& parameters, const ClusterCallbacks& set_callbacks,
                                           double bandwidth, double latency, Link::SharingPolicy sharing_policy);
 
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif /* SIMGRID_S4U_NETZONE_HPP */
index 6dcb9a4..4c16f7a 100644 (file)
@@ -8,8 +8,7 @@
 
 #include <simgrid/forward.h>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 /** @brief A classical semaphore, but blocking in the simulation world
  *
@@ -46,7 +45,7 @@ class XBT_PUBLIC Semaphore {
 #endif
 
 public:
-  /** Constructs a new semaphore */
+  /** \static Constructs a new semaphore */
   static SemaphorePtr create(unsigned int initial_capacity);
 
   void acquire();
@@ -57,7 +56,6 @@ public:
   bool would_block() const;
 };
 
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif /* SIMGRID_S4U_SEMAPHORE_HPP */
diff --git a/include/simgrid/s4u/Task.hpp b/include/simgrid/s4u/Task.hpp
new file mode 100644 (file)
index 0000000..4c44875
--- /dev/null
@@ -0,0 +1,227 @@
+#ifndef SIMGRID_S4U_TASK_H_
+#define SIMGRID_S4U_TASK_H_
+
+#include <simgrid/forward.h>
+#include <simgrid/s4u/Activity.hpp>
+#include <simgrid/s4u/Io.hpp>
+#include <xbt/Extendable.hpp>
+
+#include <atomic>
+#include <deque>
+#include <map>
+#include <memory>
+#include <set>
+#include <xbt/asserts.h>
+
+namespace simgrid::s4u {
+
+class XBT_PUBLIC Token : public xbt::Extendable<Token> {};
+
+/** Task class */
+class XBT_PUBLIC Task {
+
+  std::string name_;
+
+  std::map<std::string, double> amount_              = {{"instance_0", 0}, {"dispatcher", 0}, {"collector", 0}};
+  std::map<std::string, int> queued_firings_         = {{"instance_0", 0}, {"dispatcher", 0}, {"collector", 0}};
+  std::map<std::string, int> running_instances_      = {{"instance_0", 0}, {"dispatcher", 0}, {"collector", 0}};
+  std::map<std::string, int> count_                  = {{"instance_0", 0}, {"dispatcher", 0}, {"collector", 0}};
+  std::map<std::string, int> parallelism_degree_     = {{"instance_0", 1}, {"dispatcher", 1}, {"collector", 1}};
+  std::map<std::string, int> internal_bytes_to_send_ = {{"instance_0", 0}, {"dispatcher", 0}};
+
+  std::function<std::string()> load_balancing_function_;
+
+  std::set<Task*> successors_                 = {};
+  std::map<Task*, unsigned int> predecessors_ = {};
+  std::atomic_int_fast32_t refcount_{0};
+
+  bool ready_to_run(std::string instance);
+  void receive(Task* source);
+
+  std::shared_ptr<Token> token_ = nullptr;
+  std::map<TaskPtr, std::deque<std::shared_ptr<Token>>> tokens_received_;
+  std::map<std::string, std::deque<ActivityPtr>> current_activities_ = {
+      {"instance_0", {}}, {"dispatcher", {}}, {"collector", {}}};
+
+  inline static xbt::signal<void(Task*)> on_start;
+  xbt::signal<void(Task*)> on_this_start;
+  inline static xbt::signal<void(Task*)> on_completion;
+  xbt::signal<void(Task*)> on_this_completion;
+
+protected:
+  explicit Task(const std::string& name);
+  virtual ~Task() = default;
+
+  virtual void fire(std::string instance);
+  void complete(std::string instance);
+
+  void store_activity(ActivityPtr a, const std::string& instance) { current_activities_[instance].push_back(a); }
+
+  virtual void add_instances(int n);
+  virtual void remove_instances(int n);
+
+public:
+  /** @param name The new name of this Task */
+  void set_name(std::string name);
+  /** Retrieves the name of that Task as a C++ string */
+  const std::string& get_name() const { return name_; }
+  /** Retrieves the name of that Task as a C string */
+  const char* get_cname() const { return name_.c_str(); }
+  /** @param amount The new amount of work this instance of this Task has to do
+   *  @note In flops for ExecTasks instances and in bytes for CommTasks instances. In flops for dispatcher and collector
+   * instances */
+  void set_amount(double amount, std::string instance = "instance_0");
+  /** @return Amout of work this instance of this Task has to process */
+  double get_amount(std::string instance = "instance_0") const { return amount_.at(instance); }
+  /** @return Amount of queued firings for this instance of this Task */
+  int get_queued_firings(std::string instance = "instance_0") const { return queued_firings_.at(instance); }
+  /** @return Amount currently running of this instance of this Task */
+  int get_running_count(std::string instance = "instance_0") const { return running_instances_.at(instance); }
+  /** @return Number of times this instance of this Task has been completed */
+  int get_count(std::string instance = "collector") const { return count_.at(instance); }
+  /** @param n The parallelism degree to set
+   *  @brief The parallelism degree defines how many of this instance can run in parallel. */
+  void set_parallelism_degree(int n, std::string instance = "all");
+  /** @return Parallelism degree of this instance of this Task */
+  int get_parallelism_degree(std::string instance = "instance_0") const { return parallelism_degree_.at(instance); }
+  /** @param bytes The amount of bytes this instance has to send to the next instance of this Task
+   *  @note This amount is used when the host is different between the dispatcher and the instance doing the work of the
+   * Task, or between the instance and the collector. */
+  void set_internal_bytes(int bytes, std::string instance = "instance_0");
+  /** @return Amount of bytes this instance of the Task has to send to the next instance */
+  double get_internal_bytes(std::string instance = "instance_0") const { return internal_bytes_to_send_.at(instance); }
+  /** @param func The new balancing function
+   *  @note This function is used by the dispatcher to determine which instance will effectively do the work. This
+   * function must return the name of the instance as a string. The default balancing function always returns
+   * "instance_0" */
+  void set_load_balancing_function(std::function<std::string()> func);
+  /** @param token The new token */
+  void set_token(std::shared_ptr<Token> token);
+  /** @param t A Smart pointer to a Task
+   *  @return Oldest token received by this Task that was sent by Task t */
+  std::shared_ptr<Token> get_token_from(TaskPtr t) const { return tokens_received_.at(t).front(); }
+  /** @param t A Smart pointer to a Task
+   *  @return All tokens received by this Task that were sent by Task t */
+  std::deque<std::shared_ptr<Token>> get_tokens_from(TaskPtr t) const { return tokens_received_.at(t); }
+  /** @param t A Smart pointer to a Task
+   *   @brief Pop the oldest token received by this Task that was sent by Task t */
+  void deque_token_from(TaskPtr t);
+  /** @param t A Smart pointer to a Task
+   *  @brief Add t as a successor of this Task */
+  void add_successor(TaskPtr t);
+  /** @param t A Smart pointer to a Task
+   *  @brief Remove t from the successors of this Task */
+  void remove_successor(TaskPtr t);
+  /** @brief Remove all successors from this Task */
+  void remove_all_successors();
+  /** @return All successors of this Task */
+  const std::set<Task*>& get_successors() const { return successors_; }
+  /** @param n The number of firings to enqueue */
+  void enqueue_firings(int n);
+  /** Add a callback fired before this task activity starts */
+  void on_this_start_cb(const std::function<void(Task*)>& func) { on_this_start.connect(func); }
+  /** Add a callback fired before a task activity starts.
+   * Triggered after the on_this_start function**/
+  static void on_start_cb(const std::function<void(Task*)>& cb) { on_start.connect(cb); }
+  /** Add a callback fired before this task activity ends */
+  void on_this_completion_cb(const std::function<void(Task*)>& func) { on_this_completion.connect(func); };
+  /** Add a callback fired after a task activity ends.
+   * Triggered after the on_this_end function, but before sending tokens to successors.**/
+  static void on_completion_cb(const std::function<void(Task*)>& cb) { on_completion.connect(cb); }
+
+#ifndef DOXYGEN
+  friend void intrusive_ptr_release(Task* o)
+  {
+    if (o->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
+      std::atomic_thread_fence(std::memory_order_acquire);
+      delete o;
+    }
+  }
+  friend void intrusive_ptr_add_ref(Task* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); }
+#endif
+};
+
+/** CommTask class */
+class CommTask : public Task {
+  Host* source_;
+  Host* destination_;
+
+  explicit CommTask(const std::string& name);
+  void fire(std::string instance) override;
+
+public:
+  static CommTaskPtr init(const std::string& name);
+  static CommTaskPtr init(const std::string& name, double bytes, Host* source, Host* destination);
+
+  /** @param source The new source Host of this CommTask
+   *  @return A Smart pointer to this CommTask */
+  CommTaskPtr set_source(Host* source);
+  /** @return A pointer to the source Host of this CommTask */
+  Host* get_source() const { return source_; }
+  /** @param destination The new destination of this CommTask
+   *  @return A Smart pointer to the destination Host of this CommTask */
+  CommTaskPtr set_destination(Host* destination);
+  /** @return A pointer to the destination Host of this CommTask */
+  Host* get_destination() const { return destination_; }
+  /** @param bytes The amount of bytes this CommTask has to send */
+  CommTaskPtr set_bytes(double bytes);
+  /** @return The amout of bytes this CommTask has to send */
+  double get_bytes() const { return get_amount("instance_0"); }
+};
+
+/** ExecTask class */
+class ExecTask : public Task {
+  std::map<std::string, Host*> host_ = {{"instance_0", nullptr}, {"dispatcher", nullptr}, {"collector", nullptr}};
+
+  explicit ExecTask(const std::string& name);
+  void fire(std::string instance) override;
+
+public:
+  static ExecTaskPtr init(const std::string& name);
+  static ExecTaskPtr init(const std::string& name, double flops, Host* host);
+
+  /** @param host The new host of this instance of this ExecTask
+   *  @return a Smart pointer to this ExecTask */
+  ExecTaskPtr set_host(Host* host, std::string instance = "all");
+  /** @return A pointer to the host of this instance of this ExecTask */
+  Host* get_host(std::string instance = "instance_0") const { return host_.at(instance); }
+  /** @param flops The new amount of flops this instance of this Task has to execute
+   *  @return A Smart pointer to this ExecTask */
+  ExecTaskPtr set_flops(double flops, std::string instance = "instance_0");
+  /** @return The amount of flops this instance of this ExecTask has to execute */
+  double get_flops(std::string instance = "instance_0") const { return get_amount(instance); }
+  /** @param n The number of instances to add to this ExecTask */
+  void add_instances(int n) override;
+  /** @param n The number of isntances to remove from this ExecTask */
+  void remove_instances(int n) override;
+};
+
+/** IoTask class */
+class IoTask : public Task {
+  Disk* disk_;
+  Io::OpType type_;
+  explicit IoTask(const std::string& name);
+  void fire(std::string instance) override;
+
+public:
+  static IoTaskPtr init(const std::string& name);
+  static IoTaskPtr init(const std::string& name, double bytes, Disk* disk, Io::OpType type);
+
+  /** @param disk The new disk of this IoTask
+   * @return A Smart pointer to this IoTask */
+  IoTaskPtr set_disk(Disk* disk);
+  /** @return A pointer to the disk of this IoTask */
+  Disk* get_disk() const { return disk_; }
+  /** @param bytes The new amount of bytes this IoTask has to write or read
+   *  @return A Smart pointer to this IoTask */
+  IoTaskPtr set_bytes(double bytes);
+  /** @return The amount of bytes this IoTask has to write or read */
+  double get_bytes() const { return get_amount("instance_0"); }
+  /** @param type The type of operation this IoTask has to do
+   *  @return A Smart pointer to this IoTask */
+  IoTaskPtr set_op_type(Io::OpType type);
+  /** @return The type of operation this IoTask has to to */
+  Io::OpType get_op_type() const { return type_; }
+};
+} // namespace simgrid::s4u
+#endif
index 748f264..b269022 100644 (file)
@@ -10,8 +10,7 @@
 #include <simgrid/s4u/Host.hpp>
 #include <xbt/utility.hpp>
 
-namespace simgrid {
-namespace s4u {
+namespace simgrid::s4u {
 
 /** @brief Host extension for the VMs */
 class VmHostExt {
@@ -37,13 +36,21 @@ class XBT_PUBLIC VirtualMachine : public s4u::Host {
   /* Signals about the life cycle of the VM */
   static xbt::signal<void(VirtualMachine&)> on_vm_creation;
   static xbt::signal<void(VirtualMachine const&)> on_start;
+  xbt::signal<void(VirtualMachine const&)> on_this_start;
   static xbt::signal<void(VirtualMachine const&)> on_started;
+  xbt::signal<void(VirtualMachine const&)> on_this_started;
   static xbt::signal<void(VirtualMachine const&)> on_shutdown;
+  xbt::signal<void(VirtualMachine const&)> on_this_shutdown;
   static xbt::signal<void(VirtualMachine const&)> on_suspend;
+  xbt::signal<void(VirtualMachine const&)> on_this_suspend;
   static xbt::signal<void(VirtualMachine const&)> on_resume;
+  xbt::signal<void(VirtualMachine const&)> on_this_resume;
   static xbt::signal<void(VirtualMachine const&)> on_migration_start;
+  xbt::signal<void(VirtualMachine const&)> on_this_migration_start;
   static xbt::signal<void(VirtualMachine const&)> on_migration_end;
+  xbt::signal<void(VirtualMachine const&)> on_this_migration_end;
   static xbt::signal<void(VirtualMachine const&)> on_vm_destruction;
+  xbt::signal<void(VirtualMachine const&)> on_this_vm_destruction;
 
 #ifndef DOXYGEN
   friend kernel::resource::VirtualMachineImpl; // calls signals from Impl
@@ -52,11 +59,6 @@ class XBT_PUBLIC VirtualMachine : public s4u::Host {
 #endif
 
 public:
-  XBT_ATTRIB_DEPRECATED_v336("Please use s4u::Host::create_vm") explicit VirtualMachine(const std::string& name,
-                                                                                        Host* physical_host,
-                                                                                        int core_amount,
-                                                                                        size_t ramsize = 1024);
-
 #ifndef DOXYGEN
   // No copy/move
   VirtualMachine(VirtualMachine const&) = delete;
@@ -89,23 +91,71 @@ public:
   State get_state() const;
 
   /* Callbacks on signals */
+  /*! \static Add a callback fired when any VM is created */
   static void on_creation_cb(const std::function<void(VirtualMachine&)>& cb) { on_vm_creation.connect(cb); }
+  /*! \static Add a callback fired when any VM starts */
   static void on_start_cb(const std::function<void(VirtualMachine const&)>& cb) { on_start.connect(cb); }
+  /*! Add a callback fired when this specific VM starts */
+  void on_this_start_cb(const std::function<void(VirtualMachine const&)>& cb)
+  {
+    on_this_start.connect(cb);
+  }
+  /*! \static Add a callback fired when any VM is actually started */
   static void on_started_cb(const std::function<void(VirtualMachine const&)>& cb) { on_started.connect(cb); }
+  /*! Add a callback fired when this specific VM is actually started */
+  void on_this_started_cb(const std::function<void(VirtualMachine const&)>& cb)
+  {
+    on_this_started.connect(cb);
+  }
+  /*! \static Add a callback fired when any VM is shut down */
   static void on_shutdown_cb(const std::function<void(VirtualMachine const&)>& cb) { on_shutdown.connect(cb); }
+  /*! Add a callback fired when this specific VM is shut down */
+  void on_this_shutdown_cb(const std::function<void(VirtualMachine const&)>& cb)
+  {
+    on_this_shutdown.connect(cb);
+  }
+  /*! \static Add a callback fired when any VM is suspended*/
   static void on_suspend_cb(const std::function<void(VirtualMachine const&)>& cb) { on_suspend.connect(cb); }
+  /*! Add a callback fired when this specific VM is suspended*/
+  void on_this_suspend_cb(const std::function<void(VirtualMachine const&)>& cb)
+  {
+    on_this_suspend.connect(cb);
+  }
+  /*! \static Add a callback fired when any VM is resumed*/
   static void on_resume_cb(const std::function<void(VirtualMachine const&)>& cb) { on_resume.connect(cb); }
+  /*! Add a callback fired when this specific VM is resumed*/
+  void on_this_resume_cb(const std::function<void(VirtualMachine const&)>& cb)
+  {
+    on_this_resume.connect(cb);
+  }
+  /*! \static Add a callback fired when any VM is destroyed*/
   static void on_destruction_cb(const std::function<void(VirtualMachine const&)>& cb) { on_vm_destruction.connect(cb); }
+  /*! Add a callback fired when this specific VM is destroyed*/
+  void on_this_destruction_cb(const std::function<void(VirtualMachine const&)>& cb)
+  {
+    on_this_vm_destruction.connect(cb);
+  }
+  /*! \static Add a callback fired when any VM starts a migration*/
   static void on_migration_start_cb(const std::function<void(VirtualMachine const&)>& cb)
   {
     on_migration_start.connect(cb);
   }
+  /*! Add a callback fired when this specific VM starts a migration*/
+  void on_this_migration_start_cb(const std::function<void(VirtualMachine const&)>& cb)
+  {
+    on_this_migration_start.connect(cb);
+  }
+  /*! \static Add a callback fired when any VM ends a migration*/
   static void on_migration_end_cb(const std::function<void(VirtualMachine const&)>& cb)
   {
     on_migration_end.connect(cb);
   }
+  /*! Add a callback fired when this specific VM ends a migration*/
+  void on_this_migration_end_cb(const std::function<void(VirtualMachine const&)>& cb)
+  {
+    on_this_migration_end.connect(cb);
+  }
 };
-} // namespace s4u
-} // namespace simgrid
+} // namespace simgrid::s4u
 
 #endif
diff --git a/include/simgrid/simix.h b/include/simgrid/simix.h
deleted file mode 100644 (file)
index aa70ca6..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_SIMIX_H
-#define SIMGRID_SIMIX_H
-
-#include <simgrid/forward.h>
-
-// avoid deprecation warning on include (remove entire file with XBT_ATTRIB_DEPRECATED_v335)
-#ifndef SIMIX_H_NO_DEPRECATED_WARNING
-#warning simgrid/simix.h is deprecated and will be removed in v3.35.
-#endif
-
-#ifdef __cplusplus
-
-/******************************************************************************/
-/*                            SIMIX simcalls                                  */
-/******************************************************************************/
-/* These functions are a system call-like interface to the simulation kernel. */
-/* They can also be called from maestro's context, and they are thread safe.  */
-/******************************************************************************/
-
-/************************** Communication simcalls ****************************/
-
-XBT_ATTRIB_DEPRECATED_v335("Please use s4u::Comm::send()") XBT_PUBLIC
-    void simcall_comm_send(simgrid::kernel::actor::ActorImpl* sender, simgrid::kernel::activity::MailboxImpl* mbox,
-                           double task_size, double rate, void* src_buff, size_t src_buff_size,
-                           bool (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
-                           void (*copy_data_fun)(simgrid::kernel::activity::CommImpl*, void*, size_t), void* data,
-                           double timeout);
-
-XBT_ATTRIB_DEPRECATED_v335("Please use s4u::Comm::isend()") XBT_PUBLIC simgrid::kernel::activity::ActivityImplPtr
-    simcall_comm_isend(simgrid::kernel::actor::ActorImpl* sender, simgrid::kernel::activity::MailboxImpl* mbox,
-                       double task_size, double rate, void* src_buff, size_t src_buff_size,
-                       bool (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*), void (*clean_fun)(void*),
-                       void (*copy_data_fun)(simgrid::kernel::activity::CommImpl*, void*, size_t), void* data,
-                       bool detached);
-
-XBT_ATTRIB_DEPRECATED_v335("Please use s4u::Comm::recv()") XBT_PUBLIC
-    void simcall_comm_recv(simgrid::kernel::actor::ActorImpl* receiver, simgrid::kernel::activity::MailboxImpl* mbox,
-                           void* dst_buff, size_t* dst_buff_size,
-                           bool (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
-                           void (*copy_data_fun)(simgrid::kernel::activity::CommImpl*, void*, size_t), void* data,
-                           double timeout, double rate);
-
-XBT_ATTRIB_DEPRECATED_v335("Please use s4u::Comm::irecv()") XBT_PUBLIC simgrid::kernel::activity::ActivityImplPtr
-    simcall_comm_irecv(simgrid::kernel::actor::ActorImpl* receiver, simgrid::kernel::activity::MailboxImpl* mbox,
-                       void* dst_buff, size_t* dst_buff_size,
-                       bool (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
-                       void (*copy_data_fun)(simgrid::kernel::activity::CommImpl*, void*, size_t), void* data,
-                       double rate);
-
-XBT_ATTRIB_DEPRECATED_v335("Please use s4u::Comm::wait_any_for()") XBT_PUBLIC ssize_t
-    simcall_comm_waitany(simgrid::kernel::activity::CommImpl* comms[], size_t count, double timeout);
-XBT_ATTRIB_DEPRECATED_v335("Please use s4u::Comm::wait_for()") XBT_PUBLIC
-    void simcall_comm_wait(simgrid::kernel::activity::ActivityImpl* comm, double timeout);
-XBT_ATTRIB_DEPRECATED_v335("Please use s4u::Comm::test()") XBT_PUBLIC
-    bool simcall_comm_test(simgrid::kernel::activity::ActivityImpl* comm);
-XBT_ATTRIB_DEPRECATED_v335("Please use s4u::Comm::test_any()") XBT_PUBLIC ssize_t
-    simcall_comm_testany(simgrid::kernel::activity::CommImpl* comms[], size_t count);
-
-#endif
-#endif
index 399d63f..338c337 100644 (file)
@@ -20,9 +20,7 @@ XBT_PUBLIC void simcall_run_blocking(std::function<void()> const& code,
 XBT_PUBLIC void simcall_run_object_access(std::function<void()> const& code,
                                           simgrid::kernel::actor::ObjectAccessSimcallItem* item);
 
-namespace simgrid {
-namespace kernel {
-namespace actor {
+namespace simgrid::kernel::actor {
 
 /** Execute some code in kernel context on behalf of the user code.
  *
@@ -115,8 +113,5 @@ auto simcall_blocking(F&& code, Observer* observer) -> decltype(observer->get_re
   simcall_blocking(std::forward<F>(code), static_cast<SimcallObserver*>(observer));
   return observer->get_result();
 }
-// compact namespaces are C++17 and this is a public header file so let's stick to C++14
-} // namespace actor
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::actor
 #endif
index 97071be..35938c4 100644 (file)
@@ -10,8 +10,7 @@
 #ifdef __cplusplus
 
 #include <boost/intrusive_ptr.hpp>
-namespace simgrid {
-namespace smpi {
+namespace simgrid::smpi {
 
 class Colls;
 class Comm;
@@ -31,8 +30,7 @@ class Topo_Graph;
 class Topo_Dist_Graph;
 class Win;
 
-}
-}
+} // namespace simgrid::smpi
 
 using SMPI_Comm                = simgrid::smpi::Comm;
 using SMPI_Datatype            = simgrid::smpi::Datatype;
index 2c0b849..5d61fb0 100644 (file)
 
 #include <sys/time.h> /* Load it before the define next line to not mess with the system headers */
 
-#if SIMGRID_HAVE_MC
 #undef assert
 #define assert(x) MC_assert(!!(x))
-#endif
 
 #ifdef TRACE_CALL_LOCATION /* Defined by smpicc on the command line */
 #include <smpi/smpi_extended_traces.h>
index d13615c..0812035 100644 (file)
@@ -705,8 +705,13 @@ MPI_CALL(XBT_PUBLIC int, MPI_Irsend,
 MPI_CALL(XBT_PUBLIC int, MPI_Sendrecv,
          (const void* sendbuf, int sendcount, MPI_Datatype sendtype, int dst, int sendtag, void* recvbuf, int recvcount,
           MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Status* status));
+MPI_CALL(XBT_PUBLIC int, MPI_Isendrecv,
+         (const void* sendbuf, int sendcount, MPI_Datatype sendtype, int dst, int sendtag, void* recvbuf, int recvcount,
+          MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Request* req));
 MPI_CALL(XBT_PUBLIC int, MPI_Sendrecv_replace, (void* buf, int count, MPI_Datatype datatype, int dst, int sendtag,
                                                 int src, int recvtag, MPI_Comm comm, MPI_Status* status));
+MPI_CALL(XBT_PUBLIC int, MPI_Isendrecv_replace, (void* buf, int count, MPI_Datatype datatype, int dst, int sendtag,
+                                                int src, int recvtag, MPI_Comm comm, MPI_Request* req));
 
 MPI_CALL(XBT_PUBLIC int, MPI_Test, (MPI_Request * request, int* flag, MPI_Status* status));
 MPI_CALL(XBT_PUBLIC int, MPI_Testany, (int count, MPI_Request requests[], int* index, int* flag, MPI_Status* status));
@@ -1123,7 +1128,16 @@ MPI_CALL(XBT_PUBLIC int, MPI_Ineighbor_alltoallw,
           const MPI_Aint* recvdisps, const MPI_Datatype* recvtypes, MPI_Comm comm, MPI_Request *request));
 MPI_CALL(XBT_PUBLIC int, MPI_Status_f2c, (MPI_Fint *f_status, MPI_Status *c_status));
 MPI_CALL(XBT_PUBLIC int, MPI_Status_c2f, (MPI_Status *c_status, MPI_Fint *f_status));
-
+MPI_CALL(XBT_PUBLIC int, MPI_Parrived, (MPI_Request request, int partition, int *flag));
+MPI_CALL(XBT_PUBLIC int, MPI_Pready, (int partitions, MPI_Request request));
+MPI_CALL(XBT_PUBLIC int, MPI_Pready_range, (int partition_low, int partition_high, MPI_Request request));
+MPI_CALL(XBT_PUBLIC int, MPI_Pready_list, (int length, int partition_list[], MPI_Request request));
+MPI_CALL(XBT_PUBLIC int, MPI_Precv_init, (void* buf, int partitions, MPI_Count count,
+                                  MPI_Datatype datatype, int source, int tag, MPI_Comm comm,
+                                  MPI_Info info, MPI_Request *request));
+MPI_CALL(XBT_PUBLIC int, MPI_Psend_init, (const void* buf, int partitions, MPI_Count count,
+                                  MPI_Datatype datatype, int dest, int tag, MPI_Comm comm,
+                                  MPI_Info info, MPI_Request *request));
 
 
 //FIXME: End of all the not yet implemented stuff
@@ -1160,11 +1174,11 @@ XBT_PUBLIC void smpi_comm_set_copy_data_callback(void (*callback)(smx_activity_t
  * called from the user's application! (With the __FILE__ and __LINE__ values
  * passed as parameters.)
  */
-XBT_PUBLIC void smpi_trace_set_call_location(const char* file, int line);
+XBT_PUBLIC void smpi_trace_set_call_location(const char* file, int line, const char* call_name);
 /** Fortran binding **/
-XBT_PUBLIC void smpi_trace_set_call_location_(const char* file, const int* line);
+XBT_PUBLIC void smpi_trace_set_call_location_(const char* file, const int* line, const char* call_name);
 /** Fortran binding + -fsecond-underscore **/
-XBT_PUBLIC void smpi_trace_set_call_location__(const char* file, const int* line);
+XBT_PUBLIC void smpi_trace_set_call_location__(const char* file, const int* line, const char* call_name);
 
 #define SMPI_ITER_NAME1(line) _XBT_CONCAT(iter_count, line)
 #define SMPI_ITER_NAME(line) SMPI_ITER_NAME1(line)
@@ -1235,6 +1249,7 @@ SG_END_DECL
 #ifdef __cplusplus
 XBT_PUBLIC void SMPI_app_instance_start(const char* name, std::function<void()> const& code,
                                         std::vector<simgrid::s4u::Host*> const& hosts);
+XBT_PUBLIC void SMPI_app_instance_join(const std::string& instance_id);
 
 /* This version without parameter is nice to use with SMPI_app_instance_start() */
 XBT_PUBLIC void MPI_Init();
index 19a23aa..f0757ec 100644 (file)
 // in tools/smpi/generate_smpi_defines.pl
 // DO NOT EDIT MANUALLY. ALL CHANGES WILL BE OVERWRITTEN!
 
-#define MPI_Init(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Init(__VA_ARGS__))
-#define MPI_Finalize(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Finalize(__VA_ARGS__))
-#define MPI_Finalized(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Finalized(__VA_ARGS__))
-#define MPI_Init_thread(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Init_thread(__VA_ARGS__))
-#define MPI_Initialized(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Initialized(__VA_ARGS__))
-#define MPI_Query_thread(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Query_thread(__VA_ARGS__))
-#define MPI_Is_thread_main(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Is_thread_main(__VA_ARGS__))
-#define MPI_Get_version(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get_version(__VA_ARGS__))
-#define MPI_Get_library_version(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get_library_version(__VA_ARGS__))
-#define MPI_Get_processor_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get_processor_name(__VA_ARGS__))
-#define MPI_Abort(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Abort(__VA_ARGS__))
-#define MPI_Alloc_mem(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Alloc_mem(__VA_ARGS__))
-#define MPI_Free_mem(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Free_mem(__VA_ARGS__))
-#define MPI_Wtime(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Wtime(__VA_ARGS__))
-#define MPI_Wtick(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Wtick(__VA_ARGS__))
-#define MPI_Buffer_attach(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Buffer_attach(__VA_ARGS__))
-#define MPI_Buffer_detach(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Buffer_detach(__VA_ARGS__))
-#define MPI_Address(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Address(__VA_ARGS__))
-#define MPI_Get_address(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get_address(__VA_ARGS__))
-#define MPI_Aint_diff(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Aint_diff(__VA_ARGS__))
-#define MPI_Aint_add(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Aint_add(__VA_ARGS__))
-#define MPI_Error_class(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Error_class(__VA_ARGS__))
-#define MPI_Error_string(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Error_string(__VA_ARGS__))
-#define MPI_Attr_delete(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Attr_delete(__VA_ARGS__))
-#define MPI_Attr_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Attr_get(__VA_ARGS__))
-#define MPI_Attr_put(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Attr_put(__VA_ARGS__))
-#define MPI_Keyval_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Keyval_create(__VA_ARGS__))
-#define MPI_Keyval_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Keyval_free(__VA_ARGS__))
-#define MPI_Type_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_free(__VA_ARGS__))
-#define MPI_Type_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_size(__VA_ARGS__))
-#define MPI_Type_size_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_size_x(__VA_ARGS__))
-#define MPI_Type_get_extent(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_get_extent(__VA_ARGS__))
-#define MPI_Type_get_extent_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_get_extent_x(__VA_ARGS__))
-#define MPI_Type_get_true_extent(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_get_true_extent(__VA_ARGS__))
-#define MPI_Type_get_true_extent_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_get_true_extent_x(__VA_ARGS__))
-#define MPI_Type_extent(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_extent(__VA_ARGS__))
-#define MPI_Type_lb(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_lb(__VA_ARGS__))
-#define MPI_Type_ub(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_ub(__VA_ARGS__))
-#define MPI_Type_commit(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_commit(__VA_ARGS__))
-#define MPI_Type_hindexed(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_hindexed(__VA_ARGS__))
-#define MPI_Type_create_hindexed(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_hindexed(__VA_ARGS__))
-#define MPI_Type_create_hindexed_block(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_hindexed_block(__VA_ARGS__))
-#define MPI_Type_hvector(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_hvector(__VA_ARGS__))
-#define MPI_Type_create_hvector(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_hvector(__VA_ARGS__))
-#define MPI_Type_indexed(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_indexed(__VA_ARGS__))
-#define MPI_Type_create_indexed(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_indexed(__VA_ARGS__))
-#define MPI_Type_create_indexed_block(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_indexed_block(__VA_ARGS__))
-#define MPI_Type_struct(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_struct(__VA_ARGS__))
-#define MPI_Type_create_struct(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_struct(__VA_ARGS__))
-#define MPI_Type_vector(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_vector(__VA_ARGS__))
-#define MPI_Type_contiguous(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_contiguous(__VA_ARGS__))
-#define MPI_Type_create_resized(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_resized(__VA_ARGS__))
-#define MPI_Type_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_f2c(__VA_ARGS__))
-#define MPI_Type_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_c2f(__VA_ARGS__))
-#define MPI_Get_count(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get_count(__VA_ARGS__))
-#define MPI_Type_get_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_get_attr(__VA_ARGS__))
-#define MPI_Type_set_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_set_attr(__VA_ARGS__))
-#define MPI_Type_delete_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_delete_attr(__VA_ARGS__))
-#define MPI_Type_create_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_keyval(__VA_ARGS__))
-#define MPI_Type_free_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_free_keyval(__VA_ARGS__))
-#define MPI_Type_dup(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_dup(__VA_ARGS__))
-#define MPI_Type_set_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_set_name(__VA_ARGS__))
-#define MPI_Type_get_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_get_name(__VA_ARGS__))
-#define MPI_Pack(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Pack(__VA_ARGS__))
-#define MPI_Pack_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Pack_size(__VA_ARGS__))
-#define MPI_Unpack(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Unpack(__VA_ARGS__))
-#define MPI_Op_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Op_create(__VA_ARGS__))
-#define MPI_Op_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Op_free(__VA_ARGS__))
-#define MPI_Op_commutative(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Op_commutative(__VA_ARGS__))
-#define MPI_Op_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Op_f2c(__VA_ARGS__))
-#define MPI_Op_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Op_c2f(__VA_ARGS__))
-#define MPI_Group_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_free(__VA_ARGS__))
-#define MPI_Group_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_size(__VA_ARGS__))
-#define MPI_Group_rank(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_rank(__VA_ARGS__))
-#define MPI_Group_translate_ranks(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_translate_ranks(__VA_ARGS__))
-#define MPI_Group_compare(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_compare(__VA_ARGS__))
-#define MPI_Group_union(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_union(__VA_ARGS__))
-#define MPI_Group_intersection(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_intersection(__VA_ARGS__))
-#define MPI_Group_difference(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_difference(__VA_ARGS__))
-#define MPI_Group_incl(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_incl(__VA_ARGS__))
-#define MPI_Group_excl(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_excl(__VA_ARGS__))
-#define MPI_Group_range_incl(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_range_incl(__VA_ARGS__))
-#define MPI_Group_range_excl(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_range_excl(__VA_ARGS__))
-#define MPI_Group_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_f2c(__VA_ARGS__))
-#define MPI_Group_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Group_c2f(__VA_ARGS__))
-#define MPI_Comm_rank(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_rank(__VA_ARGS__))
-#define MPI_Comm_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_size(__VA_ARGS__))
-#define MPI_Comm_get_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_get_name(__VA_ARGS__))
-#define MPI_Comm_set_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_set_name(__VA_ARGS__))
-#define MPI_Comm_dup(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_dup(__VA_ARGS__))
-#define MPI_Comm_dup_with_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_dup_with_info(__VA_ARGS__))
-#define MPI_Comm_get_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_get_attr(__VA_ARGS__))
-#define MPI_Comm_set_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_set_attr(__VA_ARGS__))
-#define MPI_Comm_delete_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_delete_attr(__VA_ARGS__))
-#define MPI_Comm_create_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_create_keyval(__VA_ARGS__))
-#define MPI_Comm_free_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_free_keyval(__VA_ARGS__))
-#define MPI_Comm_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_group(__VA_ARGS__))
-#define MPI_Comm_compare(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_compare(__VA_ARGS__))
-#define MPI_Comm_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_create(__VA_ARGS__))
-#define MPI_Comm_create_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_create_group(__VA_ARGS__))
-#define MPI_Comm_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_free(__VA_ARGS__))
-#define MPI_Comm_disconnect(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_disconnect(__VA_ARGS__))
-#define MPI_Comm_split(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_split(__VA_ARGS__))
-#define MPI_Comm_set_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_set_info(__VA_ARGS__))
-#define MPI_Comm_get_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_get_info(__VA_ARGS__))
-#define MPI_Comm_split_type(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_split_type(__VA_ARGS__))
-#define MPI_Comm_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_f2c(__VA_ARGS__))
-#define MPI_Comm_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_c2f(__VA_ARGS__))
-#define MPI_Start(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Start(__VA_ARGS__))
-#define MPI_Startall(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Startall(__VA_ARGS__))
-#define MPI_Request_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Request_free(__VA_ARGS__))
-#define MPI_Recv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Recv(__VA_ARGS__))
-#define MPI_Recv_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Recv_init(__VA_ARGS__))
-#define MPI_Irecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Irecv(__VA_ARGS__))
-#define MPI_Send(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Send(__VA_ARGS__))
-#define MPI_Send_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Send_init(__VA_ARGS__))
-#define MPI_Isend(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Isend(__VA_ARGS__))
-#define MPI_Ssend(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ssend(__VA_ARGS__))
-#define MPI_Ssend_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ssend_init(__VA_ARGS__))
-#define MPI_Issend(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Issend(__VA_ARGS__))
-#define MPI_Bsend(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Bsend(__VA_ARGS__))
-#define MPI_Bsend_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Bsend_init(__VA_ARGS__))
-#define MPI_Ibsend(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ibsend(__VA_ARGS__))
-#define MPI_Rsend(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Rsend(__VA_ARGS__))
-#define MPI_Rsend_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Rsend_init(__VA_ARGS__))
-#define MPI_Irsend(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Irsend(__VA_ARGS__))
-#define MPI_Sendrecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Sendrecv(__VA_ARGS__))
-#define MPI_Sendrecv_replace(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Sendrecv_replace(__VA_ARGS__))
-#define MPI_Test(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Test(__VA_ARGS__))
-#define MPI_Testany(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Testany(__VA_ARGS__))
-#define MPI_Testall(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Testall(__VA_ARGS__))
-#define MPI_Testsome(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Testsome(__VA_ARGS__))
-#define MPI_Test_cancelled(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Test_cancelled(__VA_ARGS__))
-#define MPI_Wait(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Wait(__VA_ARGS__))
-#define MPI_Waitany(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Waitany(__VA_ARGS__))
-#define MPI_Waitall(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Waitall(__VA_ARGS__))
-#define MPI_Waitsome(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Waitsome(__VA_ARGS__))
-#define MPI_Iprobe(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Iprobe(__VA_ARGS__))
-#define MPI_Probe(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Probe(__VA_ARGS__))
-#define MPI_Request_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Request_f2c(__VA_ARGS__))
-#define MPI_Request_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Request_c2f(__VA_ARGS__))
-#define MPI_Cancel(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cancel(__VA_ARGS__))
-#define MPI_Bcast(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Bcast(__VA_ARGS__))
-#define MPI_Barrier(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Barrier(__VA_ARGS__))
-#define MPI_Ibarrier(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ibarrier(__VA_ARGS__))
-#define MPI_Ibcast(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ibcast(__VA_ARGS__))
-#define MPI_Igather(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Igather(__VA_ARGS__))
-#define MPI_Igatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Igatherv(__VA_ARGS__))
-#define MPI_Iallgather(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Iallgather(__VA_ARGS__))
-#define MPI_Iallgatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Iallgatherv(__VA_ARGS__))
-#define MPI_Iscatter(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Iscatter(__VA_ARGS__))
-#define MPI_Iscatterv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Iscatterv(__VA_ARGS__))
-#define MPI_Ireduce(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ireduce(__VA_ARGS__))
-#define MPI_Iallreduce(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Iallreduce(__VA_ARGS__))
-#define MPI_Iscan(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Iscan(__VA_ARGS__))
-#define MPI_Iexscan(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Iexscan(__VA_ARGS__))
-#define MPI_Ireduce_scatter(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ireduce_scatter(__VA_ARGS__))
-#define MPI_Ireduce_scatter_block(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ireduce_scatter_block(__VA_ARGS__))
-#define MPI_Ialltoall(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ialltoall(__VA_ARGS__))
-#define MPI_Ialltoallv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ialltoallv(__VA_ARGS__))
-#define MPI_Ialltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ialltoallw(__VA_ARGS__))
-#define MPI_Gather(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Gather(__VA_ARGS__))
-#define MPI_Gatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Gatherv(__VA_ARGS__))
-#define MPI_Allgather(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Allgather(__VA_ARGS__))
-#define MPI_Allgatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Allgatherv(__VA_ARGS__))
-#define MPI_Scatter(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Scatter(__VA_ARGS__))
-#define MPI_Scatterv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Scatterv(__VA_ARGS__))
-#define MPI_Reduce(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Reduce(__VA_ARGS__))
-#define MPI_Allreduce(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Allreduce(__VA_ARGS__))
-#define MPI_Scan(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Scan(__VA_ARGS__))
-#define MPI_Exscan(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Exscan(__VA_ARGS__))
-#define MPI_Reduce_scatter(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Reduce_scatter(__VA_ARGS__))
-#define MPI_Reduce_scatter_block(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Reduce_scatter_block(__VA_ARGS__))
-#define MPI_Alltoall(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Alltoall(__VA_ARGS__))
-#define MPI_Alltoallv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Alltoallv(__VA_ARGS__))
-#define MPI_Alltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Alltoallw(__VA_ARGS__))
-#define MPI_Reduce_local(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Reduce_local(__VA_ARGS__))
-#define MPI_Info_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_create(__VA_ARGS__))
-#define MPI_Info_set(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_set(__VA_ARGS__))
-#define MPI_Info_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_get(__VA_ARGS__))
-#define MPI_Info_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_free(__VA_ARGS__))
-#define MPI_Info_delete(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_delete(__VA_ARGS__))
-#define MPI_Info_dup(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_dup(__VA_ARGS__))
-#define MPI_Info_get_nkeys(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_get_nkeys(__VA_ARGS__))
-#define MPI_Info_get_nthkey(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_get_nthkey(__VA_ARGS__))
-#define MPI_Info_get_valuelen(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_get_valuelen(__VA_ARGS__))
-#define MPI_Info_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_f2c(__VA_ARGS__))
-#define MPI_Info_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Info_c2f(__VA_ARGS__))
-#define MPI_Win_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_free(__VA_ARGS__))
-#define MPI_Win_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_create(__VA_ARGS__))
-#define MPI_Win_allocate(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_allocate(__VA_ARGS__))
-#define MPI_Win_allocate_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_allocate_shared(__VA_ARGS__))
-#define MPI_Win_create_dynamic(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_create_dynamic(__VA_ARGS__))
-#define MPI_Win_attach(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_attach(__VA_ARGS__))
-#define MPI_Win_detach(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_detach(__VA_ARGS__))
-#define MPI_Win_set_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_set_name(__VA_ARGS__))
-#define MPI_Win_get_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_get_name(__VA_ARGS__))
-#define MPI_Win_set_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_set_info(__VA_ARGS__))
-#define MPI_Win_get_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_get_info(__VA_ARGS__))
-#define MPI_Win_get_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_get_group(__VA_ARGS__))
-#define MPI_Win_fence(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_fence(__VA_ARGS__))
-#define MPI_Win_get_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_get_attr(__VA_ARGS__))
-#define MPI_Win_set_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_set_attr(__VA_ARGS__))
-#define MPI_Win_delete_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_delete_attr(__VA_ARGS__))
-#define MPI_Win_create_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_create_keyval(__VA_ARGS__))
-#define MPI_Win_free_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_free_keyval(__VA_ARGS__))
-#define MPI_Win_complete(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_complete(__VA_ARGS__))
-#define MPI_Win_post(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_post(__VA_ARGS__))
-#define MPI_Win_start(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_start(__VA_ARGS__))
-#define MPI_Win_wait(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_wait(__VA_ARGS__))
-#define MPI_Win_lock(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_lock(__VA_ARGS__))
-#define MPI_Win_lock_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_lock_all(__VA_ARGS__))
-#define MPI_Win_unlock(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_unlock(__VA_ARGS__))
-#define MPI_Win_unlock_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_unlock_all(__VA_ARGS__))
-#define MPI_Win_flush(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_flush(__VA_ARGS__))
-#define MPI_Win_flush_local(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_flush_local(__VA_ARGS__))
-#define MPI_Win_flush_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_flush_all(__VA_ARGS__))
-#define MPI_Win_flush_local_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_flush_local_all(__VA_ARGS__))
-#define MPI_Win_shared_query(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_shared_query(__VA_ARGS__))
-#define MPI_Win_sync(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_sync(__VA_ARGS__))
-#define MPI_Win_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_f2c(__VA_ARGS__))
-#define MPI_Win_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_c2f(__VA_ARGS__))
-#define MPI_Get(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get(__VA_ARGS__))
-#define MPI_Put(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Put(__VA_ARGS__))
-#define MPI_Accumulate(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Accumulate(__VA_ARGS__))
-#define MPI_Get_accumulate(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get_accumulate(__VA_ARGS__))
-#define MPI_Rget(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Rget(__VA_ARGS__))
-#define MPI_Rput(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Rput(__VA_ARGS__))
-#define MPI_Raccumulate(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Raccumulate(__VA_ARGS__))
-#define MPI_Rget_accumulate(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Rget_accumulate(__VA_ARGS__))
-#define MPI_Fetch_and_op(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Fetch_and_op(__VA_ARGS__))
-#define MPI_Compare_and_swap(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Compare_and_swap(__VA_ARGS__))
-#define MPI_Cart_coords(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cart_coords(__VA_ARGS__))
-#define MPI_Cart_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cart_create(__VA_ARGS__))
-#define MPI_Cart_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cart_get(__VA_ARGS__))
-#define MPI_Cart_rank(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cart_rank(__VA_ARGS__))
-#define MPI_Cart_shift(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cart_shift(__VA_ARGS__))
-#define MPI_Cart_sub(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cart_sub(__VA_ARGS__))
-#define MPI_Cartdim_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cartdim_get(__VA_ARGS__))
-#define MPI_Dims_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Dims_create(__VA_ARGS__))
-#define MPI_Request_get_status(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Request_get_status(__VA_ARGS__))
-#define MPI_Grequest_start(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Grequest_start(__VA_ARGS__))
-#define MPI_Grequest_complete(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Grequest_complete(__VA_ARGS__))
-#define MPI_Status_set_cancelled(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Status_set_cancelled(__VA_ARGS__))
-#define MPI_Status_set_elements(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Status_set_elements(__VA_ARGS__))
-#define MPI_Status_set_elements_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Status_set_elements_x(__VA_ARGS__))
-#define MPI_Type_create_subarray(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_subarray(__VA_ARGS__))
-#define MPI_File_open(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_open(__VA_ARGS__))
-#define MPI_File_close(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_close(__VA_ARGS__))
-#define MPI_File_delete(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_delete(__VA_ARGS__))
-#define MPI_File_get_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_size(__VA_ARGS__))
-#define MPI_File_get_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_group(__VA_ARGS__))
-#define MPI_File_get_amode(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_amode(__VA_ARGS__))
-#define MPI_File_set_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_set_info(__VA_ARGS__))
-#define MPI_File_get_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_info(__VA_ARGS__))
-#define MPI_File_read_at(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_at(__VA_ARGS__))
-#define MPI_File_read_at_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_at_all(__VA_ARGS__))
-#define MPI_File_write_at(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_at(__VA_ARGS__))
-#define MPI_File_write_at_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_at_all(__VA_ARGS__))
-#define MPI_File_read(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read(__VA_ARGS__))
-#define MPI_File_read_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_all(__VA_ARGS__))
-#define MPI_File_write(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write(__VA_ARGS__))
-#define MPI_File_write_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_all(__VA_ARGS__))
-#define MPI_File_seek(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_seek(__VA_ARGS__))
-#define MPI_File_get_position(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_position(__VA_ARGS__))
-#define MPI_File_read_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_shared(__VA_ARGS__))
-#define MPI_File_write_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_shared(__VA_ARGS__))
-#define MPI_File_read_ordered(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_ordered(__VA_ARGS__))
-#define MPI_File_write_ordered(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_ordered(__VA_ARGS__))
-#define MPI_File_seek_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_seek_shared(__VA_ARGS__))
-#define MPI_File_get_position_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_position_shared(__VA_ARGS__))
-#define MPI_File_sync(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_sync(__VA_ARGS__))
-#define MPI_File_set_view(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_set_view(__VA_ARGS__))
-#define MPI_File_get_view(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_view(__VA_ARGS__))
-#define MPI_Errhandler_set(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Errhandler_set(__VA_ARGS__))
-#define MPI_Errhandler_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Errhandler_create(__VA_ARGS__))
-#define MPI_Errhandler_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Errhandler_free(__VA_ARGS__))
-#define MPI_Errhandler_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Errhandler_get(__VA_ARGS__))
-#define MPI_Comm_set_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_set_errhandler(__VA_ARGS__))
-#define MPI_Comm_get_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_get_errhandler(__VA_ARGS__))
-#define MPI_Comm_create_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_create_errhandler(__VA_ARGS__))
-#define MPI_Comm_call_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_call_errhandler(__VA_ARGS__))
-#define MPI_Win_set_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_set_errhandler(__VA_ARGS__))
-#define MPI_Win_get_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_get_errhandler(__VA_ARGS__))
-#define MPI_Win_create_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_create_errhandler(__VA_ARGS__))
-#define MPI_Win_call_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_call_errhandler(__VA_ARGS__))
-#define MPI_Errhandler_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Errhandler_f2c(__VA_ARGS__))
-#define MPI_Errhandler_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Errhandler_c2f(__VA_ARGS__))
-#define MPI_Type_create_f90_integer(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_f90_integer(__VA_ARGS__))
-#define MPI_Type_create_f90_real(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_f90_real(__VA_ARGS__))
-#define MPI_Type_create_f90_complex(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_f90_complex(__VA_ARGS__))
-#define MPI_Type_get_contents(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_get_contents(__VA_ARGS__))
-#define MPI_Type_get_envelope(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_get_envelope(__VA_ARGS__))
-#define MPI_File_call_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_call_errhandler(__VA_ARGS__))
-#define MPI_File_create_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_create_errhandler(__VA_ARGS__))
-#define MPI_File_set_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_set_errhandler(__VA_ARGS__))
-#define MPI_File_get_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_errhandler(__VA_ARGS__))
-#define MPI_Cart_map(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Cart_map(__VA_ARGS__))
-#define MPI_Graph_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Graph_create(__VA_ARGS__))
-#define MPI_Graph_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Graph_get(__VA_ARGS__))
-#define MPI_Graph_map(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Graph_map(__VA_ARGS__))
-#define MPI_Graph_neighbors(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Graph_neighbors(__VA_ARGS__))
-#define MPI_Graph_neighbors_count(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Graph_neighbors_count(__VA_ARGS__))
-#define MPI_Graphdims_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Graphdims_get(__VA_ARGS__))
-#define MPI_Topo_test(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Topo_test(__VA_ARGS__))
-#define MPI_Add_error_class(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Add_error_class(__VA_ARGS__))
-#define MPI_Add_error_code(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Add_error_code(__VA_ARGS__))
-#define MPI_Add_error_string(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Add_error_string(__VA_ARGS__))
-#define MPI_Comm_test_inter(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_test_inter(__VA_ARGS__))
-#define MPI_Intercomm_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Intercomm_create(__VA_ARGS__))
-#define MPI_Intercomm_merge(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Intercomm_merge(__VA_ARGS__))
-#define MPI_Comm_remote_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_remote_group(__VA_ARGS__))
-#define MPI_Comm_remote_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_remote_size(__VA_ARGS__))
-#define MPI_Get_elements(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get_elements(__VA_ARGS__))
-#define MPI_Get_elements_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Get_elements_x(__VA_ARGS__))
-#define MPI_Pcontrol(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Pcontrol(__VA_ARGS__))
-#define MPI_Type_create_darray(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_create_darray(__VA_ARGS__))
-#define MPI_Pack_external_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Pack_external_size(__VA_ARGS__))
-#define MPI_Pack_external(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Pack_external(__VA_ARGS__))
-#define MPI_Unpack_external(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Unpack_external(__VA_ARGS__))
-#define MPI_Type_match_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Type_match_size(__VA_ARGS__))
-#define MPI_Comm_connect(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_connect(__VA_ARGS__))
-#define MPI_Unpublish_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Unpublish_name(__VA_ARGS__))
-#define MPI_Publish_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Publish_name(__VA_ARGS__))
-#define MPI_Lookup_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Lookup_name(__VA_ARGS__))
-#define MPI_Comm_idup(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_idup(__VA_ARGS__))
-#define MPI_Comm_join(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_join(__VA_ARGS__))
-#define MPI_Open_port(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Open_port(__VA_ARGS__))
-#define MPI_Close_port(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Close_port(__VA_ARGS__))
-#define MPI_Comm_accept(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_accept(__VA_ARGS__))
-#define MPI_Comm_spawn(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_spawn(__VA_ARGS__))
-#define MPI_Comm_spawn_multiple(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_spawn_multiple(__VA_ARGS__))
-#define MPI_Comm_get_parent(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Comm_get_parent(__VA_ARGS__))
-#define MPI_Dist_graph_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Dist_graph_create(__VA_ARGS__))
-#define MPI_Dist_graph_create_adjacent(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Dist_graph_create_adjacent(__VA_ARGS__))
-#define MPI_Dist_graph_neighbors(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Dist_graph_neighbors(__VA_ARGS__))
-#define MPI_Dist_graph_neighbors_count(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Dist_graph_neighbors_count(__VA_ARGS__))
-#define MPI_Win_test(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Win_test(__VA_ARGS__))
-#define MPI_File_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_c2f(__VA_ARGS__))
-#define MPI_File_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_f2c(__VA_ARGS__))
-#define MPI_Register_datarep(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Register_datarep(__VA_ARGS__))
-#define MPI_File_set_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_set_size(__VA_ARGS__))
-#define MPI_File_preallocate(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_preallocate(__VA_ARGS__))
-#define MPI_File_iread_at(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iread_at(__VA_ARGS__))
-#define MPI_File_iwrite_at(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iwrite_at(__VA_ARGS__))
-#define MPI_File_iread_at_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iread_at_all(__VA_ARGS__))
-#define MPI_File_iwrite_at_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iwrite_at_all(__VA_ARGS__))
-#define MPI_File_iread(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iread(__VA_ARGS__))
-#define MPI_File_iwrite(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iwrite(__VA_ARGS__))
-#define MPI_File_iread_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iread_all(__VA_ARGS__))
-#define MPI_File_iwrite_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iwrite_all(__VA_ARGS__))
-#define MPI_File_get_byte_offset(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_byte_offset(__VA_ARGS__))
-#define MPI_File_iread_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iread_shared(__VA_ARGS__))
-#define MPI_File_iwrite_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_iwrite_shared(__VA_ARGS__))
-#define MPI_File_read_at_all_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_at_all_begin(__VA_ARGS__))
-#define MPI_File_read_at_all_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_at_all_end(__VA_ARGS__))
-#define MPI_File_write_at_all_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_at_all_begin(__VA_ARGS__))
-#define MPI_File_write_at_all_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_at_all_end(__VA_ARGS__))
-#define MPI_File_read_all_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_all_begin(__VA_ARGS__))
-#define MPI_File_read_all_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_all_end(__VA_ARGS__))
-#define MPI_File_write_all_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_all_begin(__VA_ARGS__))
-#define MPI_File_write_all_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_all_end(__VA_ARGS__))
-#define MPI_File_read_ordered_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_ordered_begin(__VA_ARGS__))
-#define MPI_File_read_ordered_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_read_ordered_end(__VA_ARGS__))
-#define MPI_File_write_ordered_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_ordered_begin(__VA_ARGS__))
-#define MPI_File_write_ordered_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_write_ordered_end(__VA_ARGS__))
-#define MPI_File_get_type_extent(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_type_extent(__VA_ARGS__))
-#define MPI_File_set_atomicity(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_set_atomicity(__VA_ARGS__))
-#define MPI_File_get_atomicity(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_File_get_atomicity(__VA_ARGS__))
-#define MPI_Message_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Message_f2c(__VA_ARGS__))
-#define MPI_Message_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Message_c2f(__VA_ARGS__))
-#define MPI_Mrecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Mrecv(__VA_ARGS__))
-#define MPI_Mprobe(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Mprobe(__VA_ARGS__))
-#define MPI_Imrecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Imrecv(__VA_ARGS__))
-#define MPI_Improbe(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Improbe(__VA_ARGS__))
-#define MPI_Neighbor_allgather(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Neighbor_allgather(__VA_ARGS__))
-#define MPI_Neighbor_allgatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Neighbor_allgatherv(__VA_ARGS__))
-#define MPI_Neighbor_alltoall(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Neighbor_alltoall(__VA_ARGS__))
-#define MPI_Neighbor_alltoallv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Neighbor_alltoallv(__VA_ARGS__))
-#define MPI_Neighbor_alltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Neighbor_alltoallw(__VA_ARGS__))
-#define MPI_Ineighbor_allgather(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ineighbor_allgather(__VA_ARGS__))
-#define MPI_Ineighbor_allgatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ineighbor_allgatherv(__VA_ARGS__))
-#define MPI_Ineighbor_alltoall(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ineighbor_alltoall(__VA_ARGS__))
-#define MPI_Ineighbor_alltoallv(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ineighbor_alltoallv(__VA_ARGS__))
-#define MPI_Ineighbor_alltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Ineighbor_alltoallw(__VA_ARGS__))
-#define MPI_Status_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Status_f2c(__VA_ARGS__))
-#define MPI_Status_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__), MPI_Status_c2f(__VA_ARGS__))
+#define MPI_Init(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Init"), MPI_Init(__VA_ARGS__))
+#define MPI_Finalize(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Finalize"), MPI_Finalize(__VA_ARGS__))
+#define MPI_Finalized(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Finalized"), MPI_Finalized(__VA_ARGS__))
+#define MPI_Init_thread(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Init_thread"), MPI_Init_thread(__VA_ARGS__))
+#define MPI_Initialized(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Initialized"), MPI_Initialized(__VA_ARGS__))
+#define MPI_Query_thread(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Query_thread"), MPI_Query_thread(__VA_ARGS__))
+#define MPI_Is_thread_main(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Is_thread_main"), MPI_Is_thread_main(__VA_ARGS__))
+#define MPI_Get_version(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get_version"), MPI_Get_version(__VA_ARGS__))
+#define MPI_Get_library_version(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get_library_version"), MPI_Get_library_version(__VA_ARGS__))
+#define MPI_Get_processor_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get_processor_name"), MPI_Get_processor_name(__VA_ARGS__))
+#define MPI_Abort(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Abort"), MPI_Abort(__VA_ARGS__))
+#define MPI_Alloc_mem(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Alloc_mem"), MPI_Alloc_mem(__VA_ARGS__))
+#define MPI_Free_mem(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Free_mem"), MPI_Free_mem(__VA_ARGS__))
+#define MPI_Wtime(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Wtime"), MPI_Wtime(__VA_ARGS__))
+#define MPI_Wtick(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Wtick"), MPI_Wtick(__VA_ARGS__))
+#define MPI_Buffer_attach(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Buffer_attach"), MPI_Buffer_attach(__VA_ARGS__))
+#define MPI_Buffer_detach(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Buffer_detach"), MPI_Buffer_detach(__VA_ARGS__))
+#define MPI_Address(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Address"), MPI_Address(__VA_ARGS__))
+#define MPI_Get_address(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get_address"), MPI_Get_address(__VA_ARGS__))
+#define MPI_Aint_diff(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Aint_diff"), MPI_Aint_diff(__VA_ARGS__))
+#define MPI_Aint_add(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Aint_add"), MPI_Aint_add(__VA_ARGS__))
+#define MPI_Error_class(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Error_class"), MPI_Error_class(__VA_ARGS__))
+#define MPI_Error_string(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Error_string"), MPI_Error_string(__VA_ARGS__))
+#define MPI_Attr_delete(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Attr_delete"), MPI_Attr_delete(__VA_ARGS__))
+#define MPI_Attr_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Attr_get"), MPI_Attr_get(__VA_ARGS__))
+#define MPI_Attr_put(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Attr_put"), MPI_Attr_put(__VA_ARGS__))
+#define MPI_Keyval_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Keyval_create"), MPI_Keyval_create(__VA_ARGS__))
+#define MPI_Keyval_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Keyval_free"), MPI_Keyval_free(__VA_ARGS__))
+#define MPI_Type_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_free"), MPI_Type_free(__VA_ARGS__))
+#define MPI_Type_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_size"), MPI_Type_size(__VA_ARGS__))
+#define MPI_Type_size_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_size_x"), MPI_Type_size_x(__VA_ARGS__))
+#define MPI_Type_get_extent(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_get_extent"), MPI_Type_get_extent(__VA_ARGS__))
+#define MPI_Type_get_extent_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_get_extent_x"), MPI_Type_get_extent_x(__VA_ARGS__))
+#define MPI_Type_get_true_extent(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_get_true_extent"), MPI_Type_get_true_extent(__VA_ARGS__))
+#define MPI_Type_get_true_extent_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_get_true_extent_x"), MPI_Type_get_true_extent_x(__VA_ARGS__))
+#define MPI_Type_extent(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_extent"), MPI_Type_extent(__VA_ARGS__))
+#define MPI_Type_lb(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_lb"), MPI_Type_lb(__VA_ARGS__))
+#define MPI_Type_ub(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_ub"), MPI_Type_ub(__VA_ARGS__))
+#define MPI_Type_commit(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_commit"), MPI_Type_commit(__VA_ARGS__))
+#define MPI_Type_hindexed(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_hindexed"), MPI_Type_hindexed(__VA_ARGS__))
+#define MPI_Type_create_hindexed(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_hindexed"), MPI_Type_create_hindexed(__VA_ARGS__))
+#define MPI_Type_create_hindexed_block(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_hindexed_block"), MPI_Type_create_hindexed_block(__VA_ARGS__))
+#define MPI_Type_hvector(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_hvector"), MPI_Type_hvector(__VA_ARGS__))
+#define MPI_Type_create_hvector(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_hvector"), MPI_Type_create_hvector(__VA_ARGS__))
+#define MPI_Type_indexed(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_indexed"), MPI_Type_indexed(__VA_ARGS__))
+#define MPI_Type_create_indexed(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_indexed"), MPI_Type_create_indexed(__VA_ARGS__))
+#define MPI_Type_create_indexed_block(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_indexed_block"), MPI_Type_create_indexed_block(__VA_ARGS__))
+#define MPI_Type_struct(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_struct"), MPI_Type_struct(__VA_ARGS__))
+#define MPI_Type_create_struct(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_struct"), MPI_Type_create_struct(__VA_ARGS__))
+#define MPI_Type_vector(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_vector"), MPI_Type_vector(__VA_ARGS__))
+#define MPI_Type_contiguous(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_contiguous"), MPI_Type_contiguous(__VA_ARGS__))
+#define MPI_Type_create_resized(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_resized"), MPI_Type_create_resized(__VA_ARGS__))
+#define MPI_Type_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_f2c"), MPI_Type_f2c(__VA_ARGS__))
+#define MPI_Type_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_c2f"), MPI_Type_c2f(__VA_ARGS__))
+#define MPI_Get_count(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get_count"), MPI_Get_count(__VA_ARGS__))
+#define MPI_Type_get_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_get_attr"), MPI_Type_get_attr(__VA_ARGS__))
+#define MPI_Type_set_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_set_attr"), MPI_Type_set_attr(__VA_ARGS__))
+#define MPI_Type_delete_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_delete_attr"), MPI_Type_delete_attr(__VA_ARGS__))
+#define MPI_Type_create_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_keyval"), MPI_Type_create_keyval(__VA_ARGS__))
+#define MPI_Type_free_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_free_keyval"), MPI_Type_free_keyval(__VA_ARGS__))
+#define MPI_Type_dup(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_dup"), MPI_Type_dup(__VA_ARGS__))
+#define MPI_Type_set_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_set_name"), MPI_Type_set_name(__VA_ARGS__))
+#define MPI_Type_get_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_get_name"), MPI_Type_get_name(__VA_ARGS__))
+#define MPI_Pack(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pack"), MPI_Pack(__VA_ARGS__))
+#define MPI_Pack_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pack_size"), MPI_Pack_size(__VA_ARGS__))
+#define MPI_Unpack(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Unpack"), MPI_Unpack(__VA_ARGS__))
+#define MPI_Op_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Op_create"), MPI_Op_create(__VA_ARGS__))
+#define MPI_Op_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Op_free"), MPI_Op_free(__VA_ARGS__))
+#define MPI_Op_commutative(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Op_commutative"), MPI_Op_commutative(__VA_ARGS__))
+#define MPI_Op_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Op_f2c"), MPI_Op_f2c(__VA_ARGS__))
+#define MPI_Op_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Op_c2f"), MPI_Op_c2f(__VA_ARGS__))
+#define MPI_Group_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_free"), MPI_Group_free(__VA_ARGS__))
+#define MPI_Group_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_size"), MPI_Group_size(__VA_ARGS__))
+#define MPI_Group_rank(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_rank"), MPI_Group_rank(__VA_ARGS__))
+#define MPI_Group_translate_ranks(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_translate_ranks"), MPI_Group_translate_ranks(__VA_ARGS__))
+#define MPI_Group_compare(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_compare"), MPI_Group_compare(__VA_ARGS__))
+#define MPI_Group_union(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_union"), MPI_Group_union(__VA_ARGS__))
+#define MPI_Group_intersection(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_intersection"), MPI_Group_intersection(__VA_ARGS__))
+#define MPI_Group_difference(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_difference"), MPI_Group_difference(__VA_ARGS__))
+#define MPI_Group_incl(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_incl"), MPI_Group_incl(__VA_ARGS__))
+#define MPI_Group_excl(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_excl"), MPI_Group_excl(__VA_ARGS__))
+#define MPI_Group_range_incl(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_range_incl"), MPI_Group_range_incl(__VA_ARGS__))
+#define MPI_Group_range_excl(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_range_excl"), MPI_Group_range_excl(__VA_ARGS__))
+#define MPI_Group_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_f2c"), MPI_Group_f2c(__VA_ARGS__))
+#define MPI_Group_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Group_c2f"), MPI_Group_c2f(__VA_ARGS__))
+#define MPI_Comm_rank(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_rank"), MPI_Comm_rank(__VA_ARGS__))
+#define MPI_Comm_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_size"), MPI_Comm_size(__VA_ARGS__))
+#define MPI_Comm_get_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_get_name"), MPI_Comm_get_name(__VA_ARGS__))
+#define MPI_Comm_set_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_set_name"), MPI_Comm_set_name(__VA_ARGS__))
+#define MPI_Comm_dup(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_dup"), MPI_Comm_dup(__VA_ARGS__))
+#define MPI_Comm_dup_with_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_dup_with_info"), MPI_Comm_dup_with_info(__VA_ARGS__))
+#define MPI_Comm_get_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_get_attr"), MPI_Comm_get_attr(__VA_ARGS__))
+#define MPI_Comm_set_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_set_attr"), MPI_Comm_set_attr(__VA_ARGS__))
+#define MPI_Comm_delete_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_delete_attr"), MPI_Comm_delete_attr(__VA_ARGS__))
+#define MPI_Comm_create_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_create_keyval"), MPI_Comm_create_keyval(__VA_ARGS__))
+#define MPI_Comm_free_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_free_keyval"), MPI_Comm_free_keyval(__VA_ARGS__))
+#define MPI_Comm_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_group"), MPI_Comm_group(__VA_ARGS__))
+#define MPI_Comm_compare(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_compare"), MPI_Comm_compare(__VA_ARGS__))
+#define MPI_Comm_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_create"), MPI_Comm_create(__VA_ARGS__))
+#define MPI_Comm_create_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_create_group"), MPI_Comm_create_group(__VA_ARGS__))
+#define MPI_Comm_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_free"), MPI_Comm_free(__VA_ARGS__))
+#define MPI_Comm_disconnect(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_disconnect"), MPI_Comm_disconnect(__VA_ARGS__))
+#define MPI_Comm_split(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_split"), MPI_Comm_split(__VA_ARGS__))
+#define MPI_Comm_set_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_set_info"), MPI_Comm_set_info(__VA_ARGS__))
+#define MPI_Comm_get_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_get_info"), MPI_Comm_get_info(__VA_ARGS__))
+#define MPI_Comm_split_type(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_split_type"), MPI_Comm_split_type(__VA_ARGS__))
+#define MPI_Comm_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_f2c"), MPI_Comm_f2c(__VA_ARGS__))
+#define MPI_Comm_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_c2f"), MPI_Comm_c2f(__VA_ARGS__))
+#define MPI_Start(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Start"), MPI_Start(__VA_ARGS__))
+#define MPI_Startall(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Startall"), MPI_Startall(__VA_ARGS__))
+#define MPI_Request_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Request_free"), MPI_Request_free(__VA_ARGS__))
+#define MPI_Recv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Recv"), MPI_Recv(__VA_ARGS__))
+#define MPI_Recv_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Recv_init"), MPI_Recv_init(__VA_ARGS__))
+#define MPI_Irecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Irecv"), MPI_Irecv(__VA_ARGS__))
+#define MPI_Send(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Send"), MPI_Send(__VA_ARGS__))
+#define MPI_Send_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Send_init"), MPI_Send_init(__VA_ARGS__))
+#define MPI_Isend(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Isend"), MPI_Isend(__VA_ARGS__))
+#define MPI_Ssend(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ssend"), MPI_Ssend(__VA_ARGS__))
+#define MPI_Ssend_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ssend_init"), MPI_Ssend_init(__VA_ARGS__))
+#define MPI_Issend(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Issend"), MPI_Issend(__VA_ARGS__))
+#define MPI_Bsend(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Bsend"), MPI_Bsend(__VA_ARGS__))
+#define MPI_Bsend_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Bsend_init"), MPI_Bsend_init(__VA_ARGS__))
+#define MPI_Ibsend(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ibsend"), MPI_Ibsend(__VA_ARGS__))
+#define MPI_Rsend(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Rsend"), MPI_Rsend(__VA_ARGS__))
+#define MPI_Rsend_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Rsend_init"), MPI_Rsend_init(__VA_ARGS__))
+#define MPI_Irsend(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Irsend"), MPI_Irsend(__VA_ARGS__))
+#define MPI_Sendrecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Sendrecv"), MPI_Sendrecv(__VA_ARGS__))
+#define MPI_Isendrecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Isendrecv"), MPI_Isendrecv(__VA_ARGS__))
+#define MPI_Sendrecv_replace(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Sendrecv_replace"), MPI_Sendrecv_replace(__VA_ARGS__))
+#define MPI_Isendrecv_replace(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Isendrecv_replace"), MPI_Isendrecv_replace(__VA_ARGS__))
+#define MPI_Test(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Test"), MPI_Test(__VA_ARGS__))
+#define MPI_Testany(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Testany"), MPI_Testany(__VA_ARGS__))
+#define MPI_Testall(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Testall"), MPI_Testall(__VA_ARGS__))
+#define MPI_Testsome(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Testsome"), MPI_Testsome(__VA_ARGS__))
+#define MPI_Test_cancelled(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Test_cancelled"), MPI_Test_cancelled(__VA_ARGS__))
+#define MPI_Wait(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Wait"), MPI_Wait(__VA_ARGS__))
+#define MPI_Waitany(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Waitany"), MPI_Waitany(__VA_ARGS__))
+#define MPI_Waitall(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Waitall"), MPI_Waitall(__VA_ARGS__))
+#define MPI_Waitsome(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Waitsome"), MPI_Waitsome(__VA_ARGS__))
+#define MPI_Iprobe(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Iprobe"), MPI_Iprobe(__VA_ARGS__))
+#define MPI_Probe(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Probe"), MPI_Probe(__VA_ARGS__))
+#define MPI_Request_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Request_f2c"), MPI_Request_f2c(__VA_ARGS__))
+#define MPI_Request_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Request_c2f"), MPI_Request_c2f(__VA_ARGS__))
+#define MPI_Cancel(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cancel"), MPI_Cancel(__VA_ARGS__))
+#define MPI_Bcast(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Bcast"), MPI_Bcast(__VA_ARGS__))
+#define MPI_Barrier(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Barrier"), MPI_Barrier(__VA_ARGS__))
+#define MPI_Ibarrier(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ibarrier"), MPI_Ibarrier(__VA_ARGS__))
+#define MPI_Ibcast(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ibcast"), MPI_Ibcast(__VA_ARGS__))
+#define MPI_Igather(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Igather"), MPI_Igather(__VA_ARGS__))
+#define MPI_Igatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Igatherv"), MPI_Igatherv(__VA_ARGS__))
+#define MPI_Iallgather(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Iallgather"), MPI_Iallgather(__VA_ARGS__))
+#define MPI_Iallgatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Iallgatherv"), MPI_Iallgatherv(__VA_ARGS__))
+#define MPI_Iscatter(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Iscatter"), MPI_Iscatter(__VA_ARGS__))
+#define MPI_Iscatterv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Iscatterv"), MPI_Iscatterv(__VA_ARGS__))
+#define MPI_Ireduce(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ireduce"), MPI_Ireduce(__VA_ARGS__))
+#define MPI_Iallreduce(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Iallreduce"), MPI_Iallreduce(__VA_ARGS__))
+#define MPI_Iscan(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Iscan"), MPI_Iscan(__VA_ARGS__))
+#define MPI_Iexscan(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Iexscan"), MPI_Iexscan(__VA_ARGS__))
+#define MPI_Ireduce_scatter(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ireduce_scatter"), MPI_Ireduce_scatter(__VA_ARGS__))
+#define MPI_Ireduce_scatter_block(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ireduce_scatter_block"), MPI_Ireduce_scatter_block(__VA_ARGS__))
+#define MPI_Ialltoall(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ialltoall"), MPI_Ialltoall(__VA_ARGS__))
+#define MPI_Ialltoallv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ialltoallv"), MPI_Ialltoallv(__VA_ARGS__))
+#define MPI_Ialltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ialltoallw"), MPI_Ialltoallw(__VA_ARGS__))
+#define MPI_Gather(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Gather"), MPI_Gather(__VA_ARGS__))
+#define MPI_Gatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Gatherv"), MPI_Gatherv(__VA_ARGS__))
+#define MPI_Allgather(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Allgather"), MPI_Allgather(__VA_ARGS__))
+#define MPI_Allgatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Allgatherv"), MPI_Allgatherv(__VA_ARGS__))
+#define MPI_Scatter(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Scatter"), MPI_Scatter(__VA_ARGS__))
+#define MPI_Scatterv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Scatterv"), MPI_Scatterv(__VA_ARGS__))
+#define MPI_Reduce(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Reduce"), MPI_Reduce(__VA_ARGS__))
+#define MPI_Allreduce(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Allreduce"), MPI_Allreduce(__VA_ARGS__))
+#define MPI_Scan(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Scan"), MPI_Scan(__VA_ARGS__))
+#define MPI_Exscan(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Exscan"), MPI_Exscan(__VA_ARGS__))
+#define MPI_Reduce_scatter(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Reduce_scatter"), MPI_Reduce_scatter(__VA_ARGS__))
+#define MPI_Reduce_scatter_block(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Reduce_scatter_block"), MPI_Reduce_scatter_block(__VA_ARGS__))
+#define MPI_Alltoall(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Alltoall"), MPI_Alltoall(__VA_ARGS__))
+#define MPI_Alltoallv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Alltoallv"), MPI_Alltoallv(__VA_ARGS__))
+#define MPI_Alltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Alltoallw"), MPI_Alltoallw(__VA_ARGS__))
+#define MPI_Reduce_local(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Reduce_local"), MPI_Reduce_local(__VA_ARGS__))
+#define MPI_Info_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_create"), MPI_Info_create(__VA_ARGS__))
+#define MPI_Info_set(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_set"), MPI_Info_set(__VA_ARGS__))
+#define MPI_Info_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_get"), MPI_Info_get(__VA_ARGS__))
+#define MPI_Info_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_free"), MPI_Info_free(__VA_ARGS__))
+#define MPI_Info_delete(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_delete"), MPI_Info_delete(__VA_ARGS__))
+#define MPI_Info_dup(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_dup"), MPI_Info_dup(__VA_ARGS__))
+#define MPI_Info_get_nkeys(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_get_nkeys"), MPI_Info_get_nkeys(__VA_ARGS__))
+#define MPI_Info_get_nthkey(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_get_nthkey"), MPI_Info_get_nthkey(__VA_ARGS__))
+#define MPI_Info_get_valuelen(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_get_valuelen"), MPI_Info_get_valuelen(__VA_ARGS__))
+#define MPI_Info_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_f2c"), MPI_Info_f2c(__VA_ARGS__))
+#define MPI_Info_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Info_c2f"), MPI_Info_c2f(__VA_ARGS__))
+#define MPI_Win_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_free"), MPI_Win_free(__VA_ARGS__))
+#define MPI_Win_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_create"), MPI_Win_create(__VA_ARGS__))
+#define MPI_Win_allocate(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_allocate"), MPI_Win_allocate(__VA_ARGS__))
+#define MPI_Win_allocate_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_allocate_shared"), MPI_Win_allocate_shared(__VA_ARGS__))
+#define MPI_Win_create_dynamic(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_create_dynamic"), MPI_Win_create_dynamic(__VA_ARGS__))
+#define MPI_Win_attach(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_attach"), MPI_Win_attach(__VA_ARGS__))
+#define MPI_Win_detach(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_detach"), MPI_Win_detach(__VA_ARGS__))
+#define MPI_Win_set_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_set_name"), MPI_Win_set_name(__VA_ARGS__))
+#define MPI_Win_get_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_get_name"), MPI_Win_get_name(__VA_ARGS__))
+#define MPI_Win_set_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_set_info"), MPI_Win_set_info(__VA_ARGS__))
+#define MPI_Win_get_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_get_info"), MPI_Win_get_info(__VA_ARGS__))
+#define MPI_Win_get_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_get_group"), MPI_Win_get_group(__VA_ARGS__))
+#define MPI_Win_fence(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_fence"), MPI_Win_fence(__VA_ARGS__))
+#define MPI_Win_get_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_get_attr"), MPI_Win_get_attr(__VA_ARGS__))
+#define MPI_Win_set_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_set_attr"), MPI_Win_set_attr(__VA_ARGS__))
+#define MPI_Win_delete_attr(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_delete_attr"), MPI_Win_delete_attr(__VA_ARGS__))
+#define MPI_Win_create_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_create_keyval"), MPI_Win_create_keyval(__VA_ARGS__))
+#define MPI_Win_free_keyval(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_free_keyval"), MPI_Win_free_keyval(__VA_ARGS__))
+#define MPI_Win_complete(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_complete"), MPI_Win_complete(__VA_ARGS__))
+#define MPI_Win_post(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_post"), MPI_Win_post(__VA_ARGS__))
+#define MPI_Win_start(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_start"), MPI_Win_start(__VA_ARGS__))
+#define MPI_Win_wait(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_wait"), MPI_Win_wait(__VA_ARGS__))
+#define MPI_Win_lock(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_lock"), MPI_Win_lock(__VA_ARGS__))
+#define MPI_Win_lock_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_lock_all"), MPI_Win_lock_all(__VA_ARGS__))
+#define MPI_Win_unlock(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_unlock"), MPI_Win_unlock(__VA_ARGS__))
+#define MPI_Win_unlock_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_unlock_all"), MPI_Win_unlock_all(__VA_ARGS__))
+#define MPI_Win_flush(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_flush"), MPI_Win_flush(__VA_ARGS__))
+#define MPI_Win_flush_local(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_flush_local"), MPI_Win_flush_local(__VA_ARGS__))
+#define MPI_Win_flush_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_flush_all"), MPI_Win_flush_all(__VA_ARGS__))
+#define MPI_Win_flush_local_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_flush_local_all"), MPI_Win_flush_local_all(__VA_ARGS__))
+#define MPI_Win_shared_query(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_shared_query"), MPI_Win_shared_query(__VA_ARGS__))
+#define MPI_Win_sync(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_sync"), MPI_Win_sync(__VA_ARGS__))
+#define MPI_Win_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_f2c"), MPI_Win_f2c(__VA_ARGS__))
+#define MPI_Win_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_c2f"), MPI_Win_c2f(__VA_ARGS__))
+#define MPI_Get(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get"), MPI_Get(__VA_ARGS__))
+#define MPI_Put(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Put"), MPI_Put(__VA_ARGS__))
+#define MPI_Accumulate(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Accumulate"), MPI_Accumulate(__VA_ARGS__))
+#define MPI_Get_accumulate(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get_accumulate"), MPI_Get_accumulate(__VA_ARGS__))
+#define MPI_Rget(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Rget"), MPI_Rget(__VA_ARGS__))
+#define MPI_Rput(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Rput"), MPI_Rput(__VA_ARGS__))
+#define MPI_Raccumulate(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Raccumulate"), MPI_Raccumulate(__VA_ARGS__))
+#define MPI_Rget_accumulate(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Rget_accumulate"), MPI_Rget_accumulate(__VA_ARGS__))
+#define MPI_Fetch_and_op(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Fetch_and_op"), MPI_Fetch_and_op(__VA_ARGS__))
+#define MPI_Compare_and_swap(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Compare_and_swap"), MPI_Compare_and_swap(__VA_ARGS__))
+#define MPI_Cart_coords(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cart_coords"), MPI_Cart_coords(__VA_ARGS__))
+#define MPI_Cart_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cart_create"), MPI_Cart_create(__VA_ARGS__))
+#define MPI_Cart_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cart_get"), MPI_Cart_get(__VA_ARGS__))
+#define MPI_Cart_rank(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cart_rank"), MPI_Cart_rank(__VA_ARGS__))
+#define MPI_Cart_shift(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cart_shift"), MPI_Cart_shift(__VA_ARGS__))
+#define MPI_Cart_sub(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cart_sub"), MPI_Cart_sub(__VA_ARGS__))
+#define MPI_Cartdim_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cartdim_get"), MPI_Cartdim_get(__VA_ARGS__))
+#define MPI_Dims_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Dims_create"), MPI_Dims_create(__VA_ARGS__))
+#define MPI_Request_get_status(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Request_get_status"), MPI_Request_get_status(__VA_ARGS__))
+#define MPI_Grequest_start(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Grequest_start"), MPI_Grequest_start(__VA_ARGS__))
+#define MPI_Grequest_complete(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Grequest_complete"), MPI_Grequest_complete(__VA_ARGS__))
+#define MPI_Status_set_cancelled(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Status_set_cancelled"), MPI_Status_set_cancelled(__VA_ARGS__))
+#define MPI_Status_set_elements(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Status_set_elements"), MPI_Status_set_elements(__VA_ARGS__))
+#define MPI_Status_set_elements_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Status_set_elements_x"), MPI_Status_set_elements_x(__VA_ARGS__))
+#define MPI_Type_create_subarray(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_subarray"), MPI_Type_create_subarray(__VA_ARGS__))
+#define MPI_File_open(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_open"), MPI_File_open(__VA_ARGS__))
+#define MPI_File_close(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_close"), MPI_File_close(__VA_ARGS__))
+#define MPI_File_delete(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_delete"), MPI_File_delete(__VA_ARGS__))
+#define MPI_File_get_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_size"), MPI_File_get_size(__VA_ARGS__))
+#define MPI_File_get_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_group"), MPI_File_get_group(__VA_ARGS__))
+#define MPI_File_get_amode(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_amode"), MPI_File_get_amode(__VA_ARGS__))
+#define MPI_File_set_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_set_info"), MPI_File_set_info(__VA_ARGS__))
+#define MPI_File_get_info(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_info"), MPI_File_get_info(__VA_ARGS__))
+#define MPI_File_read_at(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_at"), MPI_File_read_at(__VA_ARGS__))
+#define MPI_File_read_at_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_at_all"), MPI_File_read_at_all(__VA_ARGS__))
+#define MPI_File_write_at(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_at"), MPI_File_write_at(__VA_ARGS__))
+#define MPI_File_write_at_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_at_all"), MPI_File_write_at_all(__VA_ARGS__))
+#define MPI_File_read(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read"), MPI_File_read(__VA_ARGS__))
+#define MPI_File_read_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_all"), MPI_File_read_all(__VA_ARGS__))
+#define MPI_File_write(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write"), MPI_File_write(__VA_ARGS__))
+#define MPI_File_write_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_all"), MPI_File_write_all(__VA_ARGS__))
+#define MPI_File_seek(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_seek"), MPI_File_seek(__VA_ARGS__))
+#define MPI_File_get_position(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_position"), MPI_File_get_position(__VA_ARGS__))
+#define MPI_File_read_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_shared"), MPI_File_read_shared(__VA_ARGS__))
+#define MPI_File_write_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_shared"), MPI_File_write_shared(__VA_ARGS__))
+#define MPI_File_read_ordered(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_ordered"), MPI_File_read_ordered(__VA_ARGS__))
+#define MPI_File_write_ordered(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_ordered"), MPI_File_write_ordered(__VA_ARGS__))
+#define MPI_File_seek_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_seek_shared"), MPI_File_seek_shared(__VA_ARGS__))
+#define MPI_File_get_position_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_position_shared"), MPI_File_get_position_shared(__VA_ARGS__))
+#define MPI_File_sync(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_sync"), MPI_File_sync(__VA_ARGS__))
+#define MPI_File_set_view(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_set_view"), MPI_File_set_view(__VA_ARGS__))
+#define MPI_File_get_view(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_view"), MPI_File_get_view(__VA_ARGS__))
+#define MPI_Errhandler_set(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Errhandler_set"), MPI_Errhandler_set(__VA_ARGS__))
+#define MPI_Errhandler_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Errhandler_create"), MPI_Errhandler_create(__VA_ARGS__))
+#define MPI_Errhandler_free(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Errhandler_free"), MPI_Errhandler_free(__VA_ARGS__))
+#define MPI_Errhandler_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Errhandler_get"), MPI_Errhandler_get(__VA_ARGS__))
+#define MPI_Comm_set_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_set_errhandler"), MPI_Comm_set_errhandler(__VA_ARGS__))
+#define MPI_Comm_get_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_get_errhandler"), MPI_Comm_get_errhandler(__VA_ARGS__))
+#define MPI_Comm_create_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_create_errhandler"), MPI_Comm_create_errhandler(__VA_ARGS__))
+#define MPI_Comm_call_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_call_errhandler"), MPI_Comm_call_errhandler(__VA_ARGS__))
+#define MPI_Win_set_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_set_errhandler"), MPI_Win_set_errhandler(__VA_ARGS__))
+#define MPI_Win_get_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_get_errhandler"), MPI_Win_get_errhandler(__VA_ARGS__))
+#define MPI_Win_create_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_create_errhandler"), MPI_Win_create_errhandler(__VA_ARGS__))
+#define MPI_Win_call_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_call_errhandler"), MPI_Win_call_errhandler(__VA_ARGS__))
+#define MPI_Errhandler_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Errhandler_f2c"), MPI_Errhandler_f2c(__VA_ARGS__))
+#define MPI_Errhandler_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Errhandler_c2f"), MPI_Errhandler_c2f(__VA_ARGS__))
+#define MPI_Type_create_f90_integer(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_f90_integer"), MPI_Type_create_f90_integer(__VA_ARGS__))
+#define MPI_Type_create_f90_real(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_f90_real"), MPI_Type_create_f90_real(__VA_ARGS__))
+#define MPI_Type_create_f90_complex(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_f90_complex"), MPI_Type_create_f90_complex(__VA_ARGS__))
+#define MPI_Type_get_contents(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_get_contents"), MPI_Type_get_contents(__VA_ARGS__))
+#define MPI_Type_get_envelope(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_get_envelope"), MPI_Type_get_envelope(__VA_ARGS__))
+#define MPI_File_call_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_call_errhandler"), MPI_File_call_errhandler(__VA_ARGS__))
+#define MPI_File_create_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_create_errhandler"), MPI_File_create_errhandler(__VA_ARGS__))
+#define MPI_File_set_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_set_errhandler"), MPI_File_set_errhandler(__VA_ARGS__))
+#define MPI_File_get_errhandler(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_errhandler"), MPI_File_get_errhandler(__VA_ARGS__))
+#define MPI_Cart_map(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Cart_map"), MPI_Cart_map(__VA_ARGS__))
+#define MPI_Graph_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Graph_create"), MPI_Graph_create(__VA_ARGS__))
+#define MPI_Graph_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Graph_get"), MPI_Graph_get(__VA_ARGS__))
+#define MPI_Graph_map(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Graph_map"), MPI_Graph_map(__VA_ARGS__))
+#define MPI_Graph_neighbors(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Graph_neighbors"), MPI_Graph_neighbors(__VA_ARGS__))
+#define MPI_Graph_neighbors_count(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Graph_neighbors_count"), MPI_Graph_neighbors_count(__VA_ARGS__))
+#define MPI_Graphdims_get(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Graphdims_get"), MPI_Graphdims_get(__VA_ARGS__))
+#define MPI_Topo_test(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Topo_test"), MPI_Topo_test(__VA_ARGS__))
+#define MPI_Add_error_class(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Add_error_class"), MPI_Add_error_class(__VA_ARGS__))
+#define MPI_Add_error_code(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Add_error_code"), MPI_Add_error_code(__VA_ARGS__))
+#define MPI_Add_error_string(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Add_error_string"), MPI_Add_error_string(__VA_ARGS__))
+#define MPI_Comm_test_inter(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_test_inter"), MPI_Comm_test_inter(__VA_ARGS__))
+#define MPI_Intercomm_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Intercomm_create"), MPI_Intercomm_create(__VA_ARGS__))
+#define MPI_Intercomm_merge(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Intercomm_merge"), MPI_Intercomm_merge(__VA_ARGS__))
+#define MPI_Comm_remote_group(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_remote_group"), MPI_Comm_remote_group(__VA_ARGS__))
+#define MPI_Comm_remote_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_remote_size"), MPI_Comm_remote_size(__VA_ARGS__))
+#define MPI_Get_elements(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get_elements"), MPI_Get_elements(__VA_ARGS__))
+#define MPI_Get_elements_x(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Get_elements_x"), MPI_Get_elements_x(__VA_ARGS__))
+#define MPI_Pcontrol(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pcontrol"), MPI_Pcontrol(__VA_ARGS__))
+#define MPI_Type_create_darray(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_create_darray"), MPI_Type_create_darray(__VA_ARGS__))
+#define MPI_Pack_external_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pack_external_size"), MPI_Pack_external_size(__VA_ARGS__))
+#define MPI_Pack_external(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pack_external"), MPI_Pack_external(__VA_ARGS__))
+#define MPI_Unpack_external(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Unpack_external"), MPI_Unpack_external(__VA_ARGS__))
+#define MPI_Type_match_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Type_match_size"), MPI_Type_match_size(__VA_ARGS__))
+#define MPI_Comm_connect(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_connect"), MPI_Comm_connect(__VA_ARGS__))
+#define MPI_Unpublish_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Unpublish_name"), MPI_Unpublish_name(__VA_ARGS__))
+#define MPI_Publish_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Publish_name"), MPI_Publish_name(__VA_ARGS__))
+#define MPI_Lookup_name(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Lookup_name"), MPI_Lookup_name(__VA_ARGS__))
+#define MPI_Comm_idup(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_idup"), MPI_Comm_idup(__VA_ARGS__))
+#define MPI_Comm_join(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_join"), MPI_Comm_join(__VA_ARGS__))
+#define MPI_Open_port(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Open_port"), MPI_Open_port(__VA_ARGS__))
+#define MPI_Close_port(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Close_port"), MPI_Close_port(__VA_ARGS__))
+#define MPI_Comm_accept(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_accept"), MPI_Comm_accept(__VA_ARGS__))
+#define MPI_Comm_spawn(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_spawn"), MPI_Comm_spawn(__VA_ARGS__))
+#define MPI_Comm_spawn_multiple(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_spawn_multiple"), MPI_Comm_spawn_multiple(__VA_ARGS__))
+#define MPI_Comm_get_parent(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Comm_get_parent"), MPI_Comm_get_parent(__VA_ARGS__))
+#define MPI_Dist_graph_create(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Dist_graph_create"), MPI_Dist_graph_create(__VA_ARGS__))
+#define MPI_Dist_graph_create_adjacent(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Dist_graph_create_adjacent"), MPI_Dist_graph_create_adjacent(__VA_ARGS__))
+#define MPI_Dist_graph_neighbors(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Dist_graph_neighbors"), MPI_Dist_graph_neighbors(__VA_ARGS__))
+#define MPI_Dist_graph_neighbors_count(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Dist_graph_neighbors_count"), MPI_Dist_graph_neighbors_count(__VA_ARGS__))
+#define MPI_Win_test(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Win_test"), MPI_Win_test(__VA_ARGS__))
+#define MPI_File_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_c2f"), MPI_File_c2f(__VA_ARGS__))
+#define MPI_File_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_f2c"), MPI_File_f2c(__VA_ARGS__))
+#define MPI_Register_datarep(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Register_datarep"), MPI_Register_datarep(__VA_ARGS__))
+#define MPI_File_set_size(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_set_size"), MPI_File_set_size(__VA_ARGS__))
+#define MPI_File_preallocate(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_preallocate"), MPI_File_preallocate(__VA_ARGS__))
+#define MPI_File_iread_at(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iread_at"), MPI_File_iread_at(__VA_ARGS__))
+#define MPI_File_iwrite_at(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iwrite_at"), MPI_File_iwrite_at(__VA_ARGS__))
+#define MPI_File_iread_at_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iread_at_all"), MPI_File_iread_at_all(__VA_ARGS__))
+#define MPI_File_iwrite_at_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iwrite_at_all"), MPI_File_iwrite_at_all(__VA_ARGS__))
+#define MPI_File_iread(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iread"), MPI_File_iread(__VA_ARGS__))
+#define MPI_File_iwrite(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iwrite"), MPI_File_iwrite(__VA_ARGS__))
+#define MPI_File_iread_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iread_all"), MPI_File_iread_all(__VA_ARGS__))
+#define MPI_File_iwrite_all(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iwrite_all"), MPI_File_iwrite_all(__VA_ARGS__))
+#define MPI_File_get_byte_offset(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_byte_offset"), MPI_File_get_byte_offset(__VA_ARGS__))
+#define MPI_File_iread_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iread_shared"), MPI_File_iread_shared(__VA_ARGS__))
+#define MPI_File_iwrite_shared(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_iwrite_shared"), MPI_File_iwrite_shared(__VA_ARGS__))
+#define MPI_File_read_at_all_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_at_all_begin"), MPI_File_read_at_all_begin(__VA_ARGS__))
+#define MPI_File_read_at_all_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_at_all_end"), MPI_File_read_at_all_end(__VA_ARGS__))
+#define MPI_File_write_at_all_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_at_all_begin"), MPI_File_write_at_all_begin(__VA_ARGS__))
+#define MPI_File_write_at_all_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_at_all_end"), MPI_File_write_at_all_end(__VA_ARGS__))
+#define MPI_File_read_all_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_all_begin"), MPI_File_read_all_begin(__VA_ARGS__))
+#define MPI_File_read_all_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_all_end"), MPI_File_read_all_end(__VA_ARGS__))
+#define MPI_File_write_all_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_all_begin"), MPI_File_write_all_begin(__VA_ARGS__))
+#define MPI_File_write_all_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_all_end"), MPI_File_write_all_end(__VA_ARGS__))
+#define MPI_File_read_ordered_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_ordered_begin"), MPI_File_read_ordered_begin(__VA_ARGS__))
+#define MPI_File_read_ordered_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_read_ordered_end"), MPI_File_read_ordered_end(__VA_ARGS__))
+#define MPI_File_write_ordered_begin(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_ordered_begin"), MPI_File_write_ordered_begin(__VA_ARGS__))
+#define MPI_File_write_ordered_end(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_write_ordered_end"), MPI_File_write_ordered_end(__VA_ARGS__))
+#define MPI_File_get_type_extent(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_type_extent"), MPI_File_get_type_extent(__VA_ARGS__))
+#define MPI_File_set_atomicity(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_set_atomicity"), MPI_File_set_atomicity(__VA_ARGS__))
+#define MPI_File_get_atomicity(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_File_get_atomicity"), MPI_File_get_atomicity(__VA_ARGS__))
+#define MPI_Message_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Message_f2c"), MPI_Message_f2c(__VA_ARGS__))
+#define MPI_Message_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Message_c2f"), MPI_Message_c2f(__VA_ARGS__))
+#define MPI_Mrecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Mrecv"), MPI_Mrecv(__VA_ARGS__))
+#define MPI_Mprobe(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Mprobe"), MPI_Mprobe(__VA_ARGS__))
+#define MPI_Imrecv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Imrecv"), MPI_Imrecv(__VA_ARGS__))
+#define MPI_Improbe(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Improbe"), MPI_Improbe(__VA_ARGS__))
+#define MPI_Neighbor_allgather(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Neighbor_allgather"), MPI_Neighbor_allgather(__VA_ARGS__))
+#define MPI_Neighbor_allgatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Neighbor_allgatherv"), MPI_Neighbor_allgatherv(__VA_ARGS__))
+#define MPI_Neighbor_alltoall(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Neighbor_alltoall"), MPI_Neighbor_alltoall(__VA_ARGS__))
+#define MPI_Neighbor_alltoallv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Neighbor_alltoallv"), MPI_Neighbor_alltoallv(__VA_ARGS__))
+#define MPI_Neighbor_alltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Neighbor_alltoallw"), MPI_Neighbor_alltoallw(__VA_ARGS__))
+#define MPI_Ineighbor_allgather(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ineighbor_allgather"), MPI_Ineighbor_allgather(__VA_ARGS__))
+#define MPI_Ineighbor_allgatherv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ineighbor_allgatherv"), MPI_Ineighbor_allgatherv(__VA_ARGS__))
+#define MPI_Ineighbor_alltoall(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ineighbor_alltoall"), MPI_Ineighbor_alltoall(__VA_ARGS__))
+#define MPI_Ineighbor_alltoallv(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ineighbor_alltoallv"), MPI_Ineighbor_alltoallv(__VA_ARGS__))
+#define MPI_Ineighbor_alltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ineighbor_alltoallw"), MPI_Ineighbor_alltoallw(__VA_ARGS__))
+#define MPI_Status_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Status_f2c"), MPI_Status_f2c(__VA_ARGS__))
+#define MPI_Status_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Status_c2f"), MPI_Status_c2f(__VA_ARGS__))
+#define MPI_Parrived(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Parrived"), MPI_Parrived(__VA_ARGS__))
+#define MPI_Pready(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pready"), MPI_Pready(__VA_ARGS__))
+#define MPI_Pready_range(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pready_range"), MPI_Pready_range(__VA_ARGS__))
+#define MPI_Pready_list(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pready_list"), MPI_Pready_list(__VA_ARGS__))
+#define MPI_Precv_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Precv_init"), MPI_Precv_init(__VA_ARGS__))
+#define MPI_Psend_init(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Psend_init"), MPI_Psend_init(__VA_ARGS__))
index aaef86c..4e114f0 100644 (file)
 ! in tools/smpi/generate_smpi_defines.pl
 ! DO NOT EDIT MANUALLY. ALL CHANGES WILL BE OVERWRITTEN!
 
-#define mpi_init smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Init
-#define MPI_INIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Init
-#define mpi_finalize smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Finalize
-#define MPI_FINALIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Finalize
-#define mpi_finalized smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Finalized
-#define MPI_FINALIZED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Finalized
-#define mpi_init_thread smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Init_thread
-#define MPI_INIT_THREAD smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Init_thread
-#define mpi_initialized smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Initialized
-#define MPI_INITIALIZED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Initialized
-#define mpi_query_thread smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Query_thread
-#define MPI_QUERY_THREAD smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Query_thread
-#define mpi_is_thread_main smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Is_thread_main
-#define MPI_IS_THREAD_MAIN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Is_thread_main
-#define mpi_get_version smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_version
-#define MPI_GET_VERSION smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_version
-#define mpi_get_library_version smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_library_version
-#define MPI_GET_LIBRARY_VERSION smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_library_version
-#define mpi_get_processor_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_processor_name
-#define MPI_GET_PROCESSOR_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_processor_name
-#define mpi_abort smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Abort
-#define MPI_ABORT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Abort
-#define mpi_alloc_mem smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Alloc_mem
-#define MPI_ALLOC_MEM smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Alloc_mem
-#define mpi_free_mem smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Free_mem
-#define MPI_FREE_MEM smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Free_mem
-#define mpi_wtime smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Wtime
-#define MPI_WTIME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Wtime
-#define mpi_wtick smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Wtick
-#define MPI_WTICK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Wtick
-#define mpi_buffer_attach smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Buffer_attach
-#define MPI_BUFFER_ATTACH smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Buffer_attach
-#define mpi_buffer_detach smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Buffer_detach
-#define MPI_BUFFER_DETACH smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Buffer_detach
-#define mpi_address smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Address
-#define MPI_ADDRESS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Address
-#define mpi_get_address smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_address
-#define MPI_GET_ADDRESS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_address
-#define mpi_aint_diff smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Aint_diff
-#define MPI_AINT_DIFF smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Aint_diff
-#define mpi_aint_add smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Aint_add
-#define MPI_AINT_ADD smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Aint_add
-#define mpi_error_class smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Error_class
-#define MPI_ERROR_CLASS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Error_class
-#define mpi_error_string smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Error_string
-#define MPI_ERROR_STRING smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Error_string
-#define mpi_attr_delete smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Attr_delete
-#define MPI_ATTR_DELETE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Attr_delete
-#define mpi_attr_get smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Attr_get
-#define MPI_ATTR_GET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Attr_get
-#define mpi_attr_put smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Attr_put
-#define MPI_ATTR_PUT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Attr_put
-#define mpi_keyval_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Keyval_create
-#define MPI_KEYVAL_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Keyval_create
-#define mpi_keyval_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Keyval_free
-#define MPI_KEYVAL_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Keyval_free
-#define mpi_type_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_free
-#define MPI_TYPE_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_free
-#define mpi_type_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_size
-#define MPI_TYPE_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_size
-#define mpi_type_size_x smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_size_x
-#define MPI_TYPE_SIZE_X smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_size_x
-#define mpi_type_get_extent smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_extent
-#define MPI_TYPE_GET_EXTENT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_extent
-#define mpi_type_get_extent_x smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_extent_x
-#define MPI_TYPE_GET_EXTENT_X smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_extent_x
-#define mpi_type_get_true_extent smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_true_extent
-#define MPI_TYPE_GET_TRUE_EXTENT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_true_extent
-#define mpi_type_get_true_extent_x smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_true_extent_x
-#define MPI_TYPE_GET_TRUE_EXTENT_X smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_true_extent_x
-#define mpi_type_extent smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_extent
-#define MPI_TYPE_EXTENT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_extent
-#define mpi_type_lb smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_lb
-#define MPI_TYPE_LB smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_lb
-#define mpi_type_ub smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_ub
-#define MPI_TYPE_UB smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_ub
-#define mpi_type_commit smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_commit
-#define MPI_TYPE_COMMIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_commit
-#define mpi_type_hindexed smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_hindexed
-#define MPI_TYPE_HINDEXED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_hindexed
-#define mpi_type_create_hindexed smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_hindexed
-#define MPI_TYPE_CREATE_HINDEXED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_hindexed
-#define mpi_type_create_hindexed_block smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_hindexed_block
-#define MPI_TYPE_CREATE_HINDEXED_BLOCK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_hindexed_block
-#define mpi_type_hvector smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_hvector
-#define MPI_TYPE_HVECTOR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_hvector
-#define mpi_type_create_hvector smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_hvector
-#define MPI_TYPE_CREATE_HVECTOR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_hvector
-#define mpi_type_indexed smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_indexed
-#define MPI_TYPE_INDEXED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_indexed
-#define mpi_type_create_indexed smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_indexed
-#define MPI_TYPE_CREATE_INDEXED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_indexed
-#define mpi_type_create_indexed_block smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_indexed_block
-#define MPI_TYPE_CREATE_INDEXED_BLOCK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_indexed_block
-#define mpi_type_struct smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_struct
-#define MPI_TYPE_STRUCT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_struct
-#define mpi_type_create_struct smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_struct
-#define MPI_TYPE_CREATE_STRUCT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_struct
-#define mpi_type_vector smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_vector
-#define MPI_TYPE_VECTOR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_vector
-#define mpi_type_contiguous smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_contiguous
-#define MPI_TYPE_CONTIGUOUS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_contiguous
-#define mpi_type_create_resized smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_resized
-#define MPI_TYPE_CREATE_RESIZED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_resized
-#define mpi_type_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_f2c
-#define MPI_TYPE_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_f2c
-#define mpi_type_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_c2f
-#define MPI_TYPE_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_c2f
-#define mpi_get_count smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_count
-#define MPI_GET_COUNT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_count
-#define mpi_type_get_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_attr
-#define MPI_TYPE_GET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_attr
-#define mpi_type_set_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_set_attr
-#define MPI_TYPE_SET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_set_attr
-#define mpi_type_delete_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_delete_attr
-#define MPI_TYPE_DELETE_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_delete_attr
-#define mpi_type_create_keyval smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_keyval
-#define MPI_TYPE_CREATE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_keyval
-#define mpi_type_free_keyval smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_free_keyval
-#define MPI_TYPE_FREE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_free_keyval
-#define mpi_type_dup smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_dup
-#define MPI_TYPE_DUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_dup
-#define mpi_type_set_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_set_name
-#define MPI_TYPE_SET_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_set_name
-#define mpi_type_get_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_name
-#define MPI_TYPE_GET_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_name
-#define mpi_pack smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pack
-#define MPI_PACK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pack
-#define mpi_pack_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pack_size
-#define MPI_PACK_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pack_size
-#define mpi_unpack smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Unpack
-#define MPI_UNPACK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Unpack
-#define mpi_op_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_create
-#define MPI_OP_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_create
-#define mpi_op_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_free
-#define MPI_OP_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_free
-#define mpi_op_commutative smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_commutative
-#define MPI_OP_COMMUTATIVE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_commutative
-#define mpi_op_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_f2c
-#define MPI_OP_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_f2c
-#define mpi_op_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_c2f
-#define MPI_OP_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Op_c2f
-#define mpi_group_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_free
-#define MPI_GROUP_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_free
-#define mpi_group_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_size
-#define MPI_GROUP_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_size
-#define mpi_group_rank smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_rank
-#define MPI_GROUP_RANK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_rank
-#define mpi_group_translate_ranks smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_translate_ranks
-#define MPI_GROUP_TRANSLATE_RANKS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_translate_ranks
-#define mpi_group_compare smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_compare
-#define MPI_GROUP_COMPARE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_compare
-#define mpi_group_union smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_union
-#define MPI_GROUP_UNION smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_union
-#define mpi_group_intersection smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_intersection
-#define MPI_GROUP_INTERSECTION smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_intersection
-#define mpi_group_difference smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_difference
-#define MPI_GROUP_DIFFERENCE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_difference
-#define mpi_group_incl smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_incl
-#define MPI_GROUP_INCL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_incl
-#define mpi_group_excl smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_excl
-#define MPI_GROUP_EXCL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_excl
-#define mpi_group_range_incl smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_range_incl
-#define MPI_GROUP_RANGE_INCL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_range_incl
-#define mpi_group_range_excl smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_range_excl
-#define MPI_GROUP_RANGE_EXCL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_range_excl
-#define mpi_group_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_f2c
-#define MPI_GROUP_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_f2c
-#define mpi_group_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_c2f
-#define MPI_GROUP_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Group_c2f
-#define mpi_comm_rank smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_rank
-#define MPI_COMM_RANK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_rank
-#define mpi_comm_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_size
-#define MPI_COMM_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_size
-#define mpi_comm_get_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_name
-#define MPI_COMM_GET_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_name
-#define mpi_comm_set_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_set_name
-#define MPI_COMM_SET_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_set_name
-#define mpi_comm_dup smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_dup
-#define MPI_COMM_DUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_dup
-#define mpi_comm_dup_with_info smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_dup_with_info
-#define MPI_COMM_DUP_WITH_INFO smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_dup_with_info
-#define mpi_comm_get_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_attr
-#define MPI_COMM_GET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_attr
-#define mpi_comm_set_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_set_attr
-#define MPI_COMM_SET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_set_attr
-#define mpi_comm_delete_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_delete_attr
-#define MPI_COMM_DELETE_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_delete_attr
-#define mpi_comm_create_keyval smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_create_keyval
-#define MPI_COMM_CREATE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_create_keyval
-#define mpi_comm_free_keyval smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_free_keyval
-#define MPI_COMM_FREE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_free_keyval
-#define mpi_comm_group smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_group
-#define MPI_COMM_GROUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_group
-#define mpi_comm_compare smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_compare
-#define MPI_COMM_COMPARE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_compare
-#define mpi_comm_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_create
-#define MPI_COMM_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_create
-#define mpi_comm_create_group smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_create_group
-#define MPI_COMM_CREATE_GROUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_create_group
-#define mpi_comm_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_free
-#define MPI_COMM_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_free
-#define mpi_comm_disconnect smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_disconnect
-#define MPI_COMM_DISCONNECT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_disconnect
-#define mpi_comm_split smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_split
-#define MPI_COMM_SPLIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_split
-#define mpi_comm_set_info smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_set_info
-#define MPI_COMM_SET_INFO smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_set_info
-#define mpi_comm_get_info smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_info
-#define MPI_COMM_GET_INFO smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_info
-#define mpi_comm_split_type smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_split_type
-#define MPI_COMM_SPLIT_TYPE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_split_type
-#define mpi_comm_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_f2c
-#define MPI_COMM_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_f2c
-#define mpi_comm_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_c2f
-#define MPI_COMM_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_c2f
-#define mpi_start smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Start
-#define MPI_START smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Start
-#define mpi_startall smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Startall
-#define MPI_STARTALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Startall
-#define mpi_request_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Request_free
-#define MPI_REQUEST_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Request_free
-#define mpi_recv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Recv
-#define MPI_RECV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Recv
-#define mpi_recv_init smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Recv_init
-#define MPI_RECV_INIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Recv_init
-#define mpi_irecv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Irecv
-#define MPI_IRECV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Irecv
-#define mpi_send smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Send
-#define MPI_SEND smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Send
-#define mpi_send_init smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Send_init
-#define MPI_SEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Send_init
-#define mpi_isend smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Isend
-#define MPI_ISEND smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Isend
-#define mpi_ssend smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ssend
-#define MPI_SSEND smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ssend
-#define mpi_ssend_init smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ssend_init
-#define MPI_SSEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ssend_init
-#define mpi_issend smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Issend
-#define MPI_ISSEND smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Issend
-#define mpi_bsend smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Bsend
-#define MPI_BSEND smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Bsend
-#define mpi_bsend_init smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Bsend_init
-#define MPI_BSEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Bsend_init
-#define mpi_ibsend smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ibsend
-#define MPI_IBSEND smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ibsend
-#define mpi_rsend smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rsend
-#define MPI_RSEND smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rsend
-#define mpi_rsend_init smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rsend_init
-#define MPI_RSEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rsend_init
-#define mpi_irsend smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Irsend
-#define MPI_IRSEND smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Irsend
-#define mpi_sendrecv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Sendrecv
-#define MPI_SENDRECV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Sendrecv
-#define mpi_sendrecv_replace smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Sendrecv_replace
-#define MPI_SENDRECV_REPLACE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Sendrecv_replace
-#define mpi_test smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Test
-#define MPI_TEST smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Test
-#define mpi_testany smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Testany
-#define MPI_TESTANY smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Testany
-#define mpi_testall smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Testall
-#define MPI_TESTALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Testall
-#define mpi_testsome smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Testsome
-#define MPI_TESTSOME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Testsome
-#define mpi_test_cancelled smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Test_cancelled
-#define MPI_TEST_CANCELLED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Test_cancelled
-#define mpi_wait smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Wait
-#define MPI_WAIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Wait
-#define mpi_waitany smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Waitany
-#define MPI_WAITANY smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Waitany
-#define mpi_waitall smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Waitall
-#define MPI_WAITALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Waitall
-#define mpi_waitsome smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Waitsome
-#define MPI_WAITSOME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Waitsome
-#define mpi_iprobe smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iprobe
-#define MPI_IPROBE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iprobe
-#define mpi_probe smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Probe
-#define MPI_PROBE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Probe
-#define mpi_request_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Request_f2c
-#define MPI_REQUEST_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Request_f2c
-#define mpi_request_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Request_c2f
-#define MPI_REQUEST_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Request_c2f
-#define mpi_cancel smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cancel
-#define MPI_CANCEL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cancel
-#define mpi_bcast smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Bcast
-#define MPI_BCAST smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Bcast
-#define mpi_barrier smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Barrier
-#define MPI_BARRIER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Barrier
-#define mpi_ibarrier smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ibarrier
-#define MPI_IBARRIER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ibarrier
-#define mpi_ibcast smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ibcast
-#define MPI_IBCAST smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ibcast
-#define mpi_igather smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Igather
-#define MPI_IGATHER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Igather
-#define mpi_igatherv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Igatherv
-#define MPI_IGATHERV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Igatherv
-#define mpi_iallgather smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iallgather
-#define MPI_IALLGATHER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iallgather
-#define mpi_iallgatherv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iallgatherv
-#define MPI_IALLGATHERV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iallgatherv
-#define mpi_iscatter smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iscatter
-#define MPI_ISCATTER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iscatter
-#define mpi_iscatterv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iscatterv
-#define MPI_ISCATTERV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iscatterv
-#define mpi_ireduce smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ireduce
-#define MPI_IREDUCE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ireduce
-#define mpi_iallreduce smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iallreduce
-#define MPI_IALLREDUCE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iallreduce
-#define mpi_iscan smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iscan
-#define MPI_ISCAN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iscan
-#define mpi_iexscan smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iexscan
-#define MPI_IEXSCAN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Iexscan
-#define mpi_ireduce_scatter smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ireduce_scatter
-#define MPI_IREDUCE_SCATTER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ireduce_scatter
-#define mpi_ireduce_scatter_block smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ireduce_scatter_block
-#define MPI_IREDUCE_SCATTER_BLOCK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ireduce_scatter_block
-#define mpi_ialltoall smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ialltoall
-#define MPI_IALLTOALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ialltoall
-#define mpi_ialltoallv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ialltoallv
-#define MPI_IALLTOALLV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ialltoallv
-#define mpi_ialltoallw smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ialltoallw
-#define MPI_IALLTOALLW smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ialltoallw
-#define mpi_gather smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Gather
-#define MPI_GATHER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Gather
-#define mpi_gatherv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Gatherv
-#define MPI_GATHERV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Gatherv
-#define mpi_allgather smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Allgather
-#define MPI_ALLGATHER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Allgather
-#define mpi_allgatherv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Allgatherv
-#define MPI_ALLGATHERV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Allgatherv
-#define mpi_scatter smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Scatter
-#define MPI_SCATTER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Scatter
-#define mpi_scatterv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Scatterv
-#define MPI_SCATTERV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Scatterv
-#define mpi_reduce smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Reduce
-#define MPI_REDUCE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Reduce
-#define mpi_allreduce smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Allreduce
-#define MPI_ALLREDUCE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Allreduce
-#define mpi_scan smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Scan
-#define MPI_SCAN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Scan
-#define mpi_exscan smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Exscan
-#define MPI_EXSCAN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Exscan
-#define mpi_reduce_scatter smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Reduce_scatter
-#define MPI_REDUCE_SCATTER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Reduce_scatter
-#define mpi_reduce_scatter_block smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Reduce_scatter_block
-#define MPI_REDUCE_SCATTER_BLOCK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Reduce_scatter_block
-#define mpi_alltoall smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Alltoall
-#define MPI_ALLTOALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Alltoall
-#define mpi_alltoallv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Alltoallv
-#define MPI_ALLTOALLV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Alltoallv
-#define mpi_alltoallw smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Alltoallw
-#define MPI_ALLTOALLW smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Alltoallw
-#define mpi_reduce_local smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Reduce_local
-#define MPI_REDUCE_LOCAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Reduce_local
-#define mpi_info_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_create
-#define MPI_INFO_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_create
-#define mpi_info_set smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_set
-#define MPI_INFO_SET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_set
-#define mpi_info_get smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_get
-#define MPI_INFO_GET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_get
-#define mpi_info_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_free
-#define MPI_INFO_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_free
-#define mpi_info_delete smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_delete
-#define MPI_INFO_DELETE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_delete
-#define mpi_info_dup smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_dup
-#define MPI_INFO_DUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_dup
-#define mpi_info_get_nkeys smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_get_nkeys
-#define MPI_INFO_GET_NKEYS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_get_nkeys
-#define mpi_info_get_nthkey smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_get_nthkey
-#define MPI_INFO_GET_NTHKEY smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_get_nthkey
-#define mpi_info_get_valuelen smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_get_valuelen
-#define MPI_INFO_GET_VALUELEN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_get_valuelen
-#define mpi_info_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_f2c
-#define MPI_INFO_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_f2c
-#define mpi_info_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_c2f
-#define MPI_INFO_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Info_c2f
-#define mpi_win_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_free
-#define MPI_WIN_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_free
-#define mpi_win_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_create
-#define MPI_WIN_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_create
-#define mpi_win_allocate smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_allocate
-#define MPI_WIN_ALLOCATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_allocate
-#define mpi_win_allocate_shared smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_allocate_shared
-#define MPI_WIN_ALLOCATE_SHARED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_allocate_shared
-#define mpi_win_create_dynamic smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_create_dynamic
-#define MPI_WIN_CREATE_DYNAMIC smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_create_dynamic
-#define mpi_win_attach smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_attach
-#define MPI_WIN_ATTACH smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_attach
-#define mpi_win_detach smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_detach
-#define MPI_WIN_DETACH smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_detach
-#define mpi_win_set_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_set_name
-#define MPI_WIN_SET_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_set_name
-#define mpi_win_get_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_name
-#define MPI_WIN_GET_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_name
-#define mpi_win_set_info smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_set_info
-#define MPI_WIN_SET_INFO smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_set_info
-#define mpi_win_get_info smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_info
-#define MPI_WIN_GET_INFO smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_info
-#define mpi_win_get_group smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_group
-#define MPI_WIN_GET_GROUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_group
-#define mpi_win_fence smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_fence
-#define MPI_WIN_FENCE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_fence
-#define mpi_win_get_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_attr
-#define MPI_WIN_GET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_attr
-#define mpi_win_set_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_set_attr
-#define MPI_WIN_SET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_set_attr
-#define mpi_win_delete_attr smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_delete_attr
-#define MPI_WIN_DELETE_ATTR smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_delete_attr
-#define mpi_win_create_keyval smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_create_keyval
-#define MPI_WIN_CREATE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_create_keyval
-#define mpi_win_free_keyval smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_free_keyval
-#define MPI_WIN_FREE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_free_keyval
-#define mpi_win_complete smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_complete
-#define MPI_WIN_COMPLETE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_complete
-#define mpi_win_post smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_post
-#define MPI_WIN_POST smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_post
-#define mpi_win_start smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_start
-#define MPI_WIN_START smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_start
-#define mpi_win_wait smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_wait
-#define MPI_WIN_WAIT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_wait
-#define mpi_win_lock smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_lock
-#define MPI_WIN_LOCK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_lock
-#define mpi_win_lock_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_lock_all
-#define MPI_WIN_LOCK_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_lock_all
-#define mpi_win_unlock smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_unlock
-#define MPI_WIN_UNLOCK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_unlock
-#define mpi_win_unlock_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_unlock_all
-#define MPI_WIN_UNLOCK_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_unlock_all
-#define mpi_win_flush smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_flush
-#define MPI_WIN_FLUSH smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_flush
-#define mpi_win_flush_local smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_flush_local
-#define MPI_WIN_FLUSH_LOCAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_flush_local
-#define mpi_win_flush_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_flush_all
-#define MPI_WIN_FLUSH_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_flush_all
-#define mpi_win_flush_local_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_flush_local_all
-#define MPI_WIN_FLUSH_LOCAL_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_flush_local_all
-#define mpi_win_shared_query smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_shared_query
-#define MPI_WIN_SHARED_QUERY smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_shared_query
-#define mpi_win_sync smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_sync
-#define MPI_WIN_SYNC smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_sync
-#define mpi_win_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_f2c
-#define MPI_WIN_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_f2c
-#define mpi_win_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_c2f
-#define MPI_WIN_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_c2f
-#define mpi_get smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get
-#define MPI_GET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get
-#define mpi_put smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Put
-#define MPI_PUT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Put
-#define mpi_accumulate smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Accumulate
-#define MPI_ACCUMULATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Accumulate
-#define mpi_get_accumulate smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_accumulate
-#define MPI_GET_ACCUMULATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_accumulate
-#define mpi_rget smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rget
-#define MPI_RGET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rget
-#define mpi_rput smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rput
-#define MPI_RPUT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rput
-#define mpi_raccumulate smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Raccumulate
-#define MPI_RACCUMULATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Raccumulate
-#define mpi_rget_accumulate smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rget_accumulate
-#define MPI_RGET_ACCUMULATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Rget_accumulate
-#define mpi_fetch_and_op smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Fetch_and_op
-#define MPI_FETCH_AND_OP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Fetch_and_op
-#define mpi_compare_and_swap smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Compare_and_swap
-#define MPI_COMPARE_AND_SWAP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Compare_and_swap
-#define mpi_cart_coords smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_coords
-#define MPI_CART_COORDS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_coords
-#define mpi_cart_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_create
-#define MPI_CART_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_create
-#define mpi_cart_get smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_get
-#define MPI_CART_GET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_get
-#define mpi_cart_rank smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_rank
-#define MPI_CART_RANK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_rank
-#define mpi_cart_shift smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_shift
-#define MPI_CART_SHIFT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_shift
-#define mpi_cart_sub smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_sub
-#define MPI_CART_SUB smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_sub
-#define mpi_cartdim_get smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cartdim_get
-#define MPI_CARTDIM_GET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cartdim_get
-#define mpi_dims_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dims_create
-#define MPI_DIMS_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dims_create
-#define mpi_request_get_status smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Request_get_status
-#define MPI_REQUEST_GET_STATUS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Request_get_status
-#define mpi_grequest_start smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Grequest_start
-#define MPI_GREQUEST_START smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Grequest_start
-#define mpi_grequest_complete smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Grequest_complete
-#define MPI_GREQUEST_COMPLETE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Grequest_complete
-#define mpi_status_set_cancelled smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_set_cancelled
-#define MPI_STATUS_SET_CANCELLED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_set_cancelled
-#define mpi_status_set_elements smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_set_elements
-#define MPI_STATUS_SET_ELEMENTS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_set_elements
-#define mpi_status_set_elements_x smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_set_elements_x
-#define MPI_STATUS_SET_ELEMENTS_X smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_set_elements_x
-#define mpi_type_create_subarray smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_subarray
-#define MPI_TYPE_CREATE_SUBARRAY smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_subarray
-#define mpi_file_open smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_open
-#define MPI_FILE_OPEN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_open
-#define mpi_file_close smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_close
-#define MPI_FILE_CLOSE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_close
-#define mpi_file_delete smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_delete
-#define MPI_FILE_DELETE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_delete
-#define mpi_file_get_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_size
-#define MPI_FILE_GET_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_size
-#define mpi_file_get_group smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_group
-#define MPI_FILE_GET_GROUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_group
-#define mpi_file_get_amode smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_amode
-#define MPI_FILE_GET_AMODE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_amode
-#define mpi_file_set_info smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_info
-#define MPI_FILE_SET_INFO smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_info
-#define mpi_file_get_info smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_info
-#define MPI_FILE_GET_INFO smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_info
-#define mpi_file_read_at smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_at
-#define MPI_FILE_READ_AT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_at
-#define mpi_file_read_at_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_at_all
-#define MPI_FILE_READ_AT_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_at_all
-#define mpi_file_write_at smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_at
-#define MPI_FILE_WRITE_AT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_at
-#define mpi_file_write_at_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_at_all
-#define MPI_FILE_WRITE_AT_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_at_all
-#define mpi_file_read smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read
-#define MPI_FILE_READ smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read
-#define mpi_file_read_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_all
-#define MPI_FILE_READ_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_all
-#define mpi_file_write smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write
-#define MPI_FILE_WRITE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write
-#define mpi_file_write_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_all
-#define MPI_FILE_WRITE_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_all
-#define mpi_file_seek smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_seek
-#define MPI_FILE_SEEK smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_seek
-#define mpi_file_get_position smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_position
-#define MPI_FILE_GET_POSITION smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_position
-#define mpi_file_read_shared smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_shared
-#define MPI_FILE_READ_SHARED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_shared
-#define mpi_file_write_shared smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_shared
-#define MPI_FILE_WRITE_SHARED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_shared
-#define mpi_file_read_ordered smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_ordered
-#define MPI_FILE_READ_ORDERED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_ordered
-#define mpi_file_write_ordered smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_ordered
-#define MPI_FILE_WRITE_ORDERED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_ordered
-#define mpi_file_seek_shared smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_seek_shared
-#define MPI_FILE_SEEK_SHARED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_seek_shared
-#define mpi_file_get_position_shared smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_position_shared
-#define MPI_FILE_GET_POSITION_SHARED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_position_shared
-#define mpi_file_sync smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_sync
-#define MPI_FILE_SYNC smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_sync
-#define mpi_file_set_view smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_view
-#define MPI_FILE_SET_VIEW smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_view
-#define mpi_file_get_view smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_view
-#define MPI_FILE_GET_VIEW smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_view
-#define mpi_errhandler_set smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_set
-#define MPI_ERRHANDLER_SET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_set
-#define mpi_errhandler_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_create
-#define MPI_ERRHANDLER_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_create
-#define mpi_errhandler_free smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_free
-#define MPI_ERRHANDLER_FREE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_free
-#define mpi_errhandler_get smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_get
-#define MPI_ERRHANDLER_GET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_get
-#define mpi_comm_set_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_set_errhandler
-#define MPI_COMM_SET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_set_errhandler
-#define mpi_comm_get_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_errhandler
-#define MPI_COMM_GET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_errhandler
-#define mpi_comm_create_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_create_errhandler
-#define MPI_COMM_CREATE_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_create_errhandler
-#define mpi_comm_call_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_call_errhandler
-#define MPI_COMM_CALL_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_call_errhandler
-#define mpi_win_set_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_set_errhandler
-#define MPI_WIN_SET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_set_errhandler
-#define mpi_win_get_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_errhandler
-#define MPI_WIN_GET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_get_errhandler
-#define mpi_win_create_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_create_errhandler
-#define MPI_WIN_CREATE_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_create_errhandler
-#define mpi_win_call_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_call_errhandler
-#define MPI_WIN_CALL_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_call_errhandler
-#define mpi_errhandler_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_f2c
-#define MPI_ERRHANDLER_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_f2c
-#define mpi_errhandler_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_c2f
-#define MPI_ERRHANDLER_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Errhandler_c2f
-#define mpi_type_create_f90_integer smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_f90_integer
-#define MPI_TYPE_CREATE_F90_INTEGER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_f90_integer
-#define mpi_type_create_f90_real smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_f90_real
-#define MPI_TYPE_CREATE_F90_REAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_f90_real
-#define mpi_type_create_f90_complex smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_f90_complex
-#define MPI_TYPE_CREATE_F90_COMPLEX smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_f90_complex
-#define mpi_type_get_contents smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_contents
-#define MPI_TYPE_GET_CONTENTS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_contents
-#define mpi_type_get_envelope smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_envelope
-#define MPI_TYPE_GET_ENVELOPE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_get_envelope
-#define mpi_file_call_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_call_errhandler
-#define MPI_FILE_CALL_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_call_errhandler
-#define mpi_file_create_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_create_errhandler
-#define MPI_FILE_CREATE_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_create_errhandler
-#define mpi_file_set_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_errhandler
-#define MPI_FILE_SET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_errhandler
-#define mpi_file_get_errhandler smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_errhandler
-#define MPI_FILE_GET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_errhandler
-#define mpi_cart_map smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_map
-#define MPI_CART_MAP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Cart_map
-#define mpi_graph_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_create
-#define MPI_GRAPH_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_create
-#define mpi_graph_get smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_get
-#define MPI_GRAPH_GET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_get
-#define mpi_graph_map smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_map
-#define MPI_GRAPH_MAP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_map
-#define mpi_graph_neighbors smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_neighbors
-#define MPI_GRAPH_NEIGHBORS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_neighbors
-#define mpi_graph_neighbors_count smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_neighbors_count
-#define MPI_GRAPH_NEIGHBORS_COUNT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graph_neighbors_count
-#define mpi_graphdims_get smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graphdims_get
-#define MPI_GRAPHDIMS_GET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Graphdims_get
-#define mpi_topo_test smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Topo_test
-#define MPI_TOPO_TEST smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Topo_test
-#define mpi_add_error_class smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Add_error_class
-#define MPI_ADD_ERROR_CLASS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Add_error_class
-#define mpi_add_error_code smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Add_error_code
-#define MPI_ADD_ERROR_CODE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Add_error_code
-#define mpi_add_error_string smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Add_error_string
-#define MPI_ADD_ERROR_STRING smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Add_error_string
-#define mpi_comm_test_inter smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_test_inter
-#define MPI_COMM_TEST_INTER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_test_inter
-#define mpi_intercomm_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Intercomm_create
-#define MPI_INTERCOMM_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Intercomm_create
-#define mpi_intercomm_merge smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Intercomm_merge
-#define MPI_INTERCOMM_MERGE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Intercomm_merge
-#define mpi_comm_remote_group smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_remote_group
-#define MPI_COMM_REMOTE_GROUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_remote_group
-#define mpi_comm_remote_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_remote_size
-#define MPI_COMM_REMOTE_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_remote_size
-#define mpi_get_elements smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_elements
-#define MPI_GET_ELEMENTS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_elements
-#define mpi_get_elements_x smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_elements_x
-#define MPI_GET_ELEMENTS_X smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Get_elements_x
-#define mpi_pcontrol smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pcontrol
-#define MPI_PCONTROL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pcontrol
-#define mpi_type_create_darray smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_darray
-#define MPI_TYPE_CREATE_DARRAY smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_create_darray
-#define mpi_pack_external_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pack_external_size
-#define MPI_PACK_EXTERNAL_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pack_external_size
-#define mpi_pack_external smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pack_external
-#define MPI_PACK_EXTERNAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Pack_external
-#define mpi_unpack_external smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Unpack_external
-#define MPI_UNPACK_EXTERNAL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Unpack_external
-#define mpi_type_match_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_match_size
-#define MPI_TYPE_MATCH_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Type_match_size
-#define mpi_comm_connect smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_connect
-#define MPI_COMM_CONNECT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_connect
-#define mpi_unpublish_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Unpublish_name
-#define MPI_UNPUBLISH_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Unpublish_name
-#define mpi_publish_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Publish_name
-#define MPI_PUBLISH_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Publish_name
-#define mpi_lookup_name smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Lookup_name
-#define MPI_LOOKUP_NAME smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Lookup_name
-#define mpi_comm_idup smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_idup
-#define MPI_COMM_IDUP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_idup
-#define mpi_comm_join smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_join
-#define MPI_COMM_JOIN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_join
-#define mpi_open_port smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Open_port
-#define MPI_OPEN_PORT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Open_port
-#define mpi_close_port smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Close_port
-#define MPI_CLOSE_PORT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Close_port
-#define mpi_comm_accept smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_accept
-#define MPI_COMM_ACCEPT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_accept
-#define mpi_comm_spawn smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_spawn
-#define MPI_COMM_SPAWN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_spawn
-#define mpi_comm_spawn_multiple smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_spawn_multiple
-#define MPI_COMM_SPAWN_MULTIPLE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_spawn_multiple
-#define mpi_comm_get_parent smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_parent
-#define MPI_COMM_GET_PARENT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Comm_get_parent
-#define mpi_dist_graph_create smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dist_graph_create
-#define MPI_DIST_GRAPH_CREATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dist_graph_create
-#define mpi_dist_graph_create_adjacent smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dist_graph_create_adjacent
-#define MPI_DIST_GRAPH_CREATE_ADJACENT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dist_graph_create_adjacent
-#define mpi_dist_graph_neighbors smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dist_graph_neighbors
-#define MPI_DIST_GRAPH_NEIGHBORS smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dist_graph_neighbors
-#define mpi_dist_graph_neighbors_count smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dist_graph_neighbors_count
-#define MPI_DIST_GRAPH_NEIGHBORS_COUNT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Dist_graph_neighbors_count
-#define mpi_win_test smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_test
-#define MPI_WIN_TEST smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Win_test
-#define mpi_file_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_c2f
-#define MPI_FILE_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_c2f
-#define mpi_file_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_f2c
-#define MPI_FILE_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_f2c
-#define mpi_register_datarep smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Register_datarep
-#define MPI_REGISTER_DATAREP smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Register_datarep
-#define mpi_file_set_size smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_size
-#define MPI_FILE_SET_SIZE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_size
-#define mpi_file_preallocate smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_preallocate
-#define MPI_FILE_PREALLOCATE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_preallocate
-#define mpi_file_iread_at smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread_at
-#define MPI_FILE_IREAD_AT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread_at
-#define mpi_file_iwrite_at smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite_at
-#define MPI_FILE_IWRITE_AT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite_at
-#define mpi_file_iread_at_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread_at_all
-#define MPI_FILE_IREAD_AT_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread_at_all
-#define mpi_file_iwrite_at_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite_at_all
-#define MPI_FILE_IWRITE_AT_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite_at_all
-#define mpi_file_iread smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread
-#define MPI_FILE_IREAD smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread
-#define mpi_file_iwrite smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite
-#define MPI_FILE_IWRITE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite
-#define mpi_file_iread_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread_all
-#define MPI_FILE_IREAD_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread_all
-#define mpi_file_iwrite_all smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite_all
-#define MPI_FILE_IWRITE_ALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite_all
-#define mpi_file_get_byte_offset smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_byte_offset
-#define MPI_FILE_GET_BYTE_OFFSET smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_byte_offset
-#define mpi_file_iread_shared smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread_shared
-#define MPI_FILE_IREAD_SHARED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iread_shared
-#define mpi_file_iwrite_shared smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite_shared
-#define MPI_FILE_IWRITE_SHARED smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_iwrite_shared
-#define mpi_file_read_at_all_begin smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_at_all_begin
-#define MPI_FILE_READ_AT_ALL_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_at_all_begin
-#define mpi_file_read_at_all_end smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_at_all_end
-#define MPI_FILE_READ_AT_ALL_END smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_at_all_end
-#define mpi_file_write_at_all_begin smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_at_all_begin
-#define MPI_FILE_WRITE_AT_ALL_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_at_all_begin
-#define mpi_file_write_at_all_end smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_at_all_end
-#define MPI_FILE_WRITE_AT_ALL_END smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_at_all_end
-#define mpi_file_read_all_begin smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_all_begin
-#define MPI_FILE_READ_ALL_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_all_begin
-#define mpi_file_read_all_end smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_all_end
-#define MPI_FILE_READ_ALL_END smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_all_end
-#define mpi_file_write_all_begin smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_all_begin
-#define MPI_FILE_WRITE_ALL_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_all_begin
-#define mpi_file_write_all_end smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_all_end
-#define MPI_FILE_WRITE_ALL_END smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_all_end
-#define mpi_file_read_ordered_begin smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_ordered_begin
-#define MPI_FILE_READ_ORDERED_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_ordered_begin
-#define mpi_file_read_ordered_end smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_ordered_end
-#define MPI_FILE_READ_ORDERED_END smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_read_ordered_end
-#define mpi_file_write_ordered_begin smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_ordered_begin
-#define MPI_FILE_WRITE_ORDERED_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_ordered_begin
-#define mpi_file_write_ordered_end smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_ordered_end
-#define MPI_FILE_WRITE_ORDERED_END smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_write_ordered_end
-#define mpi_file_get_type_extent smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_type_extent
-#define MPI_FILE_GET_TYPE_EXTENT smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_type_extent
-#define mpi_file_set_atomicity smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_atomicity
-#define MPI_FILE_SET_ATOMICITY smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_set_atomicity
-#define mpi_file_get_atomicity smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_atomicity
-#define MPI_FILE_GET_ATOMICITY smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_File_get_atomicity
-#define mpi_message_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Message_f2c
-#define MPI_MESSAGE_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Message_f2c
-#define mpi_message_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Message_c2f
-#define MPI_MESSAGE_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Message_c2f
-#define mpi_mrecv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Mrecv
-#define MPI_MRECV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Mrecv
-#define mpi_mprobe smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Mprobe
-#define MPI_MPROBE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Mprobe
-#define mpi_imrecv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Imrecv
-#define MPI_IMRECV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Imrecv
-#define mpi_improbe smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Improbe
-#define MPI_IMPROBE smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Improbe
-#define mpi_neighbor_allgather smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_allgather
-#define MPI_NEIGHBOR_ALLGATHER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_allgather
-#define mpi_neighbor_allgatherv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_allgatherv
-#define MPI_NEIGHBOR_ALLGATHERV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_allgatherv
-#define mpi_neighbor_alltoall smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_alltoall
-#define MPI_NEIGHBOR_ALLTOALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_alltoall
-#define mpi_neighbor_alltoallv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_alltoallv
-#define MPI_NEIGHBOR_ALLTOALLV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_alltoallv
-#define mpi_neighbor_alltoallw smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_alltoallw
-#define MPI_NEIGHBOR_ALLTOALLW smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Neighbor_alltoallw
-#define mpi_ineighbor_allgather smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_allgather
-#define MPI_INEIGHBOR_ALLGATHER smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_allgather
-#define mpi_ineighbor_allgatherv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_allgatherv
-#define MPI_INEIGHBOR_ALLGATHERV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_allgatherv
-#define mpi_ineighbor_alltoall smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_alltoall
-#define MPI_INEIGHBOR_ALLTOALL smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_alltoall
-#define mpi_ineighbor_alltoallv smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_alltoallv
-#define MPI_INEIGHBOR_ALLTOALLV smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_alltoallv
-#define mpi_ineighbor_alltoallw smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_alltoallw
-#define MPI_INEIGHBOR_ALLTOALLW smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Ineighbor_alltoallw
-#define mpi_status_f2c smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_f2c
-#define MPI_STATUS_F2C smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_f2c
-#define mpi_status_c2f smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_c2f
-#define MPI_STATUS_C2F smpi_trace_set_call_location(__FILE__,__LINE__); call MPI_Status_c2f
+#define mpi_init smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_init"); call MPI_Init
+#define MPI_INIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INIT"); call MPI_Init
+#define mpi_finalize smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_finalize"); call MPI_Finalize
+#define MPI_FINALIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FINALIZE"); call MPI_Finalize
+#define mpi_finalized smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_finalized"); call MPI_Finalized
+#define MPI_FINALIZED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FINALIZED"); call MPI_Finalized
+#define mpi_init_thread smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_init_thread"); call MPI_Init_thread
+#define MPI_INIT_THREAD smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INIT_THREAD"); call MPI_Init_thread
+#define mpi_initialized smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_initialized"); call MPI_Initialized
+#define MPI_INITIALIZED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INITIALIZED"); call MPI_Initialized
+#define mpi_query_thread smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_query_thread"); call MPI_Query_thread
+#define MPI_QUERY_THREAD smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_QUERY_THREAD"); call MPI_Query_thread
+#define mpi_is_thread_main smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_is_thread_main"); call MPI_Is_thread_main
+#define MPI_IS_THREAD_MAIN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IS_THREAD_MAIN"); call MPI_Is_thread_main
+#define mpi_get_version smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get_version"); call MPI_Get_version
+#define MPI_GET_VERSION smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET_VERSION"); call MPI_Get_version
+#define mpi_get_library_version smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get_library_version"); call MPI_Get_library_version
+#define MPI_GET_LIBRARY_VERSION smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET_LIBRARY_VERSION"); call MPI_Get_library_version
+#define mpi_get_processor_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get_processor_name"); call MPI_Get_processor_name
+#define MPI_GET_PROCESSOR_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET_PROCESSOR_NAME"); call MPI_Get_processor_name
+#define mpi_abort smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_abort"); call MPI_Abort
+#define MPI_ABORT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ABORT"); call MPI_Abort
+#define mpi_alloc_mem smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_alloc_mem"); call MPI_Alloc_mem
+#define MPI_ALLOC_MEM smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ALLOC_MEM"); call MPI_Alloc_mem
+#define mpi_free_mem smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_free_mem"); call MPI_Free_mem
+#define MPI_FREE_MEM smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FREE_MEM"); call MPI_Free_mem
+#define mpi_wtime smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_wtime"); call MPI_Wtime
+#define MPI_WTIME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WTIME"); call MPI_Wtime
+#define mpi_wtick smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_wtick"); call MPI_Wtick
+#define MPI_WTICK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WTICK"); call MPI_Wtick
+#define mpi_buffer_attach smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_buffer_attach"); call MPI_Buffer_attach
+#define MPI_BUFFER_ATTACH smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_BUFFER_ATTACH"); call MPI_Buffer_attach
+#define mpi_buffer_detach smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_buffer_detach"); call MPI_Buffer_detach
+#define MPI_BUFFER_DETACH smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_BUFFER_DETACH"); call MPI_Buffer_detach
+#define mpi_address smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_address"); call MPI_Address
+#define MPI_ADDRESS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ADDRESS"); call MPI_Address
+#define mpi_get_address smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get_address"); call MPI_Get_address
+#define MPI_GET_ADDRESS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET_ADDRESS"); call MPI_Get_address
+#define mpi_aint_diff smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_aint_diff"); call MPI_Aint_diff
+#define MPI_AINT_DIFF smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_AINT_DIFF"); call MPI_Aint_diff
+#define mpi_aint_add smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_aint_add"); call MPI_Aint_add
+#define MPI_AINT_ADD smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_AINT_ADD"); call MPI_Aint_add
+#define mpi_error_class smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_error_class"); call MPI_Error_class
+#define MPI_ERROR_CLASS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ERROR_CLASS"); call MPI_Error_class
+#define mpi_error_string smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_error_string"); call MPI_Error_string
+#define MPI_ERROR_STRING smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ERROR_STRING"); call MPI_Error_string
+#define mpi_attr_delete smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_attr_delete"); call MPI_Attr_delete
+#define MPI_ATTR_DELETE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ATTR_DELETE"); call MPI_Attr_delete
+#define mpi_attr_get smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_attr_get"); call MPI_Attr_get
+#define MPI_ATTR_GET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ATTR_GET"); call MPI_Attr_get
+#define mpi_attr_put smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_attr_put"); call MPI_Attr_put
+#define MPI_ATTR_PUT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ATTR_PUT"); call MPI_Attr_put
+#define mpi_keyval_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_keyval_create"); call MPI_Keyval_create
+#define MPI_KEYVAL_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_KEYVAL_CREATE"); call MPI_Keyval_create
+#define mpi_keyval_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_keyval_free"); call MPI_Keyval_free
+#define MPI_KEYVAL_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_KEYVAL_FREE"); call MPI_Keyval_free
+#define mpi_type_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_free"); call MPI_Type_free
+#define MPI_TYPE_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_FREE"); call MPI_Type_free
+#define mpi_type_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_size"); call MPI_Type_size
+#define MPI_TYPE_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_SIZE"); call MPI_Type_size
+#define mpi_type_size_x smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_size_x"); call MPI_Type_size_x
+#define MPI_TYPE_SIZE_X smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_SIZE_X"); call MPI_Type_size_x
+#define mpi_type_get_extent smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_get_extent"); call MPI_Type_get_extent
+#define MPI_TYPE_GET_EXTENT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_GET_EXTENT"); call MPI_Type_get_extent
+#define mpi_type_get_extent_x smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_get_extent_x"); call MPI_Type_get_extent_x
+#define MPI_TYPE_GET_EXTENT_X smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_GET_EXTENT_X"); call MPI_Type_get_extent_x
+#define mpi_type_get_true_extent smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_get_true_extent"); call MPI_Type_get_true_extent
+#define MPI_TYPE_GET_TRUE_EXTENT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_GET_TRUE_EXTENT"); call MPI_Type_get_true_extent
+#define mpi_type_get_true_extent_x smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_get_true_extent_x"); call MPI_Type_get_true_extent_x
+#define MPI_TYPE_GET_TRUE_EXTENT_X smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_GET_TRUE_EXTENT_X"); call MPI_Type_get_true_extent_x
+#define mpi_type_extent smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_extent"); call MPI_Type_extent
+#define MPI_TYPE_EXTENT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_EXTENT"); call MPI_Type_extent
+#define mpi_type_lb smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_lb"); call MPI_Type_lb
+#define MPI_TYPE_LB smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_LB"); call MPI_Type_lb
+#define mpi_type_ub smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_ub"); call MPI_Type_ub
+#define MPI_TYPE_UB smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_UB"); call MPI_Type_ub
+#define mpi_type_commit smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_commit"); call MPI_Type_commit
+#define MPI_TYPE_COMMIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_COMMIT"); call MPI_Type_commit
+#define mpi_type_hindexed smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_hindexed"); call MPI_Type_hindexed
+#define MPI_TYPE_HINDEXED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_HINDEXED"); call MPI_Type_hindexed
+#define mpi_type_create_hindexed smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_hindexed"); call MPI_Type_create_hindexed
+#define MPI_TYPE_CREATE_HINDEXED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_HINDEXED"); call MPI_Type_create_hindexed
+#define mpi_type_create_hindexed_block smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_hindexed_block"); call MPI_Type_create_hindexed_block
+#define MPI_TYPE_CREATE_HINDEXED_BLOCK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_HINDEXED_BLOCK"); call MPI_Type_create_hindexed_block
+#define mpi_type_hvector smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_hvector"); call MPI_Type_hvector
+#define MPI_TYPE_HVECTOR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_HVECTOR"); call MPI_Type_hvector
+#define mpi_type_create_hvector smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_hvector"); call MPI_Type_create_hvector
+#define MPI_TYPE_CREATE_HVECTOR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_HVECTOR"); call MPI_Type_create_hvector
+#define mpi_type_indexed smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_indexed"); call MPI_Type_indexed
+#define MPI_TYPE_INDEXED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_INDEXED"); call MPI_Type_indexed
+#define mpi_type_create_indexed smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_indexed"); call MPI_Type_create_indexed
+#define MPI_TYPE_CREATE_INDEXED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_INDEXED"); call MPI_Type_create_indexed
+#define mpi_type_create_indexed_block smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_indexed_block"); call MPI_Type_create_indexed_block
+#define MPI_TYPE_CREATE_INDEXED_BLOCK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_INDEXED_BLOCK"); call MPI_Type_create_indexed_block
+#define mpi_type_struct smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_struct"); call MPI_Type_struct
+#define MPI_TYPE_STRUCT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_STRUCT"); call MPI_Type_struct
+#define mpi_type_create_struct smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_struct"); call MPI_Type_create_struct
+#define MPI_TYPE_CREATE_STRUCT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_STRUCT"); call MPI_Type_create_struct
+#define mpi_type_vector smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_vector"); call MPI_Type_vector
+#define MPI_TYPE_VECTOR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_VECTOR"); call MPI_Type_vector
+#define mpi_type_contiguous smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_contiguous"); call MPI_Type_contiguous
+#define MPI_TYPE_CONTIGUOUS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CONTIGUOUS"); call MPI_Type_contiguous
+#define mpi_type_create_resized smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_resized"); call MPI_Type_create_resized
+#define MPI_TYPE_CREATE_RESIZED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_RESIZED"); call MPI_Type_create_resized
+#define mpi_type_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_f2c"); call MPI_Type_f2c
+#define MPI_TYPE_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_F2C"); call MPI_Type_f2c
+#define mpi_type_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_c2f"); call MPI_Type_c2f
+#define MPI_TYPE_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_C2F"); call MPI_Type_c2f
+#define mpi_get_count smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get_count"); call MPI_Get_count
+#define MPI_GET_COUNT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET_COUNT"); call MPI_Get_count
+#define mpi_type_get_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_get_attr"); call MPI_Type_get_attr
+#define MPI_TYPE_GET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_GET_ATTR"); call MPI_Type_get_attr
+#define mpi_type_set_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_set_attr"); call MPI_Type_set_attr
+#define MPI_TYPE_SET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_SET_ATTR"); call MPI_Type_set_attr
+#define mpi_type_delete_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_delete_attr"); call MPI_Type_delete_attr
+#define MPI_TYPE_DELETE_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_DELETE_ATTR"); call MPI_Type_delete_attr
+#define mpi_type_create_keyval smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_keyval"); call MPI_Type_create_keyval
+#define MPI_TYPE_CREATE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_KEYVAL"); call MPI_Type_create_keyval
+#define mpi_type_free_keyval smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_free_keyval"); call MPI_Type_free_keyval
+#define MPI_TYPE_FREE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_FREE_KEYVAL"); call MPI_Type_free_keyval
+#define mpi_type_dup smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_dup"); call MPI_Type_dup
+#define MPI_TYPE_DUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_DUP"); call MPI_Type_dup
+#define mpi_type_set_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_set_name"); call MPI_Type_set_name
+#define MPI_TYPE_SET_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_SET_NAME"); call MPI_Type_set_name
+#define mpi_type_get_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_get_name"); call MPI_Type_get_name
+#define MPI_TYPE_GET_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_GET_NAME"); call MPI_Type_get_name
+#define mpi_pack smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_pack"); call MPI_Pack
+#define MPI_PACK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PACK"); call MPI_Pack
+#define mpi_pack_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_pack_size"); call MPI_Pack_size
+#define MPI_PACK_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PACK_SIZE"); call MPI_Pack_size
+#define mpi_unpack smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_unpack"); call MPI_Unpack
+#define MPI_UNPACK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_UNPACK"); call MPI_Unpack
+#define mpi_op_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_op_create"); call MPI_Op_create
+#define MPI_OP_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_OP_CREATE"); call MPI_Op_create
+#define mpi_op_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_op_free"); call MPI_Op_free
+#define MPI_OP_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_OP_FREE"); call MPI_Op_free
+#define mpi_op_commutative smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_op_commutative"); call MPI_Op_commutative
+#define MPI_OP_COMMUTATIVE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_OP_COMMUTATIVE"); call MPI_Op_commutative
+#define mpi_op_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_op_f2c"); call MPI_Op_f2c
+#define MPI_OP_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_OP_F2C"); call MPI_Op_f2c
+#define mpi_op_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_op_c2f"); call MPI_Op_c2f
+#define MPI_OP_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_OP_C2F"); call MPI_Op_c2f
+#define mpi_group_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_free"); call MPI_Group_free
+#define MPI_GROUP_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_FREE"); call MPI_Group_free
+#define mpi_group_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_size"); call MPI_Group_size
+#define MPI_GROUP_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_SIZE"); call MPI_Group_size
+#define mpi_group_rank smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_rank"); call MPI_Group_rank
+#define MPI_GROUP_RANK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_RANK"); call MPI_Group_rank
+#define mpi_group_translate_ranks smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_translate_ranks"); call MPI_Group_translate_ranks
+#define MPI_GROUP_TRANSLATE_RANKS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_TRANSLATE_RANKS"); call MPI_Group_translate_ranks
+#define mpi_group_compare smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_compare"); call MPI_Group_compare
+#define MPI_GROUP_COMPARE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_COMPARE"); call MPI_Group_compare
+#define mpi_group_union smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_union"); call MPI_Group_union
+#define MPI_GROUP_UNION smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_UNION"); call MPI_Group_union
+#define mpi_group_intersection smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_intersection"); call MPI_Group_intersection
+#define MPI_GROUP_INTERSECTION smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_INTERSECTION"); call MPI_Group_intersection
+#define mpi_group_difference smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_difference"); call MPI_Group_difference
+#define MPI_GROUP_DIFFERENCE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_DIFFERENCE"); call MPI_Group_difference
+#define mpi_group_incl smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_incl"); call MPI_Group_incl
+#define MPI_GROUP_INCL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_INCL"); call MPI_Group_incl
+#define mpi_group_excl smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_excl"); call MPI_Group_excl
+#define MPI_GROUP_EXCL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_EXCL"); call MPI_Group_excl
+#define mpi_group_range_incl smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_range_incl"); call MPI_Group_range_incl
+#define MPI_GROUP_RANGE_INCL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_RANGE_INCL"); call MPI_Group_range_incl
+#define mpi_group_range_excl smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_range_excl"); call MPI_Group_range_excl
+#define MPI_GROUP_RANGE_EXCL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_RANGE_EXCL"); call MPI_Group_range_excl
+#define mpi_group_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_f2c"); call MPI_Group_f2c
+#define MPI_GROUP_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_F2C"); call MPI_Group_f2c
+#define mpi_group_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_group_c2f"); call MPI_Group_c2f
+#define MPI_GROUP_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GROUP_C2F"); call MPI_Group_c2f
+#define mpi_comm_rank smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_rank"); call MPI_Comm_rank
+#define MPI_COMM_RANK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_RANK"); call MPI_Comm_rank
+#define mpi_comm_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_size"); call MPI_Comm_size
+#define MPI_COMM_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SIZE"); call MPI_Comm_size
+#define mpi_comm_get_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_get_name"); call MPI_Comm_get_name
+#define MPI_COMM_GET_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_GET_NAME"); call MPI_Comm_get_name
+#define mpi_comm_set_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_set_name"); call MPI_Comm_set_name
+#define MPI_COMM_SET_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SET_NAME"); call MPI_Comm_set_name
+#define mpi_comm_dup smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_dup"); call MPI_Comm_dup
+#define MPI_COMM_DUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_DUP"); call MPI_Comm_dup
+#define mpi_comm_dup_with_info smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_dup_with_info"); call MPI_Comm_dup_with_info
+#define MPI_COMM_DUP_WITH_INFO smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_DUP_WITH_INFO"); call MPI_Comm_dup_with_info
+#define mpi_comm_get_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_get_attr"); call MPI_Comm_get_attr
+#define MPI_COMM_GET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_GET_ATTR"); call MPI_Comm_get_attr
+#define mpi_comm_set_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_set_attr"); call MPI_Comm_set_attr
+#define MPI_COMM_SET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SET_ATTR"); call MPI_Comm_set_attr
+#define mpi_comm_delete_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_delete_attr"); call MPI_Comm_delete_attr
+#define MPI_COMM_DELETE_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_DELETE_ATTR"); call MPI_Comm_delete_attr
+#define mpi_comm_create_keyval smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_create_keyval"); call MPI_Comm_create_keyval
+#define MPI_COMM_CREATE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_CREATE_KEYVAL"); call MPI_Comm_create_keyval
+#define mpi_comm_free_keyval smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_free_keyval"); call MPI_Comm_free_keyval
+#define MPI_COMM_FREE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_FREE_KEYVAL"); call MPI_Comm_free_keyval
+#define mpi_comm_group smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_group"); call MPI_Comm_group
+#define MPI_COMM_GROUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_GROUP"); call MPI_Comm_group
+#define mpi_comm_compare smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_compare"); call MPI_Comm_compare
+#define MPI_COMM_COMPARE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_COMPARE"); call MPI_Comm_compare
+#define mpi_comm_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_create"); call MPI_Comm_create
+#define MPI_COMM_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_CREATE"); call MPI_Comm_create
+#define mpi_comm_create_group smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_create_group"); call MPI_Comm_create_group
+#define MPI_COMM_CREATE_GROUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_CREATE_GROUP"); call MPI_Comm_create_group
+#define mpi_comm_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_free"); call MPI_Comm_free
+#define MPI_COMM_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_FREE"); call MPI_Comm_free
+#define mpi_comm_disconnect smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_disconnect"); call MPI_Comm_disconnect
+#define MPI_COMM_DISCONNECT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_DISCONNECT"); call MPI_Comm_disconnect
+#define mpi_comm_split smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_split"); call MPI_Comm_split
+#define MPI_COMM_SPLIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SPLIT"); call MPI_Comm_split
+#define mpi_comm_set_info smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_set_info"); call MPI_Comm_set_info
+#define MPI_COMM_SET_INFO smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SET_INFO"); call MPI_Comm_set_info
+#define mpi_comm_get_info smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_get_info"); call MPI_Comm_get_info
+#define MPI_COMM_GET_INFO smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_GET_INFO"); call MPI_Comm_get_info
+#define mpi_comm_split_type smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_split_type"); call MPI_Comm_split_type
+#define MPI_COMM_SPLIT_TYPE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SPLIT_TYPE"); call MPI_Comm_split_type
+#define mpi_comm_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_f2c"); call MPI_Comm_f2c
+#define MPI_COMM_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_F2C"); call MPI_Comm_f2c
+#define mpi_comm_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_c2f"); call MPI_Comm_c2f
+#define MPI_COMM_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_C2F"); call MPI_Comm_c2f
+#define mpi_start smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_start"); call MPI_Start
+#define MPI_START smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_START"); call MPI_Start
+#define mpi_startall smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_startall"); call MPI_Startall
+#define MPI_STARTALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_STARTALL"); call MPI_Startall
+#define mpi_request_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_request_free"); call MPI_Request_free
+#define MPI_REQUEST_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REQUEST_FREE"); call MPI_Request_free
+#define mpi_recv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_recv"); call MPI_Recv
+#define MPI_RECV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_RECV"); call MPI_Recv
+#define mpi_recv_init smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_recv_init"); call MPI_Recv_init
+#define MPI_RECV_INIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_RECV_INIT"); call MPI_Recv_init
+#define mpi_irecv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_irecv"); call MPI_Irecv
+#define MPI_IRECV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IRECV"); call MPI_Irecv
+#define mpi_send smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_send"); call MPI_Send
+#define MPI_SEND smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SEND"); call MPI_Send
+#define mpi_send_init smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_send_init"); call MPI_Send_init
+#define MPI_SEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SEND_INIT"); call MPI_Send_init
+#define mpi_isend smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_isend"); call MPI_Isend
+#define MPI_ISEND smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ISEND"); call MPI_Isend
+#define mpi_ssend smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ssend"); call MPI_Ssend
+#define MPI_SSEND smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SSEND"); call MPI_Ssend
+#define mpi_ssend_init smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ssend_init"); call MPI_Ssend_init
+#define MPI_SSEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SSEND_INIT"); call MPI_Ssend_init
+#define mpi_issend smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_issend"); call MPI_Issend
+#define MPI_ISSEND smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ISSEND"); call MPI_Issend
+#define mpi_bsend smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_bsend"); call MPI_Bsend
+#define MPI_BSEND smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_BSEND"); call MPI_Bsend
+#define mpi_bsend_init smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_bsend_init"); call MPI_Bsend_init
+#define MPI_BSEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_BSEND_INIT"); call MPI_Bsend_init
+#define mpi_ibsend smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ibsend"); call MPI_Ibsend
+#define MPI_IBSEND smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IBSEND"); call MPI_Ibsend
+#define mpi_rsend smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_rsend"); call MPI_Rsend
+#define MPI_RSEND smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_RSEND"); call MPI_Rsend
+#define mpi_rsend_init smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_rsend_init"); call MPI_Rsend_init
+#define MPI_RSEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_RSEND_INIT"); call MPI_Rsend_init
+#define mpi_irsend smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_irsend"); call MPI_Irsend
+#define MPI_IRSEND smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IRSEND"); call MPI_Irsend
+#define mpi_sendrecv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_sendrecv"); call MPI_Sendrecv
+#define MPI_SENDRECV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SENDRECV"); call MPI_Sendrecv
+#define mpi_isendrecv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_isendrecv"); call MPI_Isendrecv
+#define MPI_ISENDRECV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ISENDRECV"); call MPI_Isendrecv
+#define mpi_sendrecv_replace smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_sendrecv_replace"); call MPI_Sendrecv_replace
+#define MPI_SENDRECV_REPLACE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SENDRECV_REPLACE"); call MPI_Sendrecv_replace
+#define mpi_isendrecv_replace smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_isendrecv_replace"); call MPI_Isendrecv_replace
+#define MPI_ISENDRECV_REPLACE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ISENDRECV_REPLACE"); call MPI_Isendrecv_replace
+#define mpi_test smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_test"); call MPI_Test
+#define MPI_TEST smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TEST"); call MPI_Test
+#define mpi_testany smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_testany"); call MPI_Testany
+#define MPI_TESTANY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TESTANY"); call MPI_Testany
+#define mpi_testall smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_testall"); call MPI_Testall
+#define MPI_TESTALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TESTALL"); call MPI_Testall
+#define mpi_testsome smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_testsome"); call MPI_Testsome
+#define MPI_TESTSOME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TESTSOME"); call MPI_Testsome
+#define mpi_test_cancelled smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_test_cancelled"); call MPI_Test_cancelled
+#define MPI_TEST_CANCELLED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TEST_CANCELLED"); call MPI_Test_cancelled
+#define mpi_wait smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_wait"); call MPI_Wait
+#define MPI_WAIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WAIT"); call MPI_Wait
+#define mpi_waitany smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_waitany"); call MPI_Waitany
+#define MPI_WAITANY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WAITANY"); call MPI_Waitany
+#define mpi_waitall smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_waitall"); call MPI_Waitall
+#define MPI_WAITALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WAITALL"); call MPI_Waitall
+#define mpi_waitsome smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_waitsome"); call MPI_Waitsome
+#define MPI_WAITSOME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WAITSOME"); call MPI_Waitsome
+#define mpi_iprobe smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_iprobe"); call MPI_Iprobe
+#define MPI_IPROBE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IPROBE"); call MPI_Iprobe
+#define mpi_probe smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_probe"); call MPI_Probe
+#define MPI_PROBE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PROBE"); call MPI_Probe
+#define mpi_request_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_request_f2c"); call MPI_Request_f2c
+#define MPI_REQUEST_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REQUEST_F2C"); call MPI_Request_f2c
+#define mpi_request_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_request_c2f"); call MPI_Request_c2f
+#define MPI_REQUEST_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REQUEST_C2F"); call MPI_Request_c2f
+#define mpi_cancel smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cancel"); call MPI_Cancel
+#define MPI_CANCEL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CANCEL"); call MPI_Cancel
+#define mpi_bcast smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_bcast"); call MPI_Bcast
+#define MPI_BCAST smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_BCAST"); call MPI_Bcast
+#define mpi_barrier smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_barrier"); call MPI_Barrier
+#define MPI_BARRIER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_BARRIER"); call MPI_Barrier
+#define mpi_ibarrier smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ibarrier"); call MPI_Ibarrier
+#define MPI_IBARRIER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IBARRIER"); call MPI_Ibarrier
+#define mpi_ibcast smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ibcast"); call MPI_Ibcast
+#define MPI_IBCAST smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IBCAST"); call MPI_Ibcast
+#define mpi_igather smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_igather"); call MPI_Igather
+#define MPI_IGATHER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IGATHER"); call MPI_Igather
+#define mpi_igatherv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_igatherv"); call MPI_Igatherv
+#define MPI_IGATHERV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IGATHERV"); call MPI_Igatherv
+#define mpi_iallgather smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_iallgather"); call MPI_Iallgather
+#define MPI_IALLGATHER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IALLGATHER"); call MPI_Iallgather
+#define mpi_iallgatherv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_iallgatherv"); call MPI_Iallgatherv
+#define MPI_IALLGATHERV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IALLGATHERV"); call MPI_Iallgatherv
+#define mpi_iscatter smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_iscatter"); call MPI_Iscatter
+#define MPI_ISCATTER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ISCATTER"); call MPI_Iscatter
+#define mpi_iscatterv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_iscatterv"); call MPI_Iscatterv
+#define MPI_ISCATTERV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ISCATTERV"); call MPI_Iscatterv
+#define mpi_ireduce smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ireduce"); call MPI_Ireduce
+#define MPI_IREDUCE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IREDUCE"); call MPI_Ireduce
+#define mpi_iallreduce smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_iallreduce"); call MPI_Iallreduce
+#define MPI_IALLREDUCE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IALLREDUCE"); call MPI_Iallreduce
+#define mpi_iscan smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_iscan"); call MPI_Iscan
+#define MPI_ISCAN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ISCAN"); call MPI_Iscan
+#define mpi_iexscan smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_iexscan"); call MPI_Iexscan
+#define MPI_IEXSCAN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IEXSCAN"); call MPI_Iexscan
+#define mpi_ireduce_scatter smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ireduce_scatter"); call MPI_Ireduce_scatter
+#define MPI_IREDUCE_SCATTER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IREDUCE_SCATTER"); call MPI_Ireduce_scatter
+#define mpi_ireduce_scatter_block smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ireduce_scatter_block"); call MPI_Ireduce_scatter_block
+#define MPI_IREDUCE_SCATTER_BLOCK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IREDUCE_SCATTER_BLOCK"); call MPI_Ireduce_scatter_block
+#define mpi_ialltoall smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ialltoall"); call MPI_Ialltoall
+#define MPI_IALLTOALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IALLTOALL"); call MPI_Ialltoall
+#define mpi_ialltoallv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ialltoallv"); call MPI_Ialltoallv
+#define MPI_IALLTOALLV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IALLTOALLV"); call MPI_Ialltoallv
+#define mpi_ialltoallw smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ialltoallw"); call MPI_Ialltoallw
+#define MPI_IALLTOALLW smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IALLTOALLW"); call MPI_Ialltoallw
+#define mpi_gather smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_gather"); call MPI_Gather
+#define MPI_GATHER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GATHER"); call MPI_Gather
+#define mpi_gatherv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_gatherv"); call MPI_Gatherv
+#define MPI_GATHERV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GATHERV"); call MPI_Gatherv
+#define mpi_allgather smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_allgather"); call MPI_Allgather
+#define MPI_ALLGATHER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ALLGATHER"); call MPI_Allgather
+#define mpi_allgatherv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_allgatherv"); call MPI_Allgatherv
+#define MPI_ALLGATHERV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ALLGATHERV"); call MPI_Allgatherv
+#define mpi_scatter smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_scatter"); call MPI_Scatter
+#define MPI_SCATTER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SCATTER"); call MPI_Scatter
+#define mpi_scatterv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_scatterv"); call MPI_Scatterv
+#define MPI_SCATTERV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SCATTERV"); call MPI_Scatterv
+#define mpi_reduce smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_reduce"); call MPI_Reduce
+#define MPI_REDUCE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REDUCE"); call MPI_Reduce
+#define mpi_allreduce smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_allreduce"); call MPI_Allreduce
+#define MPI_ALLREDUCE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ALLREDUCE"); call MPI_Allreduce
+#define mpi_scan smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_scan"); call MPI_Scan
+#define MPI_SCAN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_SCAN"); call MPI_Scan
+#define mpi_exscan smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_exscan"); call MPI_Exscan
+#define MPI_EXSCAN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_EXSCAN"); call MPI_Exscan
+#define mpi_reduce_scatter smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_reduce_scatter"); call MPI_Reduce_scatter
+#define MPI_REDUCE_SCATTER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REDUCE_SCATTER"); call MPI_Reduce_scatter
+#define mpi_reduce_scatter_block smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_reduce_scatter_block"); call MPI_Reduce_scatter_block
+#define MPI_REDUCE_SCATTER_BLOCK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REDUCE_SCATTER_BLOCK"); call MPI_Reduce_scatter_block
+#define mpi_alltoall smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_alltoall"); call MPI_Alltoall
+#define MPI_ALLTOALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ALLTOALL"); call MPI_Alltoall
+#define mpi_alltoallv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_alltoallv"); call MPI_Alltoallv
+#define MPI_ALLTOALLV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ALLTOALLV"); call MPI_Alltoallv
+#define mpi_alltoallw smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_alltoallw"); call MPI_Alltoallw
+#define MPI_ALLTOALLW smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ALLTOALLW"); call MPI_Alltoallw
+#define mpi_reduce_local smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_reduce_local"); call MPI_Reduce_local
+#define MPI_REDUCE_LOCAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REDUCE_LOCAL"); call MPI_Reduce_local
+#define mpi_info_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_create"); call MPI_Info_create
+#define MPI_INFO_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_CREATE"); call MPI_Info_create
+#define mpi_info_set smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_set"); call MPI_Info_set
+#define MPI_INFO_SET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_SET"); call MPI_Info_set
+#define mpi_info_get smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_get"); call MPI_Info_get
+#define MPI_INFO_GET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_GET"); call MPI_Info_get
+#define mpi_info_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_free"); call MPI_Info_free
+#define MPI_INFO_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_FREE"); call MPI_Info_free
+#define mpi_info_delete smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_delete"); call MPI_Info_delete
+#define MPI_INFO_DELETE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_DELETE"); call MPI_Info_delete
+#define mpi_info_dup smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_dup"); call MPI_Info_dup
+#define MPI_INFO_DUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_DUP"); call MPI_Info_dup
+#define mpi_info_get_nkeys smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_get_nkeys"); call MPI_Info_get_nkeys
+#define MPI_INFO_GET_NKEYS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_GET_NKEYS"); call MPI_Info_get_nkeys
+#define mpi_info_get_nthkey smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_get_nthkey"); call MPI_Info_get_nthkey
+#define MPI_INFO_GET_NTHKEY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_GET_NTHKEY"); call MPI_Info_get_nthkey
+#define mpi_info_get_valuelen smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_get_valuelen"); call MPI_Info_get_valuelen
+#define MPI_INFO_GET_VALUELEN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_GET_VALUELEN"); call MPI_Info_get_valuelen
+#define mpi_info_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_f2c"); call MPI_Info_f2c
+#define MPI_INFO_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_F2C"); call MPI_Info_f2c
+#define mpi_info_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_info_c2f"); call MPI_Info_c2f
+#define MPI_INFO_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INFO_C2F"); call MPI_Info_c2f
+#define mpi_win_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_free"); call MPI_Win_free
+#define MPI_WIN_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_FREE"); call MPI_Win_free
+#define mpi_win_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_create"); call MPI_Win_create
+#define MPI_WIN_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_CREATE"); call MPI_Win_create
+#define mpi_win_allocate smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_allocate"); call MPI_Win_allocate
+#define MPI_WIN_ALLOCATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_ALLOCATE"); call MPI_Win_allocate
+#define mpi_win_allocate_shared smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_allocate_shared"); call MPI_Win_allocate_shared
+#define MPI_WIN_ALLOCATE_SHARED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_ALLOCATE_SHARED"); call MPI_Win_allocate_shared
+#define mpi_win_create_dynamic smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_create_dynamic"); call MPI_Win_create_dynamic
+#define MPI_WIN_CREATE_DYNAMIC smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_CREATE_DYNAMIC"); call MPI_Win_create_dynamic
+#define mpi_win_attach smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_attach"); call MPI_Win_attach
+#define MPI_WIN_ATTACH smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_ATTACH"); call MPI_Win_attach
+#define mpi_win_detach smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_detach"); call MPI_Win_detach
+#define MPI_WIN_DETACH smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_DETACH"); call MPI_Win_detach
+#define mpi_win_set_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_set_name"); call MPI_Win_set_name
+#define MPI_WIN_SET_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_SET_NAME"); call MPI_Win_set_name
+#define mpi_win_get_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_get_name"); call MPI_Win_get_name
+#define MPI_WIN_GET_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_GET_NAME"); call MPI_Win_get_name
+#define mpi_win_set_info smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_set_info"); call MPI_Win_set_info
+#define MPI_WIN_SET_INFO smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_SET_INFO"); call MPI_Win_set_info
+#define mpi_win_get_info smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_get_info"); call MPI_Win_get_info
+#define MPI_WIN_GET_INFO smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_GET_INFO"); call MPI_Win_get_info
+#define mpi_win_get_group smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_get_group"); call MPI_Win_get_group
+#define MPI_WIN_GET_GROUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_GET_GROUP"); call MPI_Win_get_group
+#define mpi_win_fence smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_fence"); call MPI_Win_fence
+#define MPI_WIN_FENCE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_FENCE"); call MPI_Win_fence
+#define mpi_win_get_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_get_attr"); call MPI_Win_get_attr
+#define MPI_WIN_GET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_GET_ATTR"); call MPI_Win_get_attr
+#define mpi_win_set_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_set_attr"); call MPI_Win_set_attr
+#define MPI_WIN_SET_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_SET_ATTR"); call MPI_Win_set_attr
+#define mpi_win_delete_attr smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_delete_attr"); call MPI_Win_delete_attr
+#define MPI_WIN_DELETE_ATTR smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_DELETE_ATTR"); call MPI_Win_delete_attr
+#define mpi_win_create_keyval smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_create_keyval"); call MPI_Win_create_keyval
+#define MPI_WIN_CREATE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_CREATE_KEYVAL"); call MPI_Win_create_keyval
+#define mpi_win_free_keyval smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_free_keyval"); call MPI_Win_free_keyval
+#define MPI_WIN_FREE_KEYVAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_FREE_KEYVAL"); call MPI_Win_free_keyval
+#define mpi_win_complete smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_complete"); call MPI_Win_complete
+#define MPI_WIN_COMPLETE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_COMPLETE"); call MPI_Win_complete
+#define mpi_win_post smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_post"); call MPI_Win_post
+#define MPI_WIN_POST smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_POST"); call MPI_Win_post
+#define mpi_win_start smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_start"); call MPI_Win_start
+#define MPI_WIN_START smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_START"); call MPI_Win_start
+#define mpi_win_wait smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_wait"); call MPI_Win_wait
+#define MPI_WIN_WAIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_WAIT"); call MPI_Win_wait
+#define mpi_win_lock smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_lock"); call MPI_Win_lock
+#define MPI_WIN_LOCK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_LOCK"); call MPI_Win_lock
+#define mpi_win_lock_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_lock_all"); call MPI_Win_lock_all
+#define MPI_WIN_LOCK_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_LOCK_ALL"); call MPI_Win_lock_all
+#define mpi_win_unlock smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_unlock"); call MPI_Win_unlock
+#define MPI_WIN_UNLOCK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_UNLOCK"); call MPI_Win_unlock
+#define mpi_win_unlock_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_unlock_all"); call MPI_Win_unlock_all
+#define MPI_WIN_UNLOCK_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_UNLOCK_ALL"); call MPI_Win_unlock_all
+#define mpi_win_flush smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_flush"); call MPI_Win_flush
+#define MPI_WIN_FLUSH smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_FLUSH"); call MPI_Win_flush
+#define mpi_win_flush_local smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_flush_local"); call MPI_Win_flush_local
+#define MPI_WIN_FLUSH_LOCAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_FLUSH_LOCAL"); call MPI_Win_flush_local
+#define mpi_win_flush_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_flush_all"); call MPI_Win_flush_all
+#define MPI_WIN_FLUSH_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_FLUSH_ALL"); call MPI_Win_flush_all
+#define mpi_win_flush_local_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_flush_local_all"); call MPI_Win_flush_local_all
+#define MPI_WIN_FLUSH_LOCAL_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_FLUSH_LOCAL_ALL"); call MPI_Win_flush_local_all
+#define mpi_win_shared_query smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_shared_query"); call MPI_Win_shared_query
+#define MPI_WIN_SHARED_QUERY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_SHARED_QUERY"); call MPI_Win_shared_query
+#define mpi_win_sync smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_sync"); call MPI_Win_sync
+#define MPI_WIN_SYNC smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_SYNC"); call MPI_Win_sync
+#define mpi_win_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_f2c"); call MPI_Win_f2c
+#define MPI_WIN_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_F2C"); call MPI_Win_f2c
+#define mpi_win_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_c2f"); call MPI_Win_c2f
+#define MPI_WIN_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_C2F"); call MPI_Win_c2f
+#define mpi_get smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get"); call MPI_Get
+#define MPI_GET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET"); call MPI_Get
+#define mpi_put smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_put"); call MPI_Put
+#define MPI_PUT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PUT"); call MPI_Put
+#define mpi_accumulate smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_accumulate"); call MPI_Accumulate
+#define MPI_ACCUMULATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ACCUMULATE"); call MPI_Accumulate
+#define mpi_get_accumulate smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get_accumulate"); call MPI_Get_accumulate
+#define MPI_GET_ACCUMULATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET_ACCUMULATE"); call MPI_Get_accumulate
+#define mpi_rget smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_rget"); call MPI_Rget
+#define MPI_RGET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_RGET"); call MPI_Rget
+#define mpi_rput smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_rput"); call MPI_Rput
+#define MPI_RPUT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_RPUT"); call MPI_Rput
+#define mpi_raccumulate smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_raccumulate"); call MPI_Raccumulate
+#define MPI_RACCUMULATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_RACCUMULATE"); call MPI_Raccumulate
+#define mpi_rget_accumulate smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_rget_accumulate"); call MPI_Rget_accumulate
+#define MPI_RGET_ACCUMULATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_RGET_ACCUMULATE"); call MPI_Rget_accumulate
+#define mpi_fetch_and_op smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_fetch_and_op"); call MPI_Fetch_and_op
+#define MPI_FETCH_AND_OP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FETCH_AND_OP"); call MPI_Fetch_and_op
+#define mpi_compare_and_swap smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_compare_and_swap"); call MPI_Compare_and_swap
+#define MPI_COMPARE_AND_SWAP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMPARE_AND_SWAP"); call MPI_Compare_and_swap
+#define mpi_cart_coords smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cart_coords"); call MPI_Cart_coords
+#define MPI_CART_COORDS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CART_COORDS"); call MPI_Cart_coords
+#define mpi_cart_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cart_create"); call MPI_Cart_create
+#define MPI_CART_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CART_CREATE"); call MPI_Cart_create
+#define mpi_cart_get smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cart_get"); call MPI_Cart_get
+#define MPI_CART_GET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CART_GET"); call MPI_Cart_get
+#define mpi_cart_rank smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cart_rank"); call MPI_Cart_rank
+#define MPI_CART_RANK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CART_RANK"); call MPI_Cart_rank
+#define mpi_cart_shift smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cart_shift"); call MPI_Cart_shift
+#define MPI_CART_SHIFT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CART_SHIFT"); call MPI_Cart_shift
+#define mpi_cart_sub smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cart_sub"); call MPI_Cart_sub
+#define MPI_CART_SUB smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CART_SUB"); call MPI_Cart_sub
+#define mpi_cartdim_get smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cartdim_get"); call MPI_Cartdim_get
+#define MPI_CARTDIM_GET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CARTDIM_GET"); call MPI_Cartdim_get
+#define mpi_dims_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_dims_create"); call MPI_Dims_create
+#define MPI_DIMS_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_DIMS_CREATE"); call MPI_Dims_create
+#define mpi_request_get_status smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_request_get_status"); call MPI_Request_get_status
+#define MPI_REQUEST_GET_STATUS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REQUEST_GET_STATUS"); call MPI_Request_get_status
+#define mpi_grequest_start smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_grequest_start"); call MPI_Grequest_start
+#define MPI_GREQUEST_START smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GREQUEST_START"); call MPI_Grequest_start
+#define mpi_grequest_complete smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_grequest_complete"); call MPI_Grequest_complete
+#define MPI_GREQUEST_COMPLETE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GREQUEST_COMPLETE"); call MPI_Grequest_complete
+#define mpi_status_set_cancelled smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_status_set_cancelled"); call MPI_Status_set_cancelled
+#define MPI_STATUS_SET_CANCELLED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_STATUS_SET_CANCELLED"); call MPI_Status_set_cancelled
+#define mpi_status_set_elements smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_status_set_elements"); call MPI_Status_set_elements
+#define MPI_STATUS_SET_ELEMENTS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_STATUS_SET_ELEMENTS"); call MPI_Status_set_elements
+#define mpi_status_set_elements_x smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_status_set_elements_x"); call MPI_Status_set_elements_x
+#define MPI_STATUS_SET_ELEMENTS_X smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_STATUS_SET_ELEMENTS_X"); call MPI_Status_set_elements_x
+#define mpi_type_create_subarray smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_subarray"); call MPI_Type_create_subarray
+#define MPI_TYPE_CREATE_SUBARRAY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_SUBARRAY"); call MPI_Type_create_subarray
+#define mpi_file_open smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_open"); call MPI_File_open
+#define MPI_FILE_OPEN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_OPEN"); call MPI_File_open
+#define mpi_file_close smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_close"); call MPI_File_close
+#define MPI_FILE_CLOSE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_CLOSE"); call MPI_File_close
+#define mpi_file_delete smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_delete"); call MPI_File_delete
+#define MPI_FILE_DELETE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_DELETE"); call MPI_File_delete
+#define mpi_file_get_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_size"); call MPI_File_get_size
+#define MPI_FILE_GET_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_SIZE"); call MPI_File_get_size
+#define mpi_file_get_group smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_group"); call MPI_File_get_group
+#define MPI_FILE_GET_GROUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_GROUP"); call MPI_File_get_group
+#define mpi_file_get_amode smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_amode"); call MPI_File_get_amode
+#define MPI_FILE_GET_AMODE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_AMODE"); call MPI_File_get_amode
+#define mpi_file_set_info smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_set_info"); call MPI_File_set_info
+#define MPI_FILE_SET_INFO smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_SET_INFO"); call MPI_File_set_info
+#define mpi_file_get_info smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_info"); call MPI_File_get_info
+#define MPI_FILE_GET_INFO smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_INFO"); call MPI_File_get_info
+#define mpi_file_read_at smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_at"); call MPI_File_read_at
+#define MPI_FILE_READ_AT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_AT"); call MPI_File_read_at
+#define mpi_file_read_at_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_at_all"); call MPI_File_read_at_all
+#define MPI_FILE_READ_AT_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_AT_ALL"); call MPI_File_read_at_all
+#define mpi_file_write_at smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_at"); call MPI_File_write_at
+#define MPI_FILE_WRITE_AT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_AT"); call MPI_File_write_at
+#define mpi_file_write_at_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_at_all"); call MPI_File_write_at_all
+#define MPI_FILE_WRITE_AT_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_AT_ALL"); call MPI_File_write_at_all
+#define mpi_file_read smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read"); call MPI_File_read
+#define MPI_FILE_READ smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ"); call MPI_File_read
+#define mpi_file_read_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_all"); call MPI_File_read_all
+#define MPI_FILE_READ_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_ALL"); call MPI_File_read_all
+#define mpi_file_write smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write"); call MPI_File_write
+#define MPI_FILE_WRITE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE"); call MPI_File_write
+#define mpi_file_write_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_all"); call MPI_File_write_all
+#define MPI_FILE_WRITE_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_ALL"); call MPI_File_write_all
+#define mpi_file_seek smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_seek"); call MPI_File_seek
+#define MPI_FILE_SEEK smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_SEEK"); call MPI_File_seek
+#define mpi_file_get_position smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_position"); call MPI_File_get_position
+#define MPI_FILE_GET_POSITION smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_POSITION"); call MPI_File_get_position
+#define mpi_file_read_shared smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_shared"); call MPI_File_read_shared
+#define MPI_FILE_READ_SHARED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_SHARED"); call MPI_File_read_shared
+#define mpi_file_write_shared smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_shared"); call MPI_File_write_shared
+#define MPI_FILE_WRITE_SHARED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_SHARED"); call MPI_File_write_shared
+#define mpi_file_read_ordered smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_ordered"); call MPI_File_read_ordered
+#define MPI_FILE_READ_ORDERED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_ORDERED"); call MPI_File_read_ordered
+#define mpi_file_write_ordered smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_ordered"); call MPI_File_write_ordered
+#define MPI_FILE_WRITE_ORDERED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_ORDERED"); call MPI_File_write_ordered
+#define mpi_file_seek_shared smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_seek_shared"); call MPI_File_seek_shared
+#define MPI_FILE_SEEK_SHARED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_SEEK_SHARED"); call MPI_File_seek_shared
+#define mpi_file_get_position_shared smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_position_shared"); call MPI_File_get_position_shared
+#define MPI_FILE_GET_POSITION_SHARED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_POSITION_SHARED"); call MPI_File_get_position_shared
+#define mpi_file_sync smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_sync"); call MPI_File_sync
+#define MPI_FILE_SYNC smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_SYNC"); call MPI_File_sync
+#define mpi_file_set_view smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_set_view"); call MPI_File_set_view
+#define MPI_FILE_SET_VIEW smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_SET_VIEW"); call MPI_File_set_view
+#define mpi_file_get_view smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_view"); call MPI_File_get_view
+#define MPI_FILE_GET_VIEW smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_VIEW"); call MPI_File_get_view
+#define mpi_errhandler_set smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_errhandler_set"); call MPI_Errhandler_set
+#define MPI_ERRHANDLER_SET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ERRHANDLER_SET"); call MPI_Errhandler_set
+#define mpi_errhandler_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_errhandler_create"); call MPI_Errhandler_create
+#define MPI_ERRHANDLER_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ERRHANDLER_CREATE"); call MPI_Errhandler_create
+#define mpi_errhandler_free smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_errhandler_free"); call MPI_Errhandler_free
+#define MPI_ERRHANDLER_FREE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ERRHANDLER_FREE"); call MPI_Errhandler_free
+#define mpi_errhandler_get smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_errhandler_get"); call MPI_Errhandler_get
+#define MPI_ERRHANDLER_GET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ERRHANDLER_GET"); call MPI_Errhandler_get
+#define mpi_comm_set_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_set_errhandler"); call MPI_Comm_set_errhandler
+#define MPI_COMM_SET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SET_ERRHANDLER"); call MPI_Comm_set_errhandler
+#define mpi_comm_get_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_get_errhandler"); call MPI_Comm_get_errhandler
+#define MPI_COMM_GET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_GET_ERRHANDLER"); call MPI_Comm_get_errhandler
+#define mpi_comm_create_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_create_errhandler"); call MPI_Comm_create_errhandler
+#define MPI_COMM_CREATE_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_CREATE_ERRHANDLER"); call MPI_Comm_create_errhandler
+#define mpi_comm_call_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_call_errhandler"); call MPI_Comm_call_errhandler
+#define MPI_COMM_CALL_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_CALL_ERRHANDLER"); call MPI_Comm_call_errhandler
+#define mpi_win_set_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_set_errhandler"); call MPI_Win_set_errhandler
+#define MPI_WIN_SET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_SET_ERRHANDLER"); call MPI_Win_set_errhandler
+#define mpi_win_get_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_get_errhandler"); call MPI_Win_get_errhandler
+#define MPI_WIN_GET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_GET_ERRHANDLER"); call MPI_Win_get_errhandler
+#define mpi_win_create_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_create_errhandler"); call MPI_Win_create_errhandler
+#define MPI_WIN_CREATE_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_CREATE_ERRHANDLER"); call MPI_Win_create_errhandler
+#define mpi_win_call_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_call_errhandler"); call MPI_Win_call_errhandler
+#define MPI_WIN_CALL_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_CALL_ERRHANDLER"); call MPI_Win_call_errhandler
+#define mpi_errhandler_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_errhandler_f2c"); call MPI_Errhandler_f2c
+#define MPI_ERRHANDLER_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ERRHANDLER_F2C"); call MPI_Errhandler_f2c
+#define mpi_errhandler_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_errhandler_c2f"); call MPI_Errhandler_c2f
+#define MPI_ERRHANDLER_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ERRHANDLER_C2F"); call MPI_Errhandler_c2f
+#define mpi_type_create_f90_integer smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_f90_integer"); call MPI_Type_create_f90_integer
+#define MPI_TYPE_CREATE_F90_INTEGER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_F90_INTEGER"); call MPI_Type_create_f90_integer
+#define mpi_type_create_f90_real smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_f90_real"); call MPI_Type_create_f90_real
+#define MPI_TYPE_CREATE_F90_REAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_F90_REAL"); call MPI_Type_create_f90_real
+#define mpi_type_create_f90_complex smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_f90_complex"); call MPI_Type_create_f90_complex
+#define MPI_TYPE_CREATE_F90_COMPLEX smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_F90_COMPLEX"); call MPI_Type_create_f90_complex
+#define mpi_type_get_contents smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_get_contents"); call MPI_Type_get_contents
+#define MPI_TYPE_GET_CONTENTS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_GET_CONTENTS"); call MPI_Type_get_contents
+#define mpi_type_get_envelope smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_get_envelope"); call MPI_Type_get_envelope
+#define MPI_TYPE_GET_ENVELOPE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_GET_ENVELOPE"); call MPI_Type_get_envelope
+#define mpi_file_call_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_call_errhandler"); call MPI_File_call_errhandler
+#define MPI_FILE_CALL_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_CALL_ERRHANDLER"); call MPI_File_call_errhandler
+#define mpi_file_create_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_create_errhandler"); call MPI_File_create_errhandler
+#define MPI_FILE_CREATE_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_CREATE_ERRHANDLER"); call MPI_File_create_errhandler
+#define mpi_file_set_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_set_errhandler"); call MPI_File_set_errhandler
+#define MPI_FILE_SET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_SET_ERRHANDLER"); call MPI_File_set_errhandler
+#define mpi_file_get_errhandler smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_errhandler"); call MPI_File_get_errhandler
+#define MPI_FILE_GET_ERRHANDLER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_ERRHANDLER"); call MPI_File_get_errhandler
+#define mpi_cart_map smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_cart_map"); call MPI_Cart_map
+#define MPI_CART_MAP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CART_MAP"); call MPI_Cart_map
+#define mpi_graph_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_graph_create"); call MPI_Graph_create
+#define MPI_GRAPH_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GRAPH_CREATE"); call MPI_Graph_create
+#define mpi_graph_get smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_graph_get"); call MPI_Graph_get
+#define MPI_GRAPH_GET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GRAPH_GET"); call MPI_Graph_get
+#define mpi_graph_map smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_graph_map"); call MPI_Graph_map
+#define MPI_GRAPH_MAP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GRAPH_MAP"); call MPI_Graph_map
+#define mpi_graph_neighbors smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_graph_neighbors"); call MPI_Graph_neighbors
+#define MPI_GRAPH_NEIGHBORS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GRAPH_NEIGHBORS"); call MPI_Graph_neighbors
+#define mpi_graph_neighbors_count smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_graph_neighbors_count"); call MPI_Graph_neighbors_count
+#define MPI_GRAPH_NEIGHBORS_COUNT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GRAPH_NEIGHBORS_COUNT"); call MPI_Graph_neighbors_count
+#define mpi_graphdims_get smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_graphdims_get"); call MPI_Graphdims_get
+#define MPI_GRAPHDIMS_GET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GRAPHDIMS_GET"); call MPI_Graphdims_get
+#define mpi_topo_test smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_topo_test"); call MPI_Topo_test
+#define MPI_TOPO_TEST smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TOPO_TEST"); call MPI_Topo_test
+#define mpi_add_error_class smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_add_error_class"); call MPI_Add_error_class
+#define MPI_ADD_ERROR_CLASS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ADD_ERROR_CLASS"); call MPI_Add_error_class
+#define mpi_add_error_code smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_add_error_code"); call MPI_Add_error_code
+#define MPI_ADD_ERROR_CODE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ADD_ERROR_CODE"); call MPI_Add_error_code
+#define mpi_add_error_string smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_add_error_string"); call MPI_Add_error_string
+#define MPI_ADD_ERROR_STRING smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_ADD_ERROR_STRING"); call MPI_Add_error_string
+#define mpi_comm_test_inter smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_test_inter"); call MPI_Comm_test_inter
+#define MPI_COMM_TEST_INTER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_TEST_INTER"); call MPI_Comm_test_inter
+#define mpi_intercomm_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_intercomm_create"); call MPI_Intercomm_create
+#define MPI_INTERCOMM_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INTERCOMM_CREATE"); call MPI_Intercomm_create
+#define mpi_intercomm_merge smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_intercomm_merge"); call MPI_Intercomm_merge
+#define MPI_INTERCOMM_MERGE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INTERCOMM_MERGE"); call MPI_Intercomm_merge
+#define mpi_comm_remote_group smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_remote_group"); call MPI_Comm_remote_group
+#define MPI_COMM_REMOTE_GROUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_REMOTE_GROUP"); call MPI_Comm_remote_group
+#define mpi_comm_remote_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_remote_size"); call MPI_Comm_remote_size
+#define MPI_COMM_REMOTE_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_REMOTE_SIZE"); call MPI_Comm_remote_size
+#define mpi_get_elements smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get_elements"); call MPI_Get_elements
+#define MPI_GET_ELEMENTS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET_ELEMENTS"); call MPI_Get_elements
+#define mpi_get_elements_x smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_get_elements_x"); call MPI_Get_elements_x
+#define MPI_GET_ELEMENTS_X smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_GET_ELEMENTS_X"); call MPI_Get_elements_x
+#define mpi_pcontrol smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_pcontrol"); call MPI_Pcontrol
+#define MPI_PCONTROL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PCONTROL"); call MPI_Pcontrol
+#define mpi_type_create_darray smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_create_darray"); call MPI_Type_create_darray
+#define MPI_TYPE_CREATE_DARRAY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_CREATE_DARRAY"); call MPI_Type_create_darray
+#define mpi_pack_external_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_pack_external_size"); call MPI_Pack_external_size
+#define MPI_PACK_EXTERNAL_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PACK_EXTERNAL_SIZE"); call MPI_Pack_external_size
+#define mpi_pack_external smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_pack_external"); call MPI_Pack_external
+#define MPI_PACK_EXTERNAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PACK_EXTERNAL"); call MPI_Pack_external
+#define mpi_unpack_external smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_unpack_external"); call MPI_Unpack_external
+#define MPI_UNPACK_EXTERNAL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_UNPACK_EXTERNAL"); call MPI_Unpack_external
+#define mpi_type_match_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_type_match_size"); call MPI_Type_match_size
+#define MPI_TYPE_MATCH_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_TYPE_MATCH_SIZE"); call MPI_Type_match_size
+#define mpi_comm_connect smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_connect"); call MPI_Comm_connect
+#define MPI_COMM_CONNECT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_CONNECT"); call MPI_Comm_connect
+#define mpi_unpublish_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_unpublish_name"); call MPI_Unpublish_name
+#define MPI_UNPUBLISH_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_UNPUBLISH_NAME"); call MPI_Unpublish_name
+#define mpi_publish_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_publish_name"); call MPI_Publish_name
+#define MPI_PUBLISH_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PUBLISH_NAME"); call MPI_Publish_name
+#define mpi_lookup_name smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_lookup_name"); call MPI_Lookup_name
+#define MPI_LOOKUP_NAME smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_LOOKUP_NAME"); call MPI_Lookup_name
+#define mpi_comm_idup smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_idup"); call MPI_Comm_idup
+#define MPI_COMM_IDUP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_IDUP"); call MPI_Comm_idup
+#define mpi_comm_join smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_join"); call MPI_Comm_join
+#define MPI_COMM_JOIN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_JOIN"); call MPI_Comm_join
+#define mpi_open_port smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_open_port"); call MPI_Open_port
+#define MPI_OPEN_PORT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_OPEN_PORT"); call MPI_Open_port
+#define mpi_close_port smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_close_port"); call MPI_Close_port
+#define MPI_CLOSE_PORT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_CLOSE_PORT"); call MPI_Close_port
+#define mpi_comm_accept smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_accept"); call MPI_Comm_accept
+#define MPI_COMM_ACCEPT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_ACCEPT"); call MPI_Comm_accept
+#define mpi_comm_spawn smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_spawn"); call MPI_Comm_spawn
+#define MPI_COMM_SPAWN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SPAWN"); call MPI_Comm_spawn
+#define mpi_comm_spawn_multiple smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_spawn_multiple"); call MPI_Comm_spawn_multiple
+#define MPI_COMM_SPAWN_MULTIPLE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_SPAWN_MULTIPLE"); call MPI_Comm_spawn_multiple
+#define mpi_comm_get_parent smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_comm_get_parent"); call MPI_Comm_get_parent
+#define MPI_COMM_GET_PARENT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_COMM_GET_PARENT"); call MPI_Comm_get_parent
+#define mpi_dist_graph_create smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_dist_graph_create"); call MPI_Dist_graph_create
+#define MPI_DIST_GRAPH_CREATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_DIST_GRAPH_CREATE"); call MPI_Dist_graph_create
+#define mpi_dist_graph_create_adjacent smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_dist_graph_create_adjacent"); call MPI_Dist_graph_create_adjacent
+#define MPI_DIST_GRAPH_CREATE_ADJACENT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_DIST_GRAPH_CREATE_ADJACENT"); call MPI_Dist_graph_create_adjacent
+#define mpi_dist_graph_neighbors smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_dist_graph_neighbors"); call MPI_Dist_graph_neighbors
+#define MPI_DIST_GRAPH_NEIGHBORS smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_DIST_GRAPH_NEIGHBORS"); call MPI_Dist_graph_neighbors
+#define mpi_dist_graph_neighbors_count smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_dist_graph_neighbors_count"); call MPI_Dist_graph_neighbors_count
+#define MPI_DIST_GRAPH_NEIGHBORS_COUNT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_DIST_GRAPH_NEIGHBORS_COUNT"); call MPI_Dist_graph_neighbors_count
+#define mpi_win_test smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_win_test"); call MPI_Win_test
+#define MPI_WIN_TEST smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_WIN_TEST"); call MPI_Win_test
+#define mpi_file_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_c2f"); call MPI_File_c2f
+#define MPI_FILE_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_C2F"); call MPI_File_c2f
+#define mpi_file_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_f2c"); call MPI_File_f2c
+#define MPI_FILE_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_F2C"); call MPI_File_f2c
+#define mpi_register_datarep smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_register_datarep"); call MPI_Register_datarep
+#define MPI_REGISTER_DATAREP smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_REGISTER_DATAREP"); call MPI_Register_datarep
+#define mpi_file_set_size smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_set_size"); call MPI_File_set_size
+#define MPI_FILE_SET_SIZE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_SET_SIZE"); call MPI_File_set_size
+#define mpi_file_preallocate smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_preallocate"); call MPI_File_preallocate
+#define MPI_FILE_PREALLOCATE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_PREALLOCATE"); call MPI_File_preallocate
+#define mpi_file_iread_at smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iread_at"); call MPI_File_iread_at
+#define MPI_FILE_IREAD_AT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IREAD_AT"); call MPI_File_iread_at
+#define mpi_file_iwrite_at smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iwrite_at"); call MPI_File_iwrite_at
+#define MPI_FILE_IWRITE_AT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IWRITE_AT"); call MPI_File_iwrite_at
+#define mpi_file_iread_at_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iread_at_all"); call MPI_File_iread_at_all
+#define MPI_FILE_IREAD_AT_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IREAD_AT_ALL"); call MPI_File_iread_at_all
+#define mpi_file_iwrite_at_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iwrite_at_all"); call MPI_File_iwrite_at_all
+#define MPI_FILE_IWRITE_AT_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IWRITE_AT_ALL"); call MPI_File_iwrite_at_all
+#define mpi_file_iread smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iread"); call MPI_File_iread
+#define MPI_FILE_IREAD smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IREAD"); call MPI_File_iread
+#define mpi_file_iwrite smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iwrite"); call MPI_File_iwrite
+#define MPI_FILE_IWRITE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IWRITE"); call MPI_File_iwrite
+#define mpi_file_iread_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iread_all"); call MPI_File_iread_all
+#define MPI_FILE_IREAD_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IREAD_ALL"); call MPI_File_iread_all
+#define mpi_file_iwrite_all smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iwrite_all"); call MPI_File_iwrite_all
+#define MPI_FILE_IWRITE_ALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IWRITE_ALL"); call MPI_File_iwrite_all
+#define mpi_file_get_byte_offset smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_byte_offset"); call MPI_File_get_byte_offset
+#define MPI_FILE_GET_BYTE_OFFSET smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_BYTE_OFFSET"); call MPI_File_get_byte_offset
+#define mpi_file_iread_shared smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iread_shared"); call MPI_File_iread_shared
+#define MPI_FILE_IREAD_SHARED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IREAD_SHARED"); call MPI_File_iread_shared
+#define mpi_file_iwrite_shared smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_iwrite_shared"); call MPI_File_iwrite_shared
+#define MPI_FILE_IWRITE_SHARED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_IWRITE_SHARED"); call MPI_File_iwrite_shared
+#define mpi_file_read_at_all_begin smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_at_all_begin"); call MPI_File_read_at_all_begin
+#define MPI_FILE_READ_AT_ALL_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_AT_ALL_BEGIN"); call MPI_File_read_at_all_begin
+#define mpi_file_read_at_all_end smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_at_all_end"); call MPI_File_read_at_all_end
+#define MPI_FILE_READ_AT_ALL_END smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_AT_ALL_END"); call MPI_File_read_at_all_end
+#define mpi_file_write_at_all_begin smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_at_all_begin"); call MPI_File_write_at_all_begin
+#define MPI_FILE_WRITE_AT_ALL_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_AT_ALL_BEGIN"); call MPI_File_write_at_all_begin
+#define mpi_file_write_at_all_end smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_at_all_end"); call MPI_File_write_at_all_end
+#define MPI_FILE_WRITE_AT_ALL_END smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_AT_ALL_END"); call MPI_File_write_at_all_end
+#define mpi_file_read_all_begin smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_all_begin"); call MPI_File_read_all_begin
+#define MPI_FILE_READ_ALL_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_ALL_BEGIN"); call MPI_File_read_all_begin
+#define mpi_file_read_all_end smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_all_end"); call MPI_File_read_all_end
+#define MPI_FILE_READ_ALL_END smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_ALL_END"); call MPI_File_read_all_end
+#define mpi_file_write_all_begin smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_all_begin"); call MPI_File_write_all_begin
+#define MPI_FILE_WRITE_ALL_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_ALL_BEGIN"); call MPI_File_write_all_begin
+#define mpi_file_write_all_end smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_all_end"); call MPI_File_write_all_end
+#define MPI_FILE_WRITE_ALL_END smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_ALL_END"); call MPI_File_write_all_end
+#define mpi_file_read_ordered_begin smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_ordered_begin"); call MPI_File_read_ordered_begin
+#define MPI_FILE_READ_ORDERED_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_ORDERED_BEGIN"); call MPI_File_read_ordered_begin
+#define mpi_file_read_ordered_end smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_read_ordered_end"); call MPI_File_read_ordered_end
+#define MPI_FILE_READ_ORDERED_END smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_READ_ORDERED_END"); call MPI_File_read_ordered_end
+#define mpi_file_write_ordered_begin smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_ordered_begin"); call MPI_File_write_ordered_begin
+#define MPI_FILE_WRITE_ORDERED_BEGIN smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_ORDERED_BEGIN"); call MPI_File_write_ordered_begin
+#define mpi_file_write_ordered_end smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_write_ordered_end"); call MPI_File_write_ordered_end
+#define MPI_FILE_WRITE_ORDERED_END smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_WRITE_ORDERED_END"); call MPI_File_write_ordered_end
+#define mpi_file_get_type_extent smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_type_extent"); call MPI_File_get_type_extent
+#define MPI_FILE_GET_TYPE_EXTENT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_TYPE_EXTENT"); call MPI_File_get_type_extent
+#define mpi_file_set_atomicity smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_set_atomicity"); call MPI_File_set_atomicity
+#define MPI_FILE_SET_ATOMICITY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_SET_ATOMICITY"); call MPI_File_set_atomicity
+#define mpi_file_get_atomicity smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_file_get_atomicity"); call MPI_File_get_atomicity
+#define MPI_FILE_GET_ATOMICITY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_FILE_GET_ATOMICITY"); call MPI_File_get_atomicity
+#define mpi_message_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_message_f2c"); call MPI_Message_f2c
+#define MPI_MESSAGE_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_MESSAGE_F2C"); call MPI_Message_f2c
+#define mpi_message_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_message_c2f"); call MPI_Message_c2f
+#define MPI_MESSAGE_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_MESSAGE_C2F"); call MPI_Message_c2f
+#define mpi_mrecv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_mrecv"); call MPI_Mrecv
+#define MPI_MRECV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_MRECV"); call MPI_Mrecv
+#define mpi_mprobe smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_mprobe"); call MPI_Mprobe
+#define MPI_MPROBE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_MPROBE"); call MPI_Mprobe
+#define mpi_imrecv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_imrecv"); call MPI_Imrecv
+#define MPI_IMRECV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IMRECV"); call MPI_Imrecv
+#define mpi_improbe smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_improbe"); call MPI_Improbe
+#define MPI_IMPROBE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_IMPROBE"); call MPI_Improbe
+#define mpi_neighbor_allgather smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_neighbor_allgather"); call MPI_Neighbor_allgather
+#define MPI_NEIGHBOR_ALLGATHER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_NEIGHBOR_ALLGATHER"); call MPI_Neighbor_allgather
+#define mpi_neighbor_allgatherv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_neighbor_allgatherv"); call MPI_Neighbor_allgatherv
+#define MPI_NEIGHBOR_ALLGATHERV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_NEIGHBOR_ALLGATHERV"); call MPI_Neighbor_allgatherv
+#define mpi_neighbor_alltoall smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_neighbor_alltoall"); call MPI_Neighbor_alltoall
+#define MPI_NEIGHBOR_ALLTOALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_NEIGHBOR_ALLTOALL"); call MPI_Neighbor_alltoall
+#define mpi_neighbor_alltoallv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_neighbor_alltoallv"); call MPI_Neighbor_alltoallv
+#define MPI_NEIGHBOR_ALLTOALLV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_NEIGHBOR_ALLTOALLV"); call MPI_Neighbor_alltoallv
+#define mpi_neighbor_alltoallw smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_neighbor_alltoallw"); call MPI_Neighbor_alltoallw
+#define MPI_NEIGHBOR_ALLTOALLW smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_NEIGHBOR_ALLTOALLW"); call MPI_Neighbor_alltoallw
+#define mpi_ineighbor_allgather smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ineighbor_allgather"); call MPI_Ineighbor_allgather
+#define MPI_INEIGHBOR_ALLGATHER smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INEIGHBOR_ALLGATHER"); call MPI_Ineighbor_allgather
+#define mpi_ineighbor_allgatherv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ineighbor_allgatherv"); call MPI_Ineighbor_allgatherv
+#define MPI_INEIGHBOR_ALLGATHERV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INEIGHBOR_ALLGATHERV"); call MPI_Ineighbor_allgatherv
+#define mpi_ineighbor_alltoall smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ineighbor_alltoall"); call MPI_Ineighbor_alltoall
+#define MPI_INEIGHBOR_ALLTOALL smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INEIGHBOR_ALLTOALL"); call MPI_Ineighbor_alltoall
+#define mpi_ineighbor_alltoallv smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ineighbor_alltoallv"); call MPI_Ineighbor_alltoallv
+#define MPI_INEIGHBOR_ALLTOALLV smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INEIGHBOR_ALLTOALLV"); call MPI_Ineighbor_alltoallv
+#define mpi_ineighbor_alltoallw smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_ineighbor_alltoallw"); call MPI_Ineighbor_alltoallw
+#define MPI_INEIGHBOR_ALLTOALLW smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_INEIGHBOR_ALLTOALLW"); call MPI_Ineighbor_alltoallw
+#define mpi_status_f2c smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_status_f2c"); call MPI_Status_f2c
+#define MPI_STATUS_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_STATUS_F2C"); call MPI_Status_f2c
+#define mpi_status_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_status_c2f"); call MPI_Status_c2f
+#define MPI_STATUS_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_STATUS_C2F"); call MPI_Status_c2f
+#define mpi_parrived smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_parrived"); call MPI_Parrived
+#define MPI_PARRIVED smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PARRIVED"); call MPI_Parrived
+#define mpi_pready smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_pready"); call MPI_Pready
+#define MPI_PREADY smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PREADY"); call MPI_Pready
+#define mpi_pready_range smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_pready_range"); call MPI_Pready_range
+#define MPI_PREADY_RANGE smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PREADY_RANGE"); call MPI_Pready_range
+#define mpi_pready_list smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_pready_list"); call MPI_Pready_list
+#define MPI_PREADY_LIST smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PREADY_LIST"); call MPI_Pready_list
+#define mpi_precv_init smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_precv_init"); call MPI_Precv_init
+#define MPI_PRECV_INIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PRECV_INIT"); call MPI_Precv_init
+#define mpi_psend_init smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_psend_init"); call MPI_Psend_init
+#define MPI_PSEND_INIT smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_PSEND_INIT"); call MPI_Psend_init
index edc04a9..ec5d479 100644 (file)
@@ -15,8 +15,8 @@
 #define sleep(x) smpi_sleep(x)
 #define usleep(x) smpi_usleep(x)
 #else
-#define sleep(x) (smpi_trace_set_call_location(__FILE__, __LINE__), smpi_sleep(x))
-#define usleep(x) (smpi_trace_set_call_location(__FILE__, __LINE__), smpi_usleep(x))
+#define sleep(x) (smpi_trace_set_call_location(__FILE__, __LINE__, "sleep"), smpi_sleep(x))
+#define usleep(x) (smpi_trace_set_call_location(__FILE__, __LINE__, "usleep"), smpi_usleep(x))
 #endif
 
 #define gettimeofday(x, y) smpi_gettimeofday((x), 0)
@@ -24,7 +24,7 @@
 #ifndef TRACE_CALL_LOCATION /* Defined by smpicc on the command line */
 #define nanosleep(x, y) smpi_nanosleep((x), (y))
 #else
-#define nanosleep(x) (smpi_trace_set_call_location(__FILE__, __LINE__), smpi_nanosleep(x))
+#define nanosleep(x) (smpi_trace_set_call_location(__FILE__, __LINE__, "nanosleep"), smpi_nanosleep(x))
 #endif
 #define clock_gettime(x, y) smpi_clock_gettime((x), (y))
 #endif
index eb205de..54adb3e 100644 (file)
@@ -7,14 +7,13 @@
 #ifndef SIMGRID_XBT_LIB_HPP
 #define SIMGRID_XBT_LIB_HPP
 
-#include "xbt/base.h" // XBT_ATTRIB_DEPRECATED_v334
 #include <cstddef>
 #include <functional>
 #include <limits>
+#include <memory>
 #include <vector>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 template<class T, class U> class Extension;
 template<class T>          class Extendable;
@@ -110,10 +109,8 @@ public:
     extensions_[0]=data;
   }
   template <typename D> D* get_data() const { return static_cast<D*>(extensions_[0]); }
-  XBT_ATTRIB_DEPRECATED_v334("Please use typed template Extendable::get_data<>()") void* get_data() const
-  {
-    return get_data<void>();
-  }
+  template <typename D> std::unique_ptr<D> get_unique_data() { return std::unique_ptr<D>(get_data<D>()); }
+
   // Convenience extension access when the type has an associated EXTENSION ID:
   template <class U> U* extension() const { return extension<U>(U::EXTENSION_ID); }
   template<class U> void extension_set(U* p) { extension_set<U>(U::EXTENSION_ID, p); }
@@ -121,7 +118,6 @@ public:
 
 // Initialized with a first element, to save space for void* user data
 template <class T> std::vector<std::function<void(void*)>> Extendable<T>::deleters_{1};
-}
-}
+} // namespace simgrid::xbt
 
 #endif
index 90ffbea..623a35a 100644 (file)
@@ -10,8 +10,7 @@
 #include <string>
 #include <unordered_map>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 /** @brief a PropertyHolder can be given a set of textual properties
  *
@@ -32,7 +31,6 @@ public:
   template <class Assoc> void set_properties(const Assoc& properties);
 };
 
-} // namespace xbt
-} // namespace simgrid
+} // namespace simgrid::xbt
 
 #endif
diff --git a/include/xbt/automaton.h b/include/xbt/automaton.h
deleted file mode 100644 (file)
index 582b2fd..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/* Copyright (c) 2011-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef XBT_AUTOMATON_H
-#define XBT_AUTOMATON_H
-
-#include <xbt/dynar.h>
-
-SG_BEGIN_DECL
-
-typedef struct xbt_automaton_state {
-  char* id;
-  int type; /* -1 = init, 0 = inter, 1 = final */
-  xbt_dynar_t in;
-  xbt_dynar_t out;
-} s_xbt_automaton_state;
-
-typedef struct xbt_automaton_state* xbt_automaton_state_t;
-typedef const struct xbt_automaton_state* const_xbt_automaton_state_t;
-
-typedef struct xbt_automaton {
-  xbt_dynar_t propositional_symbols;
-  xbt_dynar_t transitions;
-  xbt_dynar_t states;
-  xbt_automaton_state_t current_state;
-} s_xbt_automaton;
-
-typedef struct xbt_automaton* xbt_automaton_t;
-typedef const struct xbt_automaton* const_xbt_automaton_t;
-
-typedef struct xbt_automaton_exp_label{
-  enum{AUT_OR=0, AUT_AND=1, AUT_NOT=2, AUT_PREDICAT=3, AUT_ONE=4} type;
-  union{
-    struct{
-      struct xbt_automaton_exp_label* left_exp;
-      struct xbt_automaton_exp_label* right_exp;
-    }or_and;
-    struct xbt_automaton_exp_label* exp_not;
-    char* predicat;
-  }u;
-} s_xbt_automaton_exp_label;
-
-typedef struct xbt_automaton_exp_label* xbt_automaton_exp_label_t;
-typedef const struct xbt_automaton_exp_label* const_xbt_automaton_exp_label_t;
-
-typedef struct xbt_automaton_transition {
-  xbt_automaton_state_t src;
-  xbt_automaton_state_t dst;
-  xbt_automaton_exp_label_t label;
-} s_xbt_automaton_transition;
-
-typedef struct xbt_automaton_transition* xbt_automaton_transition_t;
-typedef const struct xbt_automaton_transition* const_xbt_automaton_transition_t;
-
-typedef struct xbt_automaton_propositional_symbol* xbt_automaton_propositional_symbol_t;
-typedef const struct xbt_automaton_propositional_symbol* const_xbt_automaton_propositional_symbol_t;
-
-typedef int (*xbt_automaton_propositional_symbol_callback_type)(void*);
-typedef void (*xbt_automaton_propositional_symbol_free_function_type)(void*);
-
-XBT_PUBLIC xbt_automaton_t xbt_automaton_new(void);
-XBT_PUBLIC void xbt_automaton_load(xbt_automaton_t automaton, const char* file);
-XBT_PUBLIC xbt_automaton_state_t xbt_automaton_state_new(const_xbt_automaton_t a, int type, const char* id);
-XBT_PUBLIC xbt_automaton_transition_t xbt_automaton_transition_new(const_xbt_automaton_t a, xbt_automaton_state_t src,
-                                                                   xbt_automaton_state_t dst,
-                                                                   xbt_automaton_exp_label_t label);
-XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_or(xbt_automaton_exp_label_t left,
-                                                                    xbt_automaton_exp_label_t right);
-XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_and(xbt_automaton_exp_label_t left,
-                                                                     xbt_automaton_exp_label_t right);
-XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_not(xbt_automaton_exp_label_t exp_not);
-XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_predicat(const char* p);
-XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_one(void);
-XBT_PUBLIC xbt_dynar_t xbt_automaton_get_states(const_xbt_automaton_t a);
-XBT_PUBLIC xbt_dynar_t xbt_automaton_get_transitions(const_xbt_automaton_t a);
-XBT_PUBLIC xbt_automaton_transition_t xbt_automaton_get_transition(const_xbt_automaton_t a,
-                                                                   const_xbt_automaton_state_t src,
-                                                                   const_xbt_automaton_state_t dst);
-XBT_PUBLIC xbt_automaton_state_t xbt_automaton_transition_get_source(const_xbt_automaton_transition_t t);
-XBT_PUBLIC xbt_automaton_state_t xbt_automaton_transition_get_destination(const_xbt_automaton_transition_t t);
-XBT_PUBLIC void xbt_automaton_transition_set_source(xbt_automaton_transition_t t, xbt_automaton_state_t src);
-XBT_PUBLIC void xbt_automaton_transition_set_destination(xbt_automaton_transition_t t, xbt_automaton_state_t dst);
-XBT_PUBLIC xbt_dynar_t xbt_automaton_state_get_out_transitions(const_xbt_automaton_state_t s);
-XBT_PUBLIC xbt_dynar_t xbt_automaton_state_get_in_transitions(const_xbt_automaton_state_t s);
-XBT_PUBLIC xbt_automaton_state_t xbt_automaton_state_exists(const_xbt_automaton_t a, const char* id);
-XBT_PUBLIC void xbt_automaton_display(const_xbt_automaton_t a);
-XBT_PUBLIC void xbt_automaton_exp_label_display(const_xbt_automaton_exp_label_t l);
-
-// xbt_automaton_propositional_symbol constructors:
-XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new(const_xbt_automaton_t a,
-                                                                                       const char* id,
-                                                                                       int (*fct)(void));
-XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new_pointer(const_xbt_automaton_t a,
-                                                                                               const char* id,
-                                                                                               int* value);
-XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new_callback(
-    const_xbt_automaton_t a, const char* id, xbt_automaton_propositional_symbol_callback_type callback, void* data,
-    xbt_automaton_propositional_symbol_free_function_type free_function);
-
-// xbt_automaton_propositional_symbol accessors:
-XBT_PUBLIC xbt_automaton_propositional_symbol_callback_type
-xbt_automaton_propositional_symbol_get_callback(const_xbt_automaton_propositional_symbol_t symbol);
-XBT_PUBLIC void* xbt_automaton_propositional_symbol_get_data(const_xbt_automaton_propositional_symbol_t symbol);
-XBT_PUBLIC const char* xbt_automaton_propositional_symbol_get_name(const_xbt_automaton_propositional_symbol_t symbol);
-
-// xbt_automaton_propositional_symbol methods!
-XBT_PUBLIC int xbt_automaton_propositional_symbol_evaluate(const_xbt_automaton_propositional_symbol_t symbol);
-
-XBT_PUBLIC xbt_automaton_state_t xbt_automaton_get_current_state(const_xbt_automaton_t a);
-XBT_PUBLIC int xbt_automaton_state_compare(const_xbt_automaton_state_t s1, const_xbt_automaton_state_t s2);
-XBT_PUBLIC int xbt_automaton_propositional_symbols_compare_value(const_xbt_dynar_t s1, const_xbt_dynar_t s2);
-XBT_PUBLIC int xbt_automaton_transition_compare(const_xbt_automaton_transition_t t1,
-                                                const_xbt_automaton_transition_t t2);
-XBT_PUBLIC int xbt_automaton_exp_label_compare(const_xbt_automaton_exp_label_t l1, const_xbt_automaton_exp_label_t l2);
-XBT_PUBLIC void xbt_automaton_state_free_voidp(void* s);
-XBT_PUBLIC void xbt_automaton_state_free(xbt_automaton_state_t s);
-XBT_PUBLIC void xbt_automaton_transition_free_voidp(void* t);
-XBT_PUBLIC void xbt_automaton_exp_label_free_voidp(void* e);
-XBT_PUBLIC void xbt_automaton_propositional_symbol_free_voidp(void* ps);
-XBT_PUBLIC void xbt_automaton_free(xbt_automaton_t a);
-
-SG_END_DECL
-
-#endif
diff --git a/include/xbt/automaton.hpp b/include/xbt/automaton.hpp
deleted file mode 100644 (file)
index 8e2e857..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef XBT_AUTOMATON_HPP
-#define XBT_AUTOMATON_HPP
-
-#include <utility>
-
-#include <xbt/automaton.h>
-
-namespace simgrid {
-namespace xbt {
-
-/** Add a proposition to an automaton (the C++ way)
- *
- *  This API hides all the callback and dynamic allocation hell from
- *  the used which can use C++ style functors and lambda expressions.
- */
-template <class F> xbt_automaton_propositional_symbol_t add_proposition(const_xbt_automaton_t a, const char* id, F f)
-{
-  auto* callback = new F(std::move(f));
-  return xbt_automaton_propositional_symbol_new_callback(
-      a, id, [](auto* cb) -> int { return (*(F*)cb)(); }, callback, [](auto* cb) -> void { delete (F*)cb; });
-}
-
-}
-}
-#endif
index cda0da7..c220965 100644 (file)
@@ -17,8 +17,7 @@ SG_BEGIN_DECL
 XBT_PUBLIC void xbt_backtrace_display_current();
 SG_END_DECL
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 class BacktraceImpl;
 /** A backtrace
@@ -38,6 +37,5 @@ public:
   void display() const;
 };
 
-}
-}
+} // namespace simgrid::xbt
 #endif
index d39a948..ceb0fb2 100644 (file)
@@ -1,4 +1,4 @@
-/* xbt.h - Public interface to the xbt (simgrid's toolbox)                  */
+/* xbt.h - Public interface to the xbt (SimGrid's toolbox)                  */
 
 /* Copyright (c) 2004-2023. The SimGrid Team. All rights reserved.          */
 
 #define XBT_ATTRIB_DEPRECATED(mesg) __attribute__((deprecated(mesg)))
 #endif
 
-#define XBT_ATTRIB_DEPRECATED_v334(mesg)                                                                               \
-  XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.33)")
-#define XBT_ATTRIB_DEPRECATED_v335(mesg)                                                                               \
-  XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.34)")
-#define XBT_ATTRIB_DEPRECATED_v336(mesg)                                                                               \
-  XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.35)")
-#define XBT_ATTRIB_DEPRECATED_v337(mesg)                                                                               \
-  XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.36)")
+#define XBT_ATTRIB_DEPRECATED_v338(mesg)                                                                               \
+  XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.37)")
+#define XBT_ATTRIB_DEPRECATED_v339(mesg)                                                                               \
+  XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.38)")
+#define XBT_ATTRIB_DEPRECATED_v340(mesg)                                                                               \
+  XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.39)")
 
 /* Work around https://github.com/microsoft/vscode-cpptools/issues/4503 */
 #ifdef __INTELLISENSE__
index 8071dbd..bb5ee91 100644 (file)
@@ -22,8 +22,7 @@
 #include <xbt/sysdep.h>
 #include <xbt/utility.hpp>
 
-namespace simgrid {
-namespace config {
+namespace simgrid::config {
 
 class Config;
 
@@ -92,10 +91,10 @@ XBT_PUBLIC void alias(const char* realname, std::initializer_list<const char*> a
  */
 template <class T>
 XBT_PUBLIC void declare_flag(const std::string& name, const std::string& description, T value,
-                             std::function<void(const T&)> callback = std::function<void(const T&)>());
+                             std::function<void(const T&)> callback = nullptr);
 template <class T>
 void declare_flag(const std::string& name, std::initializer_list<const char*> aliases, const std::string& description,
-                  T value, std::function<void(const T&)> callback = std::function<void(const T&)>())
+                  T value, std::function<void(const T&)> callback = nullptr)
 {
   declare_flag(name, description, std::move(value), std::move(callback));
   alias(name.c_str(), aliases);
@@ -140,7 +139,7 @@ void bind_flag(T& value, const char* name, std::initializer_list<const char*> al
  */
 // F is a checker, F : T& -> ()
 template <class T, class F>
-typename std::enable_if_t<std::is_same<void, decltype(std::declval<F>()(std::declval<const T&>()))>::value, void>
+typename std::enable_if_t<std::is_same_v<void, decltype(std::declval<F>()(std::declval<const T&>()))>, void>
 bind_flag(T& value, const char* name, const char* description, F callback)
 {
   declare_flag(name, description, value, std::function<void(const T&)>([&value, callback](const T& val) {
@@ -150,7 +149,7 @@ bind_flag(T& value, const char* name, const char* description, F callback)
 }
 
 template <class T, class F>
-typename std::enable_if_t<std::is_same<void, decltype(std::declval<F>()(std::declval<const T&>()))>::value, void>
+typename std::enable_if_t<std::is_same_v<void, decltype(std::declval<F>()(std::declval<const T&>()))>, void>
 bind_flag(T& value, const char* name, std::initializer_list<const char*> aliases, const char* description, F callback)
 {
   bind_flag(value, name, description, std::move(callback));
@@ -158,8 +157,7 @@ bind_flag(T& value, const char* name, std::initializer_list<const char*> aliases
 }
 
 template <class F>
-typename std::enable_if_t<std::is_same<void, decltype(std::declval<F>()(std::declval<const std::string&>()))>::value,
-                          void>
+typename std::enable_if_t<std::is_same_v<void, decltype(std::declval<F>()(std::declval<const std::string&>()))>, void>
 bind_flag(std::string& value, const char* name, const char* description,
           const std::map<std::string, std::string, std::less<>>& valid_values, F callback)
 {
@@ -175,14 +173,13 @@ bind_flag(std::string& value, const char* name, const char* description,
                    mesg += std::string("Possible values for option ") + name + ":\n";
                  else
                    mesg += "Invalid value '" + val + "' for option " + name + ". Possible values:\n";
-                 for (auto const& kv : valid_values)
-                   mesg += "  - '" + kv.first + "': " + kv.second + (kv.first == value ? "  <=== DEFAULT" : "") + "\n";
+                 for (auto const& [v, descr] : valid_values)
+                   mesg += "  - '" + v + "': " + descr + (v == value ? "  <=== DEFAULT" : "") + "\n";
                  xbt_die("%s", mesg.c_str());
                }));
 }
 template <class F>
-typename std::enable_if_t<std::is_same<void, decltype(std::declval<F>()(std::declval<const std::string&>()))>::value,
-                          void>
+typename std::enable_if_t<std::is_same_v<void, decltype(std::declval<F>()(std::declval<const std::string&>()))>, void>
 bind_flag(std::string& value, const char* name, std::initializer_list<const char*> aliases, const char* description,
           const std::map<std::string, std::string, std::less<>>& valid_values, F callback)
 {
@@ -199,7 +196,7 @@ bind_flag(std::string& value, const char* name, std::initializer_list<const char
  */
 // F is a predicate, F : T const& -> bool
 template <class T, class F>
-typename std::enable_if_t<std::is_same<bool, decltype(std::declval<F>()(std::declval<const T&>()))>::value, void>
+typename std::enable_if_t<std::is_same_v<bool, decltype(std::declval<F>()(std::declval<const T&>()))>, void>
 bind_flag(T& value, const char* name, const char* description, F callback)
 {
   declare_flag(name, description, value, std::function<void(const T&)>([&value, callback](const T& val) {
@@ -261,6 +258,17 @@ public:
   /* A constructor accepting a map of valid values -> their description,
    * and producing an informative error message when an invalid value is passed, or when help is passed as a value.
    */
+  Flag(const char* name, const char* desc, xbt::type_identity_t<T> value,
+       const std::map<std::string, std::string, std::less<>>& valid_values)
+      : value_(value), name_(name)
+  {
+    simgrid::config::bind_flag(value_, name, desc, valid_values, [](const std::string&) {});
+  }
+
+  /* As earlier, a constructor accepting a map of valid values -> their description,
+   * and producing an informative error message when an invalid value is passed, or when help is passed as a value.
+   * But also take a callback that is invoked before the verification of parameter name validity.
+   */
   template <class F>
   Flag(const char* name, const char* desc, xbt::type_identity_t<T> value,
        const std::map<std::string, std::string, std::less<>>& valid_values, F callback)
@@ -314,7 +322,6 @@ XBT_PUBLIC void finalize();
 XBT_PUBLIC void show_aliases();
 XBT_PUBLIC void help();
 
-} // namespace config
-} // namespace simgrid
+} // namespace simgrid::config
 
 #endif
index d0447d3..afb2622 100644 (file)
@@ -10,8 +10,7 @@
 #include <vector>
 #include <xbt/base.h>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 void path_push(std::string const& str);
 void path_pop();
@@ -38,6 +37,6 @@ public:
 private:
   std::string path_;
 };
-}}
+} // namespace simgrid::xbt
 
 #endif                          /* XBT_FILE_HPP */
index 37dd5f5..16431a1 100644 (file)
@@ -22,6 +22,9 @@ typedef int (*int_f_int_pvoid_t)(int, void*);
 typedef int (*int_f_pvoid_pvoid_t) (void *, void *);
 typedef int (*int_f_cpvoid_cpvoid_t) (const void *, const void *);
 
+/** Prototype of an actor's main function
+ *
+ * The only difference with a classical main() in C is that the return type is void */
 typedef void (*xbt_main_func_t)(int argc, char* argv[]);
 
 SG_END_DECL
index eea2729..9d1b337 100644 (file)
@@ -23,8 +23,7 @@
 #include <utility>
 #include <vector>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 template <class F> class MainFunction {
   F code_;
@@ -74,12 +73,12 @@ constexpr auto apply(F&& f, Tuple&& t, std::index_sequence<I...>)
  *  @endcode
  **/
 template <class F, class Tuple>
-constexpr auto apply(F&& f, Tuple&& t) -> decltype(
-    simgrid::xbt::bits::apply(std::forward<F>(f), std::forward<Tuple>(t),
-                              std::make_index_sequence<std::tuple_size<typename std::decay_t<Tuple>>::value>()))
+constexpr auto apply(F&& f, Tuple&& t)
+    -> decltype(simgrid::xbt::bits::apply(std::forward<F>(f), std::forward<Tuple>(t),
+                                          std::make_index_sequence<std::tuple_size_v<typename std::decay_t<Tuple>>>()))
 {
   return simgrid::xbt::bits::apply(std::forward<F>(f), std::forward<Tuple>(t),
-                                   std::make_index_sequence<std::tuple_size<typename std::decay_t<Tuple>>::value>());
+                                   std::make_index_sequence<std::tuple_size_v<typename std::decay_t<Tuple>>>());
 }
 
 template<class T> class Task;
@@ -179,7 +178,7 @@ private:
         return code(std::forward<Args>(args)...);
       },
       // Destroy:
-      std::is_trivially_destructible<F>::value ?
+      std::is_trivially_destructible_v<F> ?
       static_cast<destroy_function>(nullptr) :
       [](TaskUnion& buffer) {
         auto* code = reinterpret_cast<F*>(&buffer);
@@ -260,6 +259,5 @@ template <class F, class... Args> auto make_task(F code, Args... args) -> Task<d
   return Task<decltype(code(std::move(args)...))()>(std::move(task));
 }
 
-} // namespace xbt
-} // namespace simgrid
+} // namespace simgrid::xbt
 #endif
index dabdbbe..e2598ed 100644 (file)
@@ -9,8 +9,7 @@
 #include <simgrid/Exception.hpp>
 #include <xbt/log.h>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 /** Display information about an exception
  *
@@ -23,7 +22,6 @@ XBT_PUBLIC void log_exception(e_xbt_log_priority_t priority, const char* context
 
 XBT_PUBLIC void install_exception_handler();
 
-} // namespace xbt
-} // namespace simgrid
+} // namespace simgrid::xbt
 
-#endif
\ No newline at end of file
+#endif
index da34afa..0c45e62 100644 (file)
@@ -1,4 +1,4 @@
-/* xbt.h - Public interface to the xbt (simgrid's toolbox)                  */
+/* xbt.h - Public interface to the xbt (SimGrid's toolbox)                  */
 
 /* Copyright (c) 2004-2023. The SimGrid Team. All rights reserved.          */
 
index ee9d548..601f7f4 100644 (file)
@@ -8,17 +8,15 @@
 #ifndef XBT_MODULE_H
 #define XBT_MODULE_H
 
-// avoid deprecation warning on include (remove entire file with XBT_ATTRIB_DEPRECATED_v337)
-#ifndef XBT_MODULE_H_NO_DEPRECATED_WARNING
-#warning xbt/module.h is deprecated and will be removed in v3.37.
-#endif
+// Deprecation warning on include (remove entire file with XBT_ATTRIB_DEPRECATED_v338)
+#warning xbt/module.h is deprecated and will be removed after v3.37.
 
 #include <simgrid/engine.h>
 #include <xbt/base.h>
 
 SG_BEGIN_DECL
 
-XBT_ATTRIB_DEPRECATED_v337("Please use simgrid_init(&argc, argv) instead") static void xbt_init(int* argc, char** argv)
+XBT_ATTRIB_DEPRECATED_v338("Please use simgrid_init(&argc, argv) instead") static void xbt_init(int* argc, char** argv)
 {
   simgrid_init(argc, argv);
 }
index 8926b20..dc19907 100644 (file)
@@ -17,8 +17,7 @@
 #include <utility>
 #include <xbt/ex.h>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 /** A value or an exception (or nothing)
  *
@@ -126,7 +125,6 @@ template <class P, class F> inline void set_promise(P& promise, F&& future)
 {
   fulfill_promise(promise, [&future] { return std::forward<F>(future).get(); });
 }
-}
-}
+} // namespace simgrid::xbt
 
 #endif
index 00f42ea..a5c4c79 100644 (file)
@@ -12,9 +12,7 @@
 #include <random>
 #include <string>
 
-namespace simgrid {
-namespace xbt {
-namespace random {
+namespace simgrid::xbt::random {
 
 /** A random number generator.
  *
@@ -162,8 +160,6 @@ double exponential(double lambda);
  * @param sd Standard deviation of the normal distribution
  */
 double normal(double mean, double sd);
-} // namespace random
-} // namespace xbt
-} // namespace simgrid
+} // namespace simgrid::xbt::random
 
 #endif
index 99eb0b1..47f021e 100644 (file)
@@ -8,8 +8,7 @@
 
 #include <algorithm>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 /** Describes a contiguous inclusive-exclusive [a,b) range of values */
 template<class T> class Range {
@@ -27,7 +26,6 @@ public:
   bool contain(T const& x) const { return begin_ <= x && end_ > x; }
 };
 
-}
-}
+} // namespace simgrid::xbt
 
 #endif
index 670d851..e6da188 100644 (file)
@@ -15,8 +15,7 @@
 #include <queue>
 #include <unordered_map>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 /* To split the file if a unique one is given (specific variable for the other case live in runner()) */
 using ReplayAction = std::vector<std::string>;
 
@@ -26,8 +25,7 @@ using ReplayAction = std::vector<std::string>;
  * xbt_replay_set_tracefile(). If trace_filename is not nullptr, then it's not shared and this trace file is for this
  * actor only */
 XBT_PUBLIC int replay_runner(const char* actor_name, const char* trace_filename = nullptr);
-}
-}
+} // namespace simgrid::xbt
 
 using action_fun = std::function<void(simgrid::xbt::ReplayAction&)>;
 XBT_PUBLIC void xbt_replay_action_register(const char* action_name, const action_fun& function);
index 8b6cf91..70c477f 100644 (file)
@@ -10,8 +10,7 @@
 #include <map>
 #include <utility>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 template <class S> class signal;
 
@@ -35,15 +34,14 @@ public:
   /** Fire that signal, invoking all callbacks */
   R operator()(P... args) const
   {
-    for (auto const& handler : handlers_)
-      handler.second(args...);
+    for (auto const& [_, callback] : handlers_)
+      callback(args...);
   }
   /** Remove a callback */
   void disconnect(unsigned int id) { handlers_.erase(id); }
   /** Remove all callbacks */
   void disconnect_slots() { handlers_.clear(); }
 };
-}
-}
+} // namespace simgrid::xbt
 
 #endif
index a58d27d..ff9d695 100644 (file)
@@ -12,8 +12,7 @@
 #include <cstdlib>
 #include <string>
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 /** Create a C++ string from a C-style format
  *
@@ -27,6 +26,5 @@ XBT_PUBLIC std::string string_printf(const char* fmt, ...) XBT_ATTRIB_PRINTF(1,
  */
 XBT_PUBLIC std::string string_vprintf(const char* fmt, va_list ap) XBT_ATTRIB_PRINTF(1, 0);
 
-} // namespace xbt
-}
-#endif
\ No newline at end of file
+} // namespace simgrid::xbt
+#endif
index e78e0bd..160fb7e 100644 (file)
@@ -22,7 +22,7 @@
 SG_BEGIN_DECL
 
 #ifdef XBT_LOG_LOCALLY_DEFINE_XBT_CHANNEL
-XBT_LOG_NEW_CATEGORY(xbt, "All XBT categories (simgrid toolbox)");
+XBT_LOG_NEW_CATEGORY(xbt, "All XBT categories (SimGrid toolbox)");
 XBT_LOG_NEW_SUBCATEGORY(xbt_help, xbt, "Help messages");
 #else
 XBT_LOG_EXTERNAL_CATEGORY(xbt);
index d5620b4..c94eaff 100644 (file)
@@ -11,8 +11,7 @@
 #ifndef SIMGRID_MC_SYSTEM_ERROR_HPP
 #define SIMGRID_MC_SYSTEM_ERROR_HPP
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 /** A `error_category` suitable to be used with `errno`
  *
@@ -82,7 +81,6 @@ std::system_error errno_error(const char* what)
   return std::system_error(errno_code(), what);
 }
 
-}
-}
+} // namespace simgrid::xbt
 
 #endif
index bb599d6..c35be72 100644 (file)
@@ -31,8 +31,7 @@
   }                                                                                                                    \
   enum class EnumType { __VA_ARGS__ } /* defined here to handle trailing semicolon */
 
-namespace simgrid {
-namespace xbt {
+namespace simgrid::xbt {
 
 /** @brief Replacement for C++20's std::type_identity_t
  */
@@ -80,6 +79,5 @@ template <class List, class Elem> inline void intrusive_erase(List& list, Elem&
   list.erase(list.iterator_to(elem));
 }
 
-} // namespace xbt
-} // namespace simgrid
+} // namespace simgrid::xbt
 #endif
index 0789a9a..53ccfaf 100644 (file)
 #include <simgrid/actor.h>
 #include <xbt/base.h>
 
-// avoid deprecation warning on include (remove entire file with XBT_ATTRIB_DEPRECATED_v337)
-#ifndef XBT_VIRTU_H_NO_DEPRECATED_WARNING
-#warning xbt/virtu.h is deprecated and will be removed in v3.37.
-#endif
+// Deprecation warning on include (remove entire file with XBT_ATTRIB_DEPRECATED_v338)
+#warning xbt/virtu.h is deprecated and will be removed after v3.37.
 
 SG_BEGIN_DECL
 
-XBT_ATTRIB_DEPRECATED_v337("Please use sg_actor_self_get_name()") static const char* xbt_procname(void)
+XBT_ATTRIB_DEPRECATED_v338("Please use sg_actor_self_get_name()") static const char* xbt_procname(void)
 {
   return sg_actor_self_get_name();
 }
 
-XBT_ATTRIB_DEPRECATED_v337("Please use sg_actor_self_get_pid()") static int xbt_getpid(void)
+XBT_ATTRIB_DEPRECATED_v338("Please use sg_actor_self_get_pid()") static int xbt_getpid(void)
 {
   return sg_actor_self_get_pid();
 };
index d5ad57b..241dd33 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -38,7 +38,7 @@ class CMakeBuild(build_ext):
 
         if not os.path.exists("MANIFEST.in"):
             raise RuntimeError(
-                "Please generate a MANIFEST.in file (configure simgrid, and copy it here if you build out of tree)")
+                "Please generate a MANIFEST.in file (configure SimGrid, and copy it here if you build out of tree)")
 
         for ext in self.extensions:
             self.build_extension(ext)
@@ -74,7 +74,7 @@ class CMakeBuild(build_ext):
 
 setup(
     name='simgrid',
-    version='3.32.1',
+    version='3.35.1',
     author='Da SimGrid Team',
     author_email='simgrid-community@inria.fr',
     description='Toolkit for scalable simulation of distributed applications',
index 4207696..a9d571e 100644 (file)
@@ -4,7 +4,7 @@
 sonar.organization=simgrid
 sonar.projectKey=simgrid_simgrid
 sonar.projectName=SimGrid
-sonar.projectVersion=3.32.1
+sonar.projectVersion=3.35.1
 
 sonar.links.homepage=https://simgrid.org
 sonar.links.issue=https://framagit.org/simgrid/simgrid/issues
@@ -14,7 +14,7 @@ sonar.sources=src,examples,include,teshsuite
 
 
 # Disable some rules on some files
-sonar.issue.ignore.multicriteria=c1,c2a,c2b,c3,c5a,c5b,c6a,c6b,c7,c8,c9,c10a,c10b,c10c,cex1a,cex1b,cex2a,cex2b,cex3,cex4,cxx17a,cxx17b,cxx17c,cxx17d,cxx17e,cxx17f,cxx17g,f1,p1,s1,s2,s3,s4,s5
+sonar.issue.ignore.multicriteria=c1,c2a,c2b,c3,c5a,c5b,c6a,c6b,c7,c8,c9,c10a,c10b,c10c,cex1a,cex1b,cex2a,cex2b,cex3,cex4,f1,p1,s1,s2,s3,s4,s5
 
 # Pointers should not be cast to integral types
 # But we need that for smpi and other places
@@ -95,30 +95,6 @@ sonar.issue.ignore.multicriteria.cex3.resourceKey=examples/**/*.c
 sonar.issue.ignore.multicriteria.cex4.ruleKey=c:S995
 sonar.issue.ignore.multicriteria.cex4.resourceKey=examples/**/*.c
 
-# Ignore these C++17 rules in public headers, where we still support C++14
-
-# C++17: Concise syntax should be used for concatenatable namespaces
-sonar.issue.ignore.multicriteria.cxx17a.ruleKey=cpp:S5812
-sonar.issue.ignore.multicriteria.cxx17a.resourceKey=include/**/*
-# C++17: "if","switch", and range-based for loop initializer should be used to reduce scope of variables
-sonar.issue.ignore.multicriteria.cxx17b.ruleKey=cpp:S6004
-sonar.issue.ignore.multicriteria.cxx17b.resourceKey=include/**/*.hpp
-# C++17: Structured binding should be used
-sonar.issue.ignore.multicriteria.cxx17c.ruleKey=cpp:S6005
-sonar.issue.ignore.multicriteria.cxx17c.resourceKey=include/**/*.hpp
-# C++17: "std::string_view" should be used to pass a read-only string to a function
-sonar.issue.ignore.multicriteria.cxx17d.ruleKey=cpp:S6009
-sonar.issue.ignore.multicriteria.cxx17d.resourceKey=include/**/*.hpp
-# C++17: Redundant class template arguments should not be used
-sonar.issue.ignore.multicriteria.cxx17e.ruleKey=cpp:S6012
-sonar.issue.ignore.multicriteria.cxx17e.resourceKey=include/**/*.hpp
-# C++17: The "_t" and "_v" version of type traits should be used instead of "::type" and "::value"
-sonar.issue.ignore.multicriteria.cxx17f.ruleKey=cpp:S6020
-sonar.issue.ignore.multicriteria.cxx17f.resourceKey=include/**/*.hpp
-# C++17: "std::scoped_lock" should be used instead of "std::lock_guard"
-sonar.issue.ignore.multicriteria.cxx17g.ruleKey=cpp:S5997
-sonar.issue.ignore.multicriteria.cxx17g.resourceKey=include/**/*.hpp
-
 # "reinterpret_cast" should not be used
 # But we need this to interface C and Fortran
 sonar.issue.ignore.multicriteria.f1.ruleKey=cpp:S3630
@@ -151,13 +127,13 @@ sonar.issue.ignore.multicriteria.s5.ruleKey=cpp:S995
 sonar.issue.ignore.multicriteria.s5.resourceKey=src/smpi/bindings/*.cpp
 
 # Exclude some files from the analysis:
-#  - the tests that we borrowed elsewhere (MPICH and MBI)
+#  - the tests that we borrowed elsewhere (MPICH, MBI, McMini)
 #  - Flex-generated files
 #  - Collectives that we borrowed elsewhere (mpich, openMPI and other implems)
 #  - the NAS, that are included in our examples
 #  - The Catch2 library, that is included in our unit tests
 #  - The xxHash library, used by the MC
-sonar.exclusions=src/3rd-party/*,teshsuite/smpi/mpich3-test/**,teshsuite/smpi/MBI/**,**/*_dtd.c,**/*_dtd.h,**/*yy.c,src/xbt/automaton/parserPromela.tab.*,src/smpi/colls/**/*,examples/smpi/NAS/*,examples/smpi/gemm/gemm.c
+sonar.exclusions=src/3rd-party/*,teshsuite/smpi/mpich3-test/**,teshsuite/smpi/MBI/**,teshsuite/mc/mcmini/**,**/*_dtd.c,**/*_dtd.h,**/*yy.c,src/smpi/colls/**/*,examples/smpi/NAS/*,examples/smpi/gemm/gemm.c
 
 # Exclude our examples from the duplication detection.
 # Examples are expected to be somehow repetitive
diff --git a/src/3rd-party/xxhash.hpp b/src/3rd-party/xxhash.hpp
deleted file mode 100644 (file)
index a3dbe98..0000000
+++ /dev/null
@@ -1,757 +0,0 @@
-#pragma once
-#include <array>
-#include <cstdint>
-#include <cstring>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include <iostream>
-
-/*
-xxHash - Extremely Fast Hash algorithm
-Header File
-Copyright (C) 2012-2018, Yann Collet.
-Copyright (C) 2017-2018, Piotr Pliszka.
-All rights reserved.
-
-BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-* Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-You can contact the author at :
-- xxHash source repository : https://github.com/Cyan4973/xxHash
-- xxHash C++ port repository : https://github.com/RedSpah/xxhash_cpp
-*/
-
-/* *************************************
- *  Tuning parameters
- ***************************************/
-/*!XXH_FORCE_MEMORY_ACCESS :
- * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
- * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
- * The below switch allow to select different access method for improved performance.
- * Method 0 (default) : use `memcpy()`. Safe and portable.
- * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
- *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
- * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
- *            It can generate buggy code on targets which do not support unaligned memory accesses.
- *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
- * See http://stackoverflow.com/a/32095106/646947 for details.
- * Prefer these methods in priority order (0 > 1 > 2)
- */
-#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
-#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) ||           \
-                          defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__))
-#define XXH_FORCE_MEMORY_ACCESS 2
-#elif defined(__INTEL_COMPILER) ||                                                                                     \
-    (defined(__GNUC__) && (defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) ||          \
-                           defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)))
-#define XXH_FORCE_MEMORY_ACCESS 1
-#endif
-#endif
-
-/*!XXH_FORCE_NATIVE_FORMAT :
- * By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
- * Results are therefore identical for little-endian and big-endian CPU.
- * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
- * Should endian-independence be of no importance for your application, you may set the #define below to 1,
- * to improve speed for Big-endian CPU.
- * This option has no impact on Little_Endian CPU.
- */
-#if !defined(XXH_FORCE_NATIVE_FORMAT) || (XXH_FORCE_NATIVE_FORMAT == 0) /* can be defined externally */
-#define XXH_FORCE_NATIVE_FORMAT 0
-#define XXH_CPU_LITTLE_ENDIAN 1
-#endif
-
-/*!XXH_FORCE_ALIGN_CHECK :
- * This is a minor performance trick, only useful with lots of very small keys.
- * It means : check for aligned/unaligned input.
- * The check costs one initial branch per hash;
- * set it to 0 when the input is guaranteed to be aligned,
- * or when alignment doesn't matter for performance.
- */
-#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
-#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
-#define XXH_FORCE_ALIGN_CHECK 0
-#else
-#define XXH_FORCE_ALIGN_CHECK 1
-#endif
-#endif
-
-/*!XXH_CPU_LITTLE_ENDIAN :
- * This is a CPU endian detection macro, will be
- * automatically set to 1 (little endian) if XXH_FORCE_NATIVE_FORMAT
- * is left undefined, XXH_FORCE_NATIVE_FORMAT is defined to 0, or if an x86/x86_64 compiler macro is defined.
- * If left undefined, endianness will be determined at runtime, at the cost of a slight one-time overhead
- * and a larger overhead due to get_endian() not being constexpr.
- */
-#ifndef XXH_CPU_LITTLE_ENDIAN
-#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
-#define XXH_CPU_LITTLE_ENDIAN 1
-#endif
-#endif
-
-/* *************************************
- *  Compiler Specific Options
- ***************************************/
-#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
-
-namespace xxh {
-/* *************************************
- *  Version
- ***************************************/
-constexpr int cpp_version_major   = 0;
-constexpr int cpp_version_minor   = 6;
-constexpr int cpp_version_release = 5;
-constexpr uint32_t version_number()
-{
-  return cpp_version_major * 10000 + cpp_version_minor * 100 + cpp_version_release;
-}
-
-namespace hash_t_impl {
-/* *************************************
- *  Basic Types - Detail
- ***************************************/
-
-using _hash32_underlying = uint32_t;
-using _hash64_underlying = uint64_t;
-
-template <size_t N> struct hash_type {
-  using type = void;
-};
-template <> struct hash_type<32> {
-  using type = _hash32_underlying;
-};
-template <> struct hash_type<64> {
-  using type = _hash64_underlying;
-};
-} // namespace hash_t_impl
-
-/* *************************************
- *  Basic Types - Public
- ***************************************/
-
-template <size_t N> using hash_t = typename hash_t_impl::hash_type<N>::type;
-using hash32_t                   = hash_t<32>;
-using hash64_t                   = hash_t<64>;
-
-/* *************************************
- *  Bit Functions - Public
- ***************************************/
-
-namespace bit_ops {
-/* ****************************************
- *  Intrinsics and Bit Operations
- ******************************************/
-
-#if defined(_MSC_VER)
-inline uint32_t rotl32(uint32_t x, int32_t r)
-{
-  return _rotl(x, r);
-}
-inline uint64_t rotl64(uint64_t x, int32_t r)
-{
-  return _rotl64(x, r);
-}
-#else
-inline uint32_t rotl32(uint32_t x, int32_t r)
-{
-  return ((x << r) | (x >> (32 - r)));
-}
-inline uint64_t rotl64(uint64_t x, int32_t r)
-{
-  return ((x << r) | (x >> (64 - r)));
-}
-#endif
-
-#if defined(_MSC_VER) /* Visual Studio */
-inline uint32_t swap32(uint32_t x)
-{
-  return _byteswap_ulong(x);
-}
-inline uint64_t swap64(uint64_t x)
-{
-  return _byteswap_uint64(x);
-}
-#elif XXH_GCC_VERSION >= 403
-inline uint32_t swap32(uint32_t x)
-{
-  return __builtin_bswap32(x);
-}
-inline uint64_t swap64(uint64_t x)
-{
-  return __builtin_bswap64(x);
-}
-#else
-inline uint32_t swap32(uint32_t x)
-{
-  return ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff);
-}
-inline uint64_t swap64(uint64_t x)
-{
-  return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) |
-         ((x << 24) & 0x0000ff0000000000ULL) | ((x << 8) & 0x000000ff00000000ULL) | ((x >> 8) & 0x00000000ff000000ULL) |
-         ((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 40) & 0x000000000000ff00ULL) |
-         ((x >> 56) & 0x00000000000000ffULL);
-}
-#endif
-template <size_t N> inline hash_t<N> rotl(hash_t<N> n, int32_t r){};
-
-template <> inline hash_t<32> rotl<32>(hash_t<32> n, int32_t r)
-{
-  return rotl32(n, r);
-};
-
-template <> inline hash_t<64> rotl<64>(hash_t<64> n, int32_t r)
-{
-  return rotl64(n, r);
-};
-
-template <size_t N> inline hash_t<N> swap(hash_t<N> n){};
-
-template <> inline hash_t<32> swap<32>(hash_t<32> n)
-{
-  return swap32(n);
-};
-
-template <> inline hash_t<64> swap<64>(hash_t<64> n)
-{
-  return swap64(n);
-};
-} // namespace bit_ops
-
-/* *************************************
- *  Memory Functions - Public
- ***************************************/
-
-enum class alignment : uint8_t { aligned, unaligned };
-enum class endianness : uint8_t { big_endian = 0, little_endian = 1, unspecified = 2 };
-
-namespace mem_ops {
-/* *************************************
- *  Memory Access
- ***************************************/
-#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 2))
-
-/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
-template <size_t N> inline hash_t<N> read_unaligned(const void* memPtr)
-{
-  return *(const hash_t<N>*)memPtr;
-}
-
-#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS == 1))
-
-/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
-/* currently only defined for gcc and icc */
-template <size_t N> using unalign = union {
-  hash_t<N> uval;
-} __attribute((packed));
-
-template <size_t N> inline hash_t<N> read_unaligned(const void* memPtr)
-{
-  return ((const unalign*)memPtr)->uval;
-}
-#else
-
-/* portable and safe solution. Generally efficient.
- * see : http://stackoverflow.com/a/32095106/646947
- */
-template <size_t N> inline hash_t<N> read_unaligned(const void* memPtr)
-{
-  hash_t<N> val;
-  memcpy(&val, memPtr, sizeof(val));
-  return val;
-}
-
-#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
-
-inline hash_t<32> read32(const void* memPtr)
-{
-  return read_unaligned<32>(memPtr);
-}
-inline hash_t<64> read64(const void* memPtr)
-{
-  return read_unaligned<64>(memPtr);
-}
-
-/* *************************************
- *  Architecture Macros
- ***************************************/
-
-/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
-
-#ifndef XXH_CPU_LITTLE_ENDIAN
-
-inline endianness get_endian(endianness endian)
-{
-  static struct _dummy_t {
-    std::array<endianness, 3> endian_lookup = {endianness::big_endian, endianness::little_endian,
-                                               endianness::unspecified};
-    const int g_one                         = 1;
-    _dummy_t() { endian_lookup[2] = static_cast<endianness>(*(const char*)(&g_one)); }
-  } _dummy;
-
-  return _dummy.endian_lookup[(uint8_t)endian];
-}
-
-inline bool is_little_endian()
-{
-  return get_endian(endianness::unspecified) == endianness::little_endian;
-}
-
-#else
-constexpr endianness get_endian(endianness endian)
-{
-  constexpr std::array<endianness, 3> endian_lookup = {
-      {endianness::big_endian, endianness::little_endian,
-       (XXH_CPU_LITTLE_ENDIAN) ? endianness::little_endian : endianness::big_endian}};
-  return endian_lookup[static_cast<uint8_t>(endian)];
-}
-
-constexpr bool is_little_endian()
-{
-  return get_endian(endianness::unspecified) == endianness::little_endian;
-}
-
-#endif
-
-/* ***************************
- *  Memory reads
- *****************************/
-
-template <size_t N> inline hash_t<N> readLE_align(const void* ptr, endianness endian, alignment align)
-{
-  if (align == alignment::unaligned) {
-    return endian == endianness::little_endian ? read_unaligned<N>(ptr) : bit_ops::swap<N>(read_unaligned<N>(ptr));
-  } else {
-    return endian == endianness::little_endian ? *reinterpret_cast<const hash_t<N>*>(ptr)
-                                               : bit_ops::swap<N>(*reinterpret_cast<const hash_t<N>*>(ptr));
-  }
-}
-
-template <size_t N> inline hash_t<N> readLE(const void* ptr, endianness endian)
-{
-  return readLE_align<N>(ptr, endian, alignment::unaligned);
-}
-
-template <size_t N> inline hash_t<N> readBE(const void* ptr)
-{
-  return is_little_endian() ? bit_ops::swap<N>(read_unaligned<N>(ptr)) : read_unaligned<N>(ptr);
-}
-
-template <size_t N> inline alignment get_alignment(const void* input)
-{
-  return ((XXH_FORCE_ALIGN_CHECK) && ((reinterpret_cast<uintptr_t>(input) & ((N / 8) - 1)) == 0))
-             ? xxh::alignment::aligned
-             : xxh::alignment::unaligned;
-}
-} // namespace mem_ops
-
-/* *******************************************************************
- *  Hash functions
- *********************************************************************/
-
-namespace detail {
-/* *******************************************************************
- *  Hash functions - Implementation
- *********************************************************************/
-
-constexpr static std::array<hash32_t, 5> primes32 = {{2654435761U, 2246822519U, 3266489917U, 668265263U, 374761393U}};
-constexpr static std::array<hash64_t, 5> primes64 = {{11400714785074694791ULL, 14029467366897019727ULL,
-                                                      1609587929392839161ULL, 9650029242287828579ULL,
-                                                      2870177450012600261ULL}};
-
-template <size_t N> constexpr hash_t<N> PRIME(int32_t n){};
-
-template <> constexpr hash32_t PRIME<32>(int32_t n)
-{
-  return primes32[n - 1];
-}
-
-template <> constexpr hash64_t PRIME<64>(int32_t n)
-{
-  return primes64[n - 1];
-}
-
-template <size_t N> inline hash_t<N> round(hash_t<N> seed, hash_t<N> input)
-{
-  seed += input * PRIME<N>(2);
-  seed = bit_ops::rotl<N>(seed, ((N == 32) ? 13 : 31));
-  seed *= PRIME<N>(1);
-  return seed;
-}
-
-inline hash64_t mergeRound64(hash64_t acc, hash64_t val)
-{
-  val = round<64>(0, val);
-  acc ^= val;
-  acc = acc * PRIME<64>(1) + PRIME<64>(4);
-  return acc;
-}
-
-template <size_t N>
-inline void endian_align_sub_mergeround(
-#if __cplusplus < 201703L
-    __attribute__((unused))
-#else
-    [[maybe_unused]]
-#endif
-    hash_t<N>& hash_ret,
-    hash_t<N> v1, hash_t<N> v2, hash_t<N> v3, hash_t<N> v4){};
-
-template <>
-inline void endian_align_sub_mergeround<64>(hash_t<64>& hash_ret, hash_t<64> v1, hash_t<64> v2, hash_t<64> v3,
-                                            hash_t<64> v4)
-{
-  hash_ret = mergeRound64(hash_ret, v1);
-  hash_ret = mergeRound64(hash_ret, v2);
-  hash_ret = mergeRound64(hash_ret, v3);
-  hash_ret = mergeRound64(hash_ret, v4);
-}
-
-template <size_t N>
-inline hash_t<N> endian_align_sub_ending(hash_t<N> hash_ret, const uint8_t* p, const uint8_t* bEnd,
-                                         xxh::endianness endian, xxh::alignment align){};
-
-template <>
-inline hash_t<32> endian_align_sub_ending<32>(hash_t<32> hash_ret, const uint8_t* p, const uint8_t* bEnd,
-                                              xxh::endianness endian, xxh::alignment align)
-{
-  while ((p + 4) <= bEnd) {
-    hash_ret += mem_ops::readLE_align<32>(p, endian, align) * PRIME<32>(3);
-    hash_ret = bit_ops::rotl<32>(hash_ret, 17) * PRIME<32>(4);
-    p += 4;
-  }
-
-  while (p < bEnd) {
-    hash_ret += (*p) * PRIME<32>(5);
-    hash_ret = bit_ops::rotl<32>(hash_ret, 11) * PRIME<32>(1);
-    p++;
-  }
-
-  hash_ret ^= hash_ret >> 15;
-  hash_ret *= PRIME<32>(2);
-  hash_ret ^= hash_ret >> 13;
-  hash_ret *= PRIME<32>(3);
-  hash_ret ^= hash_ret >> 16;
-
-  return hash_ret;
-}
-
-template <>
-inline hash_t<64> endian_align_sub_ending<64>(hash_t<64> hash_ret, const uint8_t* p, const uint8_t* bEnd,
-                                              xxh::endianness endian, xxh::alignment align)
-{
-  while (p + 8 <= bEnd) {
-    const hash64_t k1 = round<64>(0, mem_ops::readLE_align<64>(p, endian, align));
-    hash_ret ^= k1;
-    hash_ret = bit_ops::rotl<64>(hash_ret, 27) * PRIME<64>(1) + PRIME<64>(4);
-    p += 8;
-  }
-
-  if (p + 4 <= bEnd) {
-    hash_ret ^= static_cast<hash64_t>(mem_ops::readLE_align<32>(p, endian, align)) * PRIME<64>(1);
-    hash_ret = bit_ops::rotl<64>(hash_ret, 23) * PRIME<64>(2) + PRIME<64>(3);
-    p += 4;
-  }
-
-  while (p < bEnd) {
-    hash_ret ^= (*p) * PRIME<64>(5);
-    hash_ret = bit_ops::rotl<64>(hash_ret, 11) * PRIME<64>(1);
-    p++;
-  }
-
-  hash_ret ^= hash_ret >> 33;
-  hash_ret *= PRIME<64>(2);
-  hash_ret ^= hash_ret >> 29;
-  hash_ret *= PRIME<64>(3);
-  hash_ret ^= hash_ret >> 32;
-
-  return hash_ret;
-}
-
-template <size_t N>
-inline hash_t<N> endian_align(const void* input, size_t len, hash_t<N> seed, xxh::endianness endian,
-                              xxh::alignment align)
-{
-  static_assert(!(N != 32 && N != 64), "You can only call endian_align in 32 or 64 bit mode.");
-
-  const uint8_t* p    = static_cast<const uint8_t*>(input);
-  const uint8_t* bEnd = p + len;
-  hash_t<N> hash_ret;
-
-  if (len >= (N / 2)) {
-    const uint8_t* const limit = bEnd - (N / 2);
-    hash_t<N> v1               = seed + PRIME<N>(1) + PRIME<N>(2);
-    hash_t<N> v2               = seed + PRIME<N>(2);
-    hash_t<N> v3               = seed + 0;
-    hash_t<N> v4               = seed - PRIME<N>(1);
-
-    do {
-      v1 = round<N>(v1, mem_ops::readLE_align<N>(p, endian, align));
-      p += (N / 8);
-      v2 = round<N>(v2, mem_ops::readLE_align<N>(p, endian, align));
-      p += (N / 8);
-      v3 = round<N>(v3, mem_ops::readLE_align<N>(p, endian, align));
-      p += (N / 8);
-      v4 = round<N>(v4, mem_ops::readLE_align<N>(p, endian, align));
-      p += (N / 8);
-    } while (p <= limit);
-
-    hash_ret = bit_ops::rotl<N>(v1, 1) + bit_ops::rotl<N>(v2, 7) + bit_ops::rotl<N>(v3, 12) + bit_ops::rotl<N>(v4, 18);
-
-    endian_align_sub_mergeround<N>(hash_ret, v1, v2, v3, v4);
-  } else {
-    hash_ret = seed + PRIME<N>(5);
-  }
-
-  hash_ret += static_cast<hash_t<N>>(len);
-
-  return endian_align_sub_ending<N>(hash_ret, p, bEnd, endian, align);
-}
-} // namespace detail
-
-template <size_t N>
-hash_t<N> xxhash(const void* input, size_t len, hash_t<N> seed = 0, endianness endian = endianness::unspecified)
-{
-  static_assert(!(N != 32 && N != 64), "You can only call xxhash in 32 or 64 bit mode.");
-  return detail::endian_align<N>(input, len, seed, mem_ops::get_endian(endian), mem_ops::get_alignment<N>(input));
-}
-
-template <size_t N, typename T>
-hash_t<N> xxhash(const std::basic_string<T>& input, hash_t<N> seed = 0, endianness endian = endianness::unspecified)
-{
-  static_assert(!(N != 32 && N != 64), "You can only call xxhash in 32 or 64 bit mode.");
-  return detail::endian_align<N>(static_cast<const void*>(input.data()), input.length() * sizeof(T), seed,
-                                 mem_ops::get_endian(endian),
-                                 mem_ops::get_alignment<N>(static_cast<const void*>(input.data())));
-}
-
-template <size_t N, typename ContiguousIterator>
-hash_t<N> xxhash(ContiguousIterator begin, ContiguousIterator end, hash_t<N> seed = 0,
-                 endianness endian = endianness::unspecified)
-{
-  static_assert(!(N != 32 && N != 64), "You can only call xxhash in 32 or 64 bit mode.");
-  using T = typename std::decay_t<decltype(*end)>;
-  return detail::endian_align<N>(static_cast<const void*>(&*begin), (end - begin) * sizeof(T), seed,
-                                 mem_ops::get_endian(endian),
-                                 mem_ops::get_alignment<N>(static_cast<const void*>(&*begin)));
-}
-
-template <size_t N, typename T>
-hash_t<N> xxhash(const std::vector<T>& input, hash_t<N> seed = 0, endianness endian = endianness::unspecified)
-{
-  static_assert(!(N != 32 && N != 64), "You can only call xxhash in 32 or 64 bit mode.");
-  return detail::endian_align<N>(static_cast<const void*>(input.data()), input.size() * sizeof(T), seed,
-                                 mem_ops::get_endian(endian),
-                                 mem_ops::get_alignment<N>(static_cast<const void*>(input.data())));
-}
-
-template <size_t N, typename T, size_t AN>
-hash_t<N> xxhash(const std::array<T, AN>& input, hash_t<N> seed = 0, endianness endian = endianness::unspecified)
-{
-  static_assert(!(N != 32 && N != 64), "You can only call xxhash in 32 or 64 bit mode.");
-  return detail::endian_align<N>(static_cast<const void*>(input.data()), AN * sizeof(T), seed,
-                                 mem_ops::get_endian(endian),
-                                 mem_ops::get_alignment<N>(static_cast<const void*>(input.data())));
-}
-
-template <size_t N, typename T>
-hash_t<N> xxhash(const std::initializer_list<T>& input, hash_t<N> seed = 0, endianness endian = endianness::unspecified)
-{
-  static_assert(!(N != 32 && N != 64), "You can only call xxhash in 32 or 64 bit mode.");
-  return detail::endian_align<N>(static_cast<const void*>(input.begin()), input.size() * sizeof(T), seed,
-                                 mem_ops::get_endian(endian),
-                                 mem_ops::get_alignment<N>(static_cast<const void*>(input.begin())));
-}
-
-/* *******************************************************************
- *  Hash streaming
- *********************************************************************/
-enum class error_code : uint8_t { ok = 0, error };
-
-template <size_t N> class hash_state_t {
-  uint64_t total_len = 0;
-  hash_t<N> v1 = 0, v2 = 0, v3 = 0, v4 = 0;
-  std::array<hash_t<N>, 4> mem = {{0, 0, 0, 0}};
-  uint32_t memsize             = 0;
-
-  inline error_code _update_impl(const void* input, size_t length, endianness endian)
-  {
-    const uint8_t* p          = reinterpret_cast<const uint8_t*>(input);
-    const uint8_t* const bEnd = p + length;
-
-    if (!input) {
-      return xxh::error_code::error;
-    }
-
-    total_len += length;
-
-    if (memsize + length < (N / 2)) { /* fill in tmp buffer */
-      memcpy(reinterpret_cast<uint8_t*>(mem.data()) + memsize, input, length);
-      memsize += static_cast<uint32_t>(length);
-      return error_code::ok;
-    }
-
-    if (memsize) { /* some data left from previous update */
-      memcpy(reinterpret_cast<uint8_t*>(mem.data()) + memsize, input, (N / 2) - memsize);
-
-      const hash_t<N>* ptr = mem.data();
-      v1                   = detail::round<N>(v1, mem_ops::readLE<N>(ptr, endian));
-      ptr++;
-      v2 = detail::round<N>(v2, mem_ops::readLE<N>(ptr, endian));
-      ptr++;
-      v3 = detail::round<N>(v3, mem_ops::readLE<N>(ptr, endian));
-      ptr++;
-      v4 = detail::round<N>(v4, mem_ops::readLE<N>(ptr, endian));
-
-      p += (N / 2) - memsize;
-      memsize = 0;
-    }
-
-    if (p <= bEnd - (N / 2)) {
-      const uint8_t* const limit = bEnd - (N / 2);
-
-      do {
-        v1 = detail::round<N>(v1, mem_ops::readLE<N>(p, endian));
-        p += (N / 8);
-        v2 = detail::round<N>(v2, mem_ops::readLE<N>(p, endian));
-        p += (N / 8);
-        v3 = detail::round<N>(v3, mem_ops::readLE<N>(p, endian));
-        p += (N / 8);
-        v4 = detail::round<N>(v4, mem_ops::readLE<N>(p, endian));
-        p += (N / 8);
-      } while (p <= limit);
-    }
-
-    if (p < bEnd) {
-      memcpy(mem.data(), p, static_cast<size_t>(bEnd - p));
-      memsize = static_cast<uint32_t>(bEnd - p);
-    }
-
-    return error_code::ok;
-  }
-
-  inline hash_t<N> _digest_impl(endianness endian) const
-  {
-    const uint8_t* p          = reinterpret_cast<const uint8_t*>(mem.data());
-    const uint8_t* const bEnd = reinterpret_cast<const uint8_t*>(mem.data()) + memsize;
-    hash_t<N> hash_ret;
-
-    if (total_len > (N / 2)) {
-      hash_ret =
-          bit_ops::rotl<N>(v1, 1) + bit_ops::rotl<N>(v2, 7) + bit_ops::rotl<N>(v3, 12) + bit_ops::rotl<N>(v4, 18);
-
-      detail::endian_align_sub_mergeround<N>(hash_ret, v1, v2, v3, v4);
-    } else {
-      hash_ret = v3 + detail::PRIME<N>(5);
-    }
-
-    hash_ret += static_cast<hash_t<N>>(total_len);
-
-    return detail::endian_align_sub_ending<N>(hash_ret, p, bEnd, endian, alignment::unaligned);
-  }
-
-public:
-  hash_state_t(hash_t<N> seed = 0)
-  {
-    static_assert(!(N != 32 && N != 64), "You can only stream hashing in 32 or 64 bit mode.");
-    v1 = seed + detail::PRIME<N>(1) + detail::PRIME<N>(2);
-    v2 = seed + detail::PRIME<N>(2);
-    v3 = seed + 0;
-    v4 = seed - detail::PRIME<N>(1);
-  };
-
-  hash_state_t operator=(hash_state_t<N>& other) { memcpy(this, other, sizeof(hash_state_t<N>)); }
-
-  error_code reset(hash_t<N> seed = 0)
-  {
-    memset(this, 0, sizeof(hash_state_t<N>));
-    v1 = seed + detail::PRIME<N>(1) + detail::PRIME<N>(2);
-    v2 = seed + detail::PRIME<N>(2);
-    v3 = seed + 0;
-    v4 = seed - detail::PRIME<N>(1);
-    return error_code::ok;
-  }
-
-  error_code update(const void* input, size_t length, endianness endian = endianness::unspecified)
-  {
-    return _update_impl(input, length, mem_ops::get_endian(endian));
-  }
-
-  template <typename T>
-  error_code update(const std::basic_string<T>& input, endianness endian = endianness::unspecified)
-  {
-    return _update_impl(static_cast<const void*>(input.data()), input.length() * sizeof(T),
-                        mem_ops::get_endian(endian));
-  }
-
-  template <typename ContiguousIterator>
-  error_code update(ContiguousIterator begin, ContiguousIterator end, endianness endian = endianness::unspecified)
-  {
-    using T = typename std::decay_t<decltype(*end)>;
-    return _update_impl(static_cast<const void*>(&*begin), (end - begin) * sizeof(T), mem_ops::get_endian(endian));
-  }
-
-  template <typename T> error_code update(const std::vector<T>& input, endianness endian = endianness::unspecified)
-  {
-    return _update_impl(static_cast<const void*>(input.data()), input.size() * sizeof(T), mem_ops::get_endian(endian));
-  }
-
-  template <typename T, size_t AN>
-  error_code update(const std::array<T, AN>& input, endianness endian = endianness::unspecified)
-  {
-    return _update_impl(static_cast<const void*>(input.data()), AN * sizeof(T), mem_ops::get_endian(endian));
-  }
-
-  template <typename T>
-  error_code update(const std::initializer_list<T>& input, endianness endian = endianness::unspecified)
-  {
-    return _update_impl(static_cast<const void*>(input.begin()), input.size() * sizeof(T), mem_ops::get_endian(endian));
-  }
-
-  hash_t<N> digest(endianness endian = endianness::unspecified) { return _digest_impl(mem_ops::get_endian(endian)); }
-};
-
-using hash_state32_t = hash_state_t<32>;
-using hash_state64_t = hash_state_t<64>;
-
-/* *******************************************************************
- *  Canonical
- *********************************************************************/
-
-template <size_t N> struct canonical_t {
-  std::array<uint8_t, N / 8> digest;
-
-  canonical_t(hash_t<N> hash)
-  {
-    if (mem_ops::is_little_endian()) {
-      hash = bit_ops::swap<N>(hash);
-    }
-    memcpy(digest.data(), &hash, sizeof(canonical_t<N>));
-  }
-
-  hash_t<N> get_hash() const { return mem_ops::readBE<N>(&digest); }
-};
-
-using canonical32_t = canonical_t<32>;
-using canonical64_t = canonical_t<64>;
-} // namespace xxh
index ef00ea4..d004949 100644 (file)
@@ -10,7 +10,9 @@
 
 #include "simgrid/kernel/ProfileBuilder.hpp"
 #include "simgrid/kernel/routing/NetPoint.hpp"
+#include "simgrid/plugins/load.h"
 #include <simgrid/Exception.hpp>
+#include <simgrid/s4u/ActivitySet.hpp>
 #include <simgrid/s4u/Actor.hpp>
 #include <simgrid/s4u/Barrier.hpp>
 #include <simgrid/s4u/Comm.hpp>
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/s4u/Exec.hpp>
 #include <simgrid/s4u/Host.hpp>
+#include <simgrid/s4u/Io.hpp>
 #include <simgrid/s4u/Link.hpp>
 #include <simgrid/s4u/Mailbox.hpp>
 #include <simgrid/s4u/Mutex.hpp>
 #include <simgrid/s4u/NetZone.hpp>
 #include <simgrid/s4u/Semaphore.hpp>
+#include <simgrid/s4u/Task.hpp>
 #include <simgrid/version.h>
 
 #include <algorithm>
 #include <vector>
 
 namespace py = pybind11;
+using simgrid::s4u::Activity;
+using simgrid::s4u::ActivityPtr;
+using simgrid::s4u::ActivitySet;
+using simgrid::s4u::ActivitySetPtr;
 using simgrid::s4u::Actor;
 using simgrid::s4u::ActorPtr;
 using simgrid::s4u::Barrier;
 using simgrid::s4u::BarrierPtr;
 using simgrid::s4u::Comm;
 using simgrid::s4u::CommPtr;
+using simgrid::s4u::CommTask;
+using simgrid::s4u::CommTaskPtr;
+using simgrid::s4u::Disk;
 using simgrid::s4u::Engine;
+using simgrid::s4u::ExecTask;
+using simgrid::s4u::ExecTaskPtr;
 using simgrid::s4u::Host;
+using simgrid::s4u::Io;
+using simgrid::s4u::IoTask;
+using simgrid::s4u::IoTaskPtr;
 using simgrid::s4u::Link;
 using simgrid::s4u::Mailbox;
 using simgrid::s4u::Mutex;
 using simgrid::s4u::MutexPtr;
 using simgrid::s4u::Semaphore;
 using simgrid::s4u::SemaphorePtr;
+using simgrid::s4u::Task;
+using simgrid::s4u::TaskPtr;
 
 XBT_LOG_NEW_DEFAULT_CATEGORY(python, "python");
 
@@ -58,15 +76,6 @@ std::string get_simgrid_version()
   sg_version_get(&major, &minor, &patch);
   return simgrid::xbt::string_printf("%i.%i.%i", major, minor, patch);
 }
-
-/** @brief Wrap for mailbox::get_async */
-class PyGetAsync {
-  std::unique_ptr<PyObject*> data = std::make_unique<PyObject*>();
-
-public:
-  PyObject** get() const { return data.get(); }
-};
-
 } // namespace
 
 PYBIND11_DECLARE_HOLDER_TYPE(T, boost::intrusive_ptr<T>)
@@ -159,54 +168,16 @@ PYBIND11_MODULE(simgrid, m)
              return new simgrid::s4u::Engine(&argc, argv.data());
            }),
            "The constructor should take the parameters from the command line, as is ")
-      .def_static("get_clock",
-                  []() // XBT_ATTRIB_DEPRECATED_v334
-                  {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "get_clock() is deprecated and  will be dropped after v3.33, use `Engine.clock` instead.", 1);
-                    return Engine::get_clock();
-                  })
       .def_property_readonly_static(
           "clock", [](py::object /* self */) { return Engine::get_clock(); },
           "The simulation time, ie the amount of simulated seconds since the simulation start.")
       .def_property_readonly_static(
           "instance", [](py::object /* self */) { return Engine::get_instance(); }, "Retrieve the simulation engine")
-      .def("get_all_hosts",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(PyExc_DeprecationWarning,
-                          "get_all_hosts() is deprecated and  will be dropped after v3.33, use all_hosts instead.", 1);
-             return self.attr("all_hosts");
-           })
       .def("host_by_name", &Engine::host_by_name_or_null,
            "Retrieve a host by its name, or None if it does not exist in the platform.")
       .def_property_readonly("all_hosts", &Engine::get_all_hosts, "Returns the list of all hosts found in the platform")
-      .def("get_all_links",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(PyExc_DeprecationWarning,
-                          "get_all_links() is deprecated and  will be dropped after v3.33, use all_links instead.", 1);
-             return self.attr("all_links");
-           })
       .def_property_readonly("all_links", &Engine::get_all_links, "Returns the list of all links found in the platform")
-      .def("get_all_netpoints",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(
-                 PyExc_DeprecationWarning,
-                 "get_all_netpoints() is deprecated and  will be dropped after v3.33, use all_netpoints instead.", 1);
-             return self.attr("all_netpoints");
-           })
       .def_property_readonly("all_netpoints", &Engine::get_all_netpoints)
-      .def("get_netzone_root",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(
-                 PyExc_DeprecationWarning,
-                 "get_netzone_root() is deprecated and  will be dropped after v3.33, use netzone_root instead.", 1);
-             return self.attr("netzone_root");
-           })
       .def_property_readonly("netzone_root", &Engine::get_netzone_root,
                              "Retrieve the root netzone, containing all others.")
       .def("netpoint_by_name", &Engine::netpoint_by_name_or_null)
@@ -235,7 +206,7 @@ PYBIND11_MODULE(simgrid, m)
                   params[i - 1] = py::cast(args[i]);
 
                 const auto fun_or_class = py::reinterpret_borrow<py::object>(fun_or_class_p);
-                py::object res = fun_or_class(*params);
+                py::object res          = fun_or_class(*params);
                 /* If I was passed a class, I just built an instance, so I need to call it now */
                 if (py::isinstance<py::function>(res))
                   res();
@@ -248,7 +219,8 @@ PYBIND11_MODULE(simgrid, m)
               }
             });
           },
-          "Registers the main function of an actor");
+          "Registers the main function of an actor")
+      .def("set_log_control", [](Engine*, const std::string& settings) { xbt_log_control_set(settings.c_str()); });
 
   /* Class Netzone */
   py::class_<simgrid::s4u::NetZone, std::unique_ptr<simgrid::s4u::NetZone, py::nodelete>> netzone(
@@ -264,10 +236,21 @@ PYBIND11_MODULE(simgrid, m)
       .def_static("create_empty_zone", &simgrid::s4u::create_empty_zone, "Creates a zone of type Empty")
       .def_static("create_wifi_zone", &simgrid::s4u::create_wifi_zone, "Creates a zone of type Wi-Fi")
       .def("add_route",
-           py::overload_cast<simgrid::kernel::routing::NetPoint*, simgrid::kernel::routing::NetPoint*,
-                             simgrid::kernel::routing::NetPoint*, simgrid::kernel::routing::NetPoint*,
+           py::overload_cast<const simgrid::s4u::Host*, const simgrid::s4u::Host*,
+                             const std::vector<simgrid::s4u::LinkInRoute>&, bool>(&simgrid::s4u::NetZone::add_route),
+           "Add a route between 2 hosts")
+      .def("add_route",
+           py::overload_cast<const simgrid::s4u::Host*, const simgrid::s4u::Host*,
+                             const std::vector<const simgrid::s4u::Link*>&>(&simgrid::s4u::NetZone::add_route),
+           "Add a route between 2 hosts")
+      .def("add_route",
+           py::overload_cast<const simgrid::s4u::NetZone*, const simgrid::s4u::NetZone*,
                              const std::vector<simgrid::s4u::LinkInRoute>&, bool>(&simgrid::s4u::NetZone::add_route),
-           "Add a route between 2 netpoints")
+           "Add a route between 2 netzones. The gateway of each zone gets used.")
+      .def("add_route",
+           py::overload_cast<const simgrid::s4u::NetZone*, const simgrid::s4u::NetZone*,
+                             const std::vector<const simgrid::s4u::Link*>&>(&simgrid::s4u::NetZone::add_route),
+           "Add a route between 2 netzones. The gateway of each zone gets used.")
       .def("create_host", py::overload_cast<const std::string&, double>(&simgrid::s4u::NetZone::create_host),
            "Creates a host")
       .def("create_host",
@@ -299,22 +282,22 @@ PYBIND11_MODULE(simgrid, m)
       .def("create_router", &simgrid::s4u::NetZone::create_router, "Create a router")
       .def("set_parent", &simgrid::s4u::NetZone::set_parent, "Set the parent of this zone")
       .def("set_property", &simgrid::s4u::NetZone::set_property, "Add a property to this zone")
-      .def("get_netpoint",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(PyExc_DeprecationWarning,
-                          "get_netpoint() is deprecated and  will be dropped after v3.33, use netpoint instead.", 1);
-             return self.attr("netpoint");
-           })
+      .def("set_gateway", py::overload_cast<const simgrid::s4u::Host*>(&simgrid::s4u::NetZone::set_gateway),
+           "Specify the gateway of this zone, to be used for inter-zone routes")
+      .def("set_gateway", py::overload_cast<simgrid::kernel::routing::NetPoint*>(&simgrid::s4u::NetZone::set_gateway),
+           "Specify the gateway of this zone, to be used for inter-zone routes")
       .def_property_readonly("netpoint", &simgrid::s4u::NetZone::get_netpoint,
                              "Retrieve the netpoint associated to this zone")
       .def("seal", &simgrid::s4u::NetZone::seal, "Seal this NetZone")
       .def_property_readonly("name", &simgrid::s4u::NetZone::get_name,
-                             "The name of this network zone (read-only property).");
+                             "The name of this network zone (read-only property).")
+      .def(
+          "__repr__", [](const simgrid::s4u::NetZone net) { return "NetZone(" + net.get_name() + ")"; },
+          "Textual representation of the NetZone");
 
   /* Class ClusterCallbacks */
   py::class_<simgrid::s4u::ClusterCallbacks>(m, "ClusterCallbacks", "Callbacks used to create cluster zones")
-      .def(py::init<const std::function<simgrid::s4u::ClusterCallbacks::ClusterNetPointCb>&,
+      .def(py::init<const std::function<simgrid::s4u::ClusterCallbacks::ClusterNetZoneCb>&,
                     const std::function<simgrid::s4u::ClusterCallbacks::ClusterLinkCb>&,
                     const std::function<simgrid::s4u::ClusterCallbacks::ClusterLinkCb>&>());
 
@@ -377,41 +360,11 @@ PYBIND11_MODULE(simgrid, m)
           "   \"\"\"\n\n"
           "The second function parameter is the periodicity: the time to wait after the last event to start again over "
           "the list. Set it to -1 to not loop over.")
-      .def("get_pstate_count",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(
-                 PyExc_DeprecationWarning,
-                 "get_pstate_count() is deprecated and  will be dropped after v3.33, use pstate_count instead.", 1);
-             return self.attr("pstate_count");
-           })
       .def_property_readonly("pstate_count", &Host::get_pstate_count, "Retrieve the count of defined pstate levels")
-      .def("get_pstate_speed",
-           [](py::object self, int state) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(
-                 PyExc_DeprecationWarning,
-                 "get_pstate_speed() is deprecated and  will be dropped after v3.33, use pstate_speed instead.", 1);
-             return self.attr("pstate_speed")(state);
-           })
       .def("pstate_speed", &Host::get_pstate_speed, "Retrieve the maximal speed at the given pstate")
-      .def("get_netpoint",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(PyExc_DeprecationWarning,
-                          "get_netpoint() is deprecated and  will be dropped after v3.33, use netpoint instead.", 1);
-             return self.attr("netpoint");
-           })
       .def_property_readonly("netpoint", &Host::get_netpoint, "Retrieve the netpoint associated to this zone")
+      .def_property_readonly("disks", &Host::get_disks, "The list of disks on this host (read-only).")
       .def("get_disks", &Host::get_disks, "Retrieve the list of disks in this host")
-      .def("set_core_count",
-           [](py::object self, double count) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(PyExc_DeprecationWarning,
-                          "set_core_count() is deprecated and  will be dropped after v3.33, use core_count instead.",
-                          1);
-             self.attr("core_count")(count);
-           })
       .def_property("core_count", &Host::get_core_count,
                     py::cpp_function(&Host::set_core_count, py::call_guard<py::gil_scoped_release>()),
                     "Manage the number of cores in the CPU")
@@ -425,6 +378,8 @@ PYBIND11_MODULE(simgrid, m)
            py::overload_cast<const std::string&, const std::string&, const std::string&>(&Host::create_disk),
            py::call_guard<py::gil_scoped_release>(), "Create a disk")
       .def("seal", &Host::seal, py::call_guard<py::gil_scoped_release>(), "Seal this host")
+      .def("turn_off", &Host::turn_off, py::call_guard<py::gil_scoped_release>(), "Turn off this host")
+      .def("turn_on", &Host::turn_on, py::call_guard<py::gil_scoped_release>(), "Turn on this host")
       .def_property("pstate", &Host::get_pstate,
                     py::cpp_function(&Host::set_pstate, py::call_guard<py::gil_scoped_release>()),
                     "The current pstate (read/write property).")
@@ -457,12 +412,35 @@ PYBIND11_MODULE(simgrid, m)
               }
             });
           },
-          "");
+          "")
+      .def(
+          "__repr__", [](const Host* h) { return "Host(" + h->get_name() + ")"; },
+          "Textual representation of the Host.");
+
+  m.def("sg_host_load_plugin_init", [host]() {
+    sg_host_load_plugin_init();
+
+    static_cast<pybind11::class_<simgrid::s4u::Host, std::unique_ptr<simgrid::s4u::Host, pybind11::nodelete>>>(host)
+        .def(
+            "reset_load", [](const Host* h) { sg_host_load_reset(h); }, py::call_guard<py::gil_scoped_release>(),
+            "Reset counters of the host load plugin for this host.")
+        .def_property_readonly(
+            "current_load", [](const Host* h) { return sg_host_get_current_load(h); }, "Current load of the host.")
+        .def_property_readonly(
+            "avg_load", [](const Host* h) { return sg_host_get_avg_load(h); }, "Average load of the host.")
+        .def_property_readonly(
+            "idle_time", [](const Host* h) { return sg_host_get_idle_time(h); }, "Idle time of the host")
+        .def_property_readonly(
+            "total_idle_time", [](const Host* h) { return sg_host_get_total_idle_time(h); },
+            "Total idle time of the host.")
+        .def_property_readonly(
+            "computed_flops", [](const Host* h) { return sg_host_get_computed_flops(h); },
+            "Computed flops of the host.");
+  });
 
   py::enum_<simgrid::s4u::Host::SharingPolicy>(host, "SharingPolicy")
       .value("NONLINEAR", simgrid::s4u::Host::SharingPolicy::NONLINEAR)
-      .value("LINEAR", simgrid::s4u::Host::SharingPolicy::LINEAR)
-      .export_values();
+      .value("LINEAR", simgrid::s4u::Host::SharingPolicy::LINEAR);
 
   /* Class Disk */
   py::class_<simgrid::s4u::Disk, std::unique_ptr<simgrid::s4u::Disk, py::nodelete>> disk(
@@ -479,16 +457,17 @@ PYBIND11_MODULE(simgrid, m)
            "Set sharing policy for this disk", py::arg("op"), py::arg("policy"),
            py::arg("cb") = simgrid::s4u::NonLinearResourceCb())
       .def("seal", &simgrid::s4u::Disk::seal, py::call_guard<py::gil_scoped_release>(), "Seal this disk")
-      .def_property_readonly("name", &simgrid::s4u::Disk::get_name, "The name of this disk (read-only property).");
+      .def_property_readonly("name", &simgrid::s4u::Disk::get_name, "The name of this disk (read-only property).")
+      .def(
+          "__repr__", [](const Disk* d) { return "Disk(" + d->get_name() + ")"; },
+          "Textual representation of the Disk");
   py::enum_<simgrid::s4u::Disk::SharingPolicy>(disk, "SharingPolicy")
       .value("NONLINEAR", simgrid::s4u::Disk::SharingPolicy::NONLINEAR)
-      .value("LINEAR", simgrid::s4u::Disk::SharingPolicy::LINEAR)
-      .export_values();
+      .value("LINEAR", simgrid::s4u::Disk::SharingPolicy::LINEAR);
   py::enum_<simgrid::s4u::Disk::Operation>(disk, "Operation")
       .value("READ", simgrid::s4u::Disk::Operation::READ)
       .value("WRITE", simgrid::s4u::Disk::Operation::WRITE)
-      .value("READWRITE", simgrid::s4u::Disk::Operation::READWRITE)
-      .export_values();
+      .value("READWRITE", simgrid::s4u::Disk::Operation::READWRITE);
 
   /* Class NetPoint */
   py::class_<simgrid::kernel::routing::NetPoint, std::unique_ptr<simgrid::kernel::routing::NetPoint, py::nodelete>>
@@ -575,15 +554,22 @@ PYBIND11_MODULE(simgrid, m)
       .def_property_readonly("name", &Link::get_name, "The name of this link")
       .def_property_readonly("bandwidth", &Link::get_bandwidth,
                              "The bandwidth (in bytes per second) (read-only property).")
-      .def_property_readonly("latency", &Link::get_latency, "The latency (in seconds) (read-only property).");
-
+      .def_property_readonly("latency", &Link::get_latency, "The latency (in seconds) (read-only property).")
+      .def(
+          "__repr__", [](const Link* l) { return "Link(" + l->get_name() + ")"; },
+          "Textual representation of the Link");
   py::enum_<Link::SharingPolicy>(link, "SharingPolicy")
-      .value("NONLINEAR", Link::SharingPolicy::NONLINEAR)
-      .value("WIFI", Link::SharingPolicy::WIFI)
-      .value("SPLITDUPLEX", Link::SharingPolicy::SPLITDUPLEX)
-      .value("SHARED", Link::SharingPolicy::SHARED)
-      .value("FATPIPE", Link::SharingPolicy::FATPIPE)
-      .export_values();
+      .value("NONLINEAR", Link::SharingPolicy::NONLINEAR,
+             "This policy takes a callback that specifies the maximal capacity as a function of the number of usage. "
+             "See the examples with 'degradation' in their name.")
+      .value("WIFI", Link::SharingPolicy::WIFI, "Pseudo-sharing policy requesting wifi-specific sharing.")
+      .value("SPLITDUPLEX", Link::SharingPolicy::SPLITDUPLEX,
+             "Each link is split in 2, UP and DOWN, one per direction. These links are SHARED.")
+      .value("SHARED", Link::SharingPolicy::SHARED,
+             "The bandwidth is shared between all comms using that link, regardless of their direction.")
+      .value("FATPIPE", Link::SharingPolicy::FATPIPE,
+             "Each comm can use the link fully, with no sharing (only a maximum). This is intended to represent the "
+             "backbone links that cannot be saturated by concurrent links, but have a maximal bandwidth.");
 
   /* Class LinkInRoute */
   py::class_<simgrid::s4u::LinkInRoute> linkinroute(m, "LinkInRoute", "Abstraction to add link in routes");
@@ -592,35 +578,20 @@ PYBIND11_MODULE(simgrid, m)
   py::enum_<simgrid::s4u::LinkInRoute::Direction>(linkinroute, "Direction")
       .value("UP", simgrid::s4u::LinkInRoute::Direction::UP)
       .value("DOWN", simgrid::s4u::LinkInRoute::Direction::DOWN)
-      .value("NONE", simgrid::s4u::LinkInRoute::Direction::NONE)
-      .export_values();
+      .value("NONE", simgrid::s4u::LinkInRoute::Direction::NONE);
 
   /* Class Split-Duplex Link */
   py::class_<simgrid::s4u::SplitDuplexLink, Link, std::unique_ptr<simgrid::s4u::SplitDuplexLink, py::nodelete>>(
       m, "SplitDuplexLink", "Network split-duplex link")
-      .def("get_link_up",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(PyExc_DeprecationWarning,
-                          "get_link_up() is deprecated and  will be dropped after v3.33, use link_up instead.", 1);
-             return self.attr("link_up");
-           })
       .def_property_readonly("link_up", &simgrid::s4u::SplitDuplexLink::get_link_up, "Get link direction up")
-      .def("get_link_down",
-           [](py::object self) // XBT_ATTRIB_DEPRECATED_v334
-           {
-             PyErr_WarnEx(PyExc_DeprecationWarning,
-                          "get_link_down() is deprecated and  will be dropped after v3.33, use link_down instead.", 1);
-             return self.attr("link_down");
-           })
       .def_property_readonly("link_down", &simgrid::s4u::SplitDuplexLink::get_link_down, "Get link direction down");
 
   /* Class Mailbox */
   py::class_<simgrid::s4u::Mailbox, std::unique_ptr<Mailbox, py::nodelete>>(
       m, "Mailbox", "Mailbox. See the C++ documentation for details.")
       .def(
-          "__str__", [](const Mailbox* self) { return "Mailbox(" + self->get_name() + ")"; },
-          "Textual representation of the Mailbox`")
+          "__repr__", [](const Mailbox* self) { return "Mailbox(" + self->get_name() + ")"; },
+          "Textual representation of the Mailbox")
       .def_static("by_name", &Mailbox::by_name, py::call_guard<py::gil_scoped_release>(), py::arg("name"),
                   "Retrieve a Mailbox from its name")
       .def_property_readonly("name", &Mailbox::get_name, "The name of that mailbox (read-only property).")
@@ -662,26 +633,17 @@ PYBIND11_MODULE(simgrid, m)
           "get", [](Mailbox* self) { return py::reinterpret_steal<py::object>(self->get<PyObject>()); },
           py::call_guard<py::gil_scoped_release>(), "Blocking data reception")
       .def(
-          "get_async",
-          [](Mailbox* self) -> std::tuple<CommPtr, PyGetAsync> {
-            PyGetAsync wrap;
-            auto comm = self->get_async(wrap.get());
-            return std::make_tuple(std::move(comm), std::move(wrap));
-          },
+          "get_async", [](Mailbox* self) -> CommPtr { return self->get_async(); },
           py::call_guard<py::gil_scoped_release>(),
           "Non-blocking data reception. Use data.get() to get the python object after the communication has finished")
       .def("set_receiver", &Mailbox::set_receiver, py::call_guard<py::gil_scoped_release>(),
            "Sets the actor as permanent receiver");
 
-  /* Class PyGetAsync */
-  py::class_<PyGetAsync>(m, "PyGetAsync", "Wrapper for async get communications")
-      .def(py::init<>())
-      .def(
-          "get", [](const PyGetAsync* self) { return py::reinterpret_steal<py::object>(*(self->get())); },
-          "Get python object after async communication in receiver side");
+  /* class Activity */
+  py::class_<Activity, ActivityPtr>(m, "Activity", "Activity. See the C++ documentation for details.");
 
   /* Class Comm */
-  py::class_<Comm, CommPtr>(m, "Comm", "Communication. See the C++ documentation for details.")
+  py::class_<Comm, CommPtr, Activity>(m, "Comm", "Communication. See the C++ documentation for details.")
       .def_property_readonly("dst_data_size", &Comm::get_dst_data_size, py::call_guard<py::gil_scoped_release>(),
                              "Retrieve the size of the received data.")
       .def_property_readonly("mailbox", &Comm::get_mailbox, py::call_guard<py::gil_scoped_release>(),
@@ -718,6 +680,11 @@ PYBIND11_MODULE(simgrid, m)
            "Block until the completion of that communication, or raises TimeoutException after the specified timeout.")
       .def("wait_until", &Comm::wait_until, py::call_guard<py::gil_scoped_release>(), py::arg("time_limit"),
            "Block until the completion of that communication, or raises TimeoutException after the specified time.")
+      .def(
+          "get_payload",
+          [](const Comm* self) { return py::reinterpret_steal<py::object>((PyObject*)self->get_payload()); },
+          py::call_guard<py::gil_scoped_release>(),
+          "Retrieve the message's payload of a get_async. You cannot call this until after the comm termination.")
       .def("detach", py::overload_cast<>(&Comm::detach), py::return_value_policy::reference_internal,
            py::call_guard<py::gil_scoped_release>(),
            "Start the comm, and ignore its result. It can be completely forgotten after that.")
@@ -730,37 +697,19 @@ PYBIND11_MODULE(simgrid, m)
                   py::arg("to"), py::arg("simulated_size_in_bytes"),
                   "Do a blocking communication between two arbitrary hosts.\n\nThis initializes a communication that "
                   "completely bypass the mailbox and actors mechanism. There is really no limit on the hosts involved. "
-                  "In particular, the actor does not have to be on one of the involved hosts.")
-      .def_static("test_any", &Comm::test_any, py::call_guard<py::gil_scoped_release>(), py::arg("comms"),
-                  "take a vector s4u::CommPtr and return the rank of the first finished one (or -1 if none is done)")
-      .def_static("wait_all", &Comm::wait_all, py::call_guard<py::gil_scoped_release>(), py::arg("comms"),
-                  "Block until the completion of all communications in the list.")
-      .def_static("wait_all_for", &Comm::wait_all_for, py::call_guard<py::gil_scoped_release>(), py::arg("comms"),
-                  py::arg("timeout"),
-                  "Block until the completion of all communications in the list, or raises TimeoutException after "
-                  "the specified timeout.")
-      .def_static("wait_any", &Comm::wait_any, py::call_guard<py::gil_scoped_release>(), py::arg("comms"),
-                  "Block until the completion of any communication in the list and return the index of the "
-                  "terminated one.")
-      .def_static("wait_any_for", &Comm::wait_any_for, py::call_guard<py::gil_scoped_release>(), py::arg("comms"),
-                  py::arg("timeout"),
-                  "Block until the completion of any communication in the list and return the index of the terminated "
-                  "one, or -1 if a timeout occurred.");
+                  "In particular, the actor does not have to be on one of the involved hosts.");
 
   /* Class Io */
-  py::class_<simgrid::s4u::Io, simgrid::s4u::IoPtr>(m, "Io", "I/O activities. See the C++ documentation for details.")
+  py::class_<simgrid::s4u::Io, simgrid::s4u::IoPtr, Activity>(m, "Io",
+                                                              "I/O activities. See the C++ documentation for details.")
       .def("test", &simgrid::s4u::Io::test, py::call_guard<py::gil_scoped_release>(),
            "Test whether the I/O is terminated.")
       .def("wait", &simgrid::s4u::Io::wait, py::call_guard<py::gil_scoped_release>(),
-           "Block until the completion of that I/O operation")
-      .def_static(
-          "wait_any_for", &simgrid::s4u::Io::wait_any_for, py::call_guard<py::gil_scoped_release>(),
-          "Block until the completion of any I/O in the list (or timeout) and return the index of the terminated one.")
-      .def_static("wait_any", &simgrid::s4u::Io::wait_any, py::call_guard<py::gil_scoped_release>(),
-                  "Block until the completion of any I/O in the list and return the index of the terminated one.");
+           "Block until the completion of that I/O operation");
 
   /* Class Exec */
-  py::class_<simgrid::s4u::Exec, simgrid::s4u::ExecPtr>(m, "Exec", "Execution. See the C++ documentation for details.")
+  py::class_<simgrid::s4u::Exec, simgrid::s4u::ExecPtr, Activity>(m, "Exec",
+                                                                  "Execution. See the C++ documentation for details.")
       .def_property_readonly("remaining", &simgrid::s4u::Exec::get_remaining, py::call_guard<py::gil_scoped_release>(),
                              "Amount of flops that remain to be computed until completion (read-only property).")
       .def_property_readonly("remaining_ratio", &simgrid::s4u::Exec::get_remaining_ratio,
@@ -794,8 +743,7 @@ PYBIND11_MODULE(simgrid, m)
       .def("acquire_timeout", &Semaphore::acquire_timeout, py::call_guard<py::gil_scoped_release>(), py::arg("timeout"),
            "Acquire on the semaphore object with no timeout. Blocks until the semaphore is acquired or return "
            "true if it has not been acquired after the specified timeout.")
-      .def("release", &Semaphore::release, py::call_guard<py::gil_scoped_release>(),
-           "Release the semaphore.")
+      .def("release", &Semaphore::release, py::call_guard<py::gil_scoped_release>(), "Release the semaphore.")
       .def_property_readonly("capacity", &Semaphore::get_capacity, py::call_guard<py::gil_scoped_release>(),
                              "Get the semaphore capacity.")
       .def_property_readonly("would_block", &Semaphore::would_block, py::call_guard<py::gil_scoped_release>(),
@@ -810,19 +758,20 @@ PYBIND11_MODULE(simgrid, m)
   py::class_<Mutex, MutexPtr>(m, "Mutex",
                               "A classical mutex, but blocking in the simulation world."
                               "See the C++ documentation for details.")
-      .def(py::init<>(&Mutex::create), py::call_guard<py::gil_scoped_release>(), "Mutex constructor.")
+      .def(py::init<>(&Mutex::create), py::call_guard<py::gil_scoped_release>(),
+           "Mutex constructor (pass True as a parameter to get a recursive Mutex).", py::arg("recursive") = false)
       .def("lock", &Mutex::lock, py::call_guard<py::gil_scoped_release>(), "Block until the mutex is acquired.")
       .def("try_lock", &Mutex::try_lock, py::call_guard<py::gil_scoped_release>(),
            "Try to acquire the mutex. Return true if the mutex was acquired, false otherwise.")
       .def("unlock", &Mutex::unlock, py::call_guard<py::gil_scoped_release>(), "Release the mutex.")
       // Allow mutexes to be automatically acquired/released with a context manager: `with mutex: ...`
       .def("__enter__", &Mutex::lock, py::call_guard<py::gil_scoped_release>())
-      .def("__exit__", [](Mutex* self, const py::object&, const py::object&, const py::object&) { self->unlock(); },
-           py::call_guard<py::gil_scoped_release>());
+      .def(
+          "__exit__", [](Mutex* self, const py::object&, const py::object&, const py::object&) { self->unlock(); },
+          py::call_guard<py::gil_scoped_release>());
 
   /* Class Barrier */
-  py::class_<Barrier, BarrierPtr>(m, "Barrier",
-                                  "A classical barrier, but blocking in the simulation world.")
+  py::class_<Barrier, BarrierPtr>(m, "Barrier", "A classical barrier, but blocking in the simulation world.")
       .def(py::init<>(&Barrier::create), py::call_guard<py::gil_scoped_release>(), py::arg("expected_actors"),
            "Barrier constructor.")
       .def("wait", &Barrier::wait, py::call_guard<py::gil_scoped_release>(),
@@ -886,5 +835,141 @@ PYBIND11_MODULE(simgrid, m)
       .def("resume", &Actor::resume, py::call_guard<py::gil_scoped_release>(),
            "Resume that actor, that was previously suspend()ed.")
       .def_static("kill_all", &Actor::kill_all, py::call_guard<py::gil_scoped_release>(),
-                  "Kill all actors but the caller.");
+                  "Kill all actors but the caller.")
+      .def(
+          "__repr__", [](const ActorPtr a) { return "Actor(" + a->get_name() + ")"; },
+          "Textual representation of the Actor");
+
+  /* Enum Class IoOpType */
+  py::enum_<simgrid::s4u::Io::OpType>(m, "IoOpType")
+      .value("READ", simgrid::s4u::Io::OpType::READ)
+      .value("WRITE", simgrid::s4u::Io::OpType::WRITE);
+
+  /* Class Task */
+  py::class_<Task, TaskPtr>(m, "Task", "Task. See the C++ documentation for details.")
+      .def_static(
+          "on_start_cb",
+          [](py::object cb) {
+            cb.inc_ref(); // keep alive after return
+            const py::gil_scoped_release gil_release;
+            Task::on_start_cb([cb_p = cb.ptr()](Task* op) {
+              const py::gil_scoped_acquire py_context; // need a new context for callback
+              py::reinterpret_borrow<py::function>(cb_p)(op);
+            });
+          },
+          "Add a callback called when each task starts.")
+      .def_static(
+          "on_completion_cb",
+          [](py::object cb) {
+            cb.inc_ref(); // keep alive after return
+            const py::gil_scoped_release gil_release;
+            Task::on_completion_cb([cb_p = cb.ptr()](Task* op) {
+              const py::gil_scoped_acquire py_context; // need a new context for callback
+              py::reinterpret_borrow<py::function>(cb_p)(op);
+            });
+          },
+          "Add a callback called when each task ends.")
+      .def_property_readonly("name", &Task::get_name, "The name of this task (read-only).")
+      .def_property_readonly("successors", &Task::get_successors, "The successors of this task (read-only).")
+      .def_property("amount", &Task::get_amount, &Task::set_amount, "The amount of work to do for this task.")
+      .def(
+          "get_count", [](const TaskPtr t) { return t->get_count("instance_0"); },
+          "The execution count of this task instance_0.")
+      .def(
+          "get_count", [](const TaskPtr t, const std::string& instance) { return t->get_count(instance); },
+          "The execution count of this task instance.")
+      .def("enqueue_firings", py::overload_cast<int>(&Task::enqueue_firings), py::call_guard<py::gil_scoped_release>(),
+           py::arg("n"), "Enqueue firings for this task.")
+      .def("add_successor", py::overload_cast<TaskPtr>(&Task::add_successor), py::call_guard<py::gil_scoped_release>(),
+           py::arg("op"), "Add a successor to this task.")
+      .def("remove_successor", py::overload_cast<TaskPtr>(&Task::remove_successor),
+           py::call_guard<py::gil_scoped_release>(), py::arg("op"), "Remove a successor of this task.")
+      .def("remove_all_successors", &Task::remove_all_successors, py::call_guard<py::gil_scoped_release>(),
+           "Remove all successors of this task.")
+      .def("on_this_start_cb", py::overload_cast<const std::function<void(Task*)>&>(&Task::on_this_start_cb),
+           py::arg("func"), "Add a callback called when this task starts.")
+      .def("on_this_completion_cb", py::overload_cast<const std::function<void(Task*)>&>(&Task::on_this_completion_cb),
+           py::arg("func"), "Add a callback called when this task ends.")
+      .def(
+          "__repr__", [](const TaskPtr op) { return "Task(" + op->get_name() + ")"; },
+          "Textual representation of the Task");
+
+  /* Class CommTask */
+  py::class_<CommTask, CommTaskPtr, Task>(m, "CommTask", "Communication Task. See the C++ documentation for details.")
+      .def_static("init", py::overload_cast<const std::string&>(&CommTask::init),
+                  py::call_guard<py::gil_scoped_release>(), py::arg("name"), "CommTask constructor")
+      .def_static("init", py::overload_cast<const std::string&, double, Host*, Host*>(&CommTask::init),
+                  py::call_guard<py::gil_scoped_release>(), py::arg("name"), py::arg("bytes"), py::arg("source"),
+                  py::arg("destination"), "CommTask constructor")
+      .def_property("source", &CommTask::get_source, &CommTask::set_source, "The source of the communication.")
+      .def_property("destination", &CommTask::get_destination, &CommTask::set_destination,
+                    "The destination of the communication.")
+      .def_property("bytes", &CommTask::get_bytes, &CommTask::set_bytes, "The amount of bytes to send.")
+      .def(
+          "__repr__", [](const CommTaskPtr c) { return "CommTask(" + c->get_name() + ")"; },
+          "Textual representation of the CommTask");
+
+  /* Class ExecTask */
+  py::class_<ExecTask, ExecTaskPtr, Task>(m, "ExecTask", "Execution Task. See the C++ documentation for details.")
+      .def_static("init", py::overload_cast<const std::string&>(&ExecTask::init),
+                  py::call_guard<py::gil_scoped_release>(), py::arg("name"), "ExecTask constructor")
+      .def_static("init", py::overload_cast<const std::string&, double, Host*>(&ExecTask::init),
+                  py::call_guard<py::gil_scoped_release>(), py::arg("name"), py::arg("flops"), py::arg("host"),
+                  "CommTask constructor.")
+      .def_property("host", &ExecTask::get_host, &ExecTask::set_host, "The host of the execution.")
+      .def_property("flops", &ExecTask::get_flops, &ExecTask::set_flops, "The amount of flops to execute.")
+      .def(
+          "__repr__", [](const ExecTaskPtr e) { return "ExecTask(" + e->get_name() + ")"; },
+          "Textual representation of the ExecTask");
+
+  /* Class IoTask */
+  py::class_<IoTask, IoTaskPtr, Task>(m, "IoTask", "IO Task. See the C++ documentation for details.")
+      .def_static("init", py::overload_cast<const std::string&>(&IoTask::init),
+                  py::call_guard<py::gil_scoped_release>(), py::arg("name"), "IoTask constructor")
+      .def_static("init", py::overload_cast<const std::string&, double, Disk*, Io::OpType>(&IoTask::init),
+                  py::call_guard<py::gil_scoped_release>(), py::arg("name"), py::arg("bytes"), py::arg("disk"),
+                  py::arg("type"), "IoTask constructor.")
+      .def_property("disk", &IoTask::get_disk, &IoTask::set_disk, "The disk of the IO.")
+      .def_property("bytes", &IoTask::get_bytes, &IoTask::set_bytes, "The amount of bytes to process.")
+      .def_property("type", &IoTask::get_bytes, &IoTask::set_bytes, "The type of IO.")
+      .def(
+          "__repr__", [](const IoTaskPtr io) { return "IoTask(" + io->get_name() + ")"; },
+          "Textual representation of the IoTask");
+
+  /* Class ActivitySet */
+  py::class_<ActivitySet, ActivitySetPtr>(m, "ActivitySet", "ActivitySet. See the C++ documentation for details.")
+      .def(py::init([](std::vector<simgrid::s4u::ActivityPtr> activities) {
+             auto* ret = new ActivitySet();
+             for (auto a : activities)
+               ret->push(a);
+             return ActivitySetPtr(ret);
+           }),
+           "The constructor should take the parameters from the command line, as is ")
+      .def(py::init([]() { return ActivitySetPtr(new ActivitySet()); }),
+           "The constructor should take the parameters from the command line, as is ")
+
+      .def("push", &ActivitySet::push, py::call_guard<py::gil_scoped_release>(), py::arg("activity"),
+           "Add an activity to the set")
+      .def("erase", &ActivitySet::erase, py::call_guard<py::gil_scoped_release>(), py::arg("activity"),
+           "Remove that activity from the set")
+      .def_property_readonly("size", &ActivitySet::size, "Count of activities in the set")
+      .def("empty", &ActivitySet::empty, "Returns whether the set is empty")
+      .def("has_failed_activities", &ActivitySet::has_failed_activities,
+           "Returns whether there is any failed activities")
+      .def("get_failed_activity", &ActivitySet::get_failed_activity, "Returns a failed activity from the set, or None")
+
+      .def("wait_all_for", &ActivitySet::wait_all_for, py::call_guard<py::gil_scoped_release>(), py::arg("timeout"),
+           "Wait for the completion of all activities in the set, but not longer than the provided timeout")
+      .def("wait_all", &ActivitySet::wait_all, py::call_guard<py::gil_scoped_release>(),
+           "Wait for the completion of all activities in the set, endlessly")
+      .def("test_any", &ActivitySet::test_any, py::call_guard<py::gil_scoped_release>(),
+           "Returns the first terminated activity if any, or None if no activity is terminated")
+      .def("wait_any_for", &ActivitySet::wait_any_for, py::call_guard<py::gil_scoped_release>(), py::arg("timeout"),
+           "Wait for the completion of one activity in the set, but not longer than the provided timeout")
+      .def("wait_any", &ActivitySet::wait_any, py::call_guard<py::gil_scoped_release>(),
+           "Wait for the completion of one activity in the set, endlessly")
+
+      .def(
+          "__repr__", [](const ActivitySetPtr as) { return "ActivitySet([...])"; },
+          "Textual representation of the ActivitySet");
 }
index d4d99a2..09591b1 100644 (file)
 #include "dax_dtd.c"
 
 #if SIMGRID_HAVE_JSON
+// Disable implicit conversions. See https://github.com/nlohmann/json#implicit-conversions
+#ifdef JSON_USE_IMPLICIT_CONVERSIONS
+#undef JSON_USE_IMPLICIT_CONVERSIONS
+#endif
+#define JSON_USE_IMPLICIT_CONVERSIONS 0
 #include <nlohmann/json.hpp>
 #include <sstream>
 #endif
@@ -87,7 +92,7 @@ static ExecPtr current_job;
 
 /** @brief loads a JSON file describing a DAG
  *
- * See https://github.com/wfcommons/wfformat for more details.
+ * See https://github.com/wfcommons/wfformat for more details. We support wfformat 1.4.
  */
 std::vector<ActivityPtr> create_DAG_from_json(const std::string& filename)
 {
@@ -95,20 +100,25 @@ std::vector<ActivityPtr> create_DAG_from_json(const std::string& filename)
   std::ifstream f(filename);
   auto data = nlohmann::json::parse(f);
   std::vector<ActivityPtr> dag = {};
-  std::map<std::string, std::vector<ActivityPtr>> successors = {};
+  std::map<std::string, std::vector<ActivityPtr>, std::less<>> successors = {};
   std::map<ActivityPtr, Host*> comms_destinations = {};
   ActivityPtr current; 
   
   for (auto const& task: data["workflow"]["tasks"]) {
     if (task["type"] == "compute") {
-      current = Exec::init()->set_name(task["name"])->set_flops_amount(task["runtime"]);
+      current =
+          Exec::init()->set_name(task["name"].get<std::string>())->set_flops_amount(task["runtimeInSeconds"].get<double>());
       if (task.contains("machine"))
-        dynamic_cast<Exec*>(current.get())->set_host(simgrid::s4u::Engine::get_instance()->host_by_name(task["machine"]));
+        dynamic_cast<Exec*>(current.get())
+            ->set_host(simgrid::s4u::Engine::get_instance()->host_by_name(task["machine"].get<std::string>()));
     }
     else if (task["type"] == "transfer"){
-      current = Comm::sendto_init()->set_name(task["name"])->set_payload_size(task["bytesWritten"]);
+      current = Comm::sendto_init()
+                    ->set_name(task["name"].get<std::string>())
+                    ->set_payload_size(task["writtenBytes"].get<double>());
       if (task.contains("machine"))
-        comms_destinations[current] = simgrid::s4u::Engine::get_instance()->host_by_name(task["machine"]);
+        comms_destinations[current] =
+            simgrid::s4u::Engine::get_instance()->host_by_name(task["machine"].get<std::string>());
       if (task["parents"].size() == 1) {
         ActivityPtr parent_activity;
         for (auto const& activity: dag) {
@@ -129,12 +139,8 @@ std::vector<ActivityPtr> create_DAG_from_json(const std::string& filename)
     }
 
     dag.push_back(current);
-    for (auto const& parent: task["parents"]) {
-      auto it = successors.find(parent);
-      if (it == successors.end())
-        successors[parent] = {};
-      successors[parent].push_back(current);
-    }
+    for (auto const& parent : task["parents"])
+      successors[parent.get<std::string>()].push_back(current);
   }
   // Assign successors
   for (auto const& [parent, successors_list] : successors)
@@ -150,7 +156,7 @@ std::vector<ActivityPtr> create_DAG_from_json(const std::string& filename)
 
   // Start only Activities with dependencies solved
   for (auto const& activity: dag) {
-    if (dynamic_cast<Exec*>(activity.get()) != nullptr and activity->dependencies_solved())
+    if (dynamic_cast<Exec*>(activity.get()) != nullptr && activity->dependencies_solved())
       activity->start();
   }
   return dag;
diff --git a/src/deprecated.cpp b/src/deprecated.cpp
deleted file mode 100644 (file)
index 79b6a89..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* This file only contains deprecated code, and will die with v3.25           */
-
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "simgrid/config.h"
-#include "simgrid/modelchecker.h"
-#include "src/kernel/EngineImpl.hpp"
-#include "src/kernel/activity/CommImpl.hpp"
-#include "src/kernel/actor/SimcallObserver.hpp"
-#include "src/mc/mc_replay.hpp"
-#include <simgrid/s4u/Activity.hpp>
-
-#define SIMIX_H_NO_DEPRECATED_WARNING // avoid deprecation warning on include (remove with XBT_ATTRIB_DEPRECATED_v335)
-#include <simgrid/simix.h>
-
-void simcall_comm_send(simgrid::kernel::actor::ActorImpl* sender, simgrid::kernel::activity::MailboxImpl* mbox,
-                       double task_size, double rate, void* src_buff, size_t src_buff_size,
-                       bool (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
-                       void (*copy_data_fun)(simgrid::kernel::activity::CommImpl*, void*, size_t), void* data,
-                       double timeout) // XBT_ATTRIB_DEPRECATED_v335
-{
-  xbt_assert(mbox, "No rendez-vous point defined for send");
-  simgrid::s4u::Comm::send(sender, mbox->get_iface(), task_size, rate, src_buff, src_buff_size, match_fun,
-                           copy_data_fun, data, timeout);
-}
-
-simgrid::kernel::activity::ActivityImplPtr
-simcall_comm_isend(simgrid::kernel::actor::ActorImpl* sender, simgrid::kernel::activity::MailboxImpl* mbox,
-                   double task_size, double rate, void* src_buff, size_t src_buff_size,
-                   bool (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*), void (*clean_fun)(void*),
-                   void (*copy_data_fun)(simgrid::kernel::activity::CommImpl*, void*, size_t), void* data,
-                   bool detached) // XBT_ATTRIB_DEPRECATED_v335
-{
-  /* checking for infinite values */
-  xbt_assert(std::isfinite(task_size), "task_size is not finite!");
-  xbt_assert(std::isfinite(rate), "rate is not finite!");
-
-  xbt_assert(mbox, "No rendez-vous point defined for isend");
-
-  simgrid::kernel::actor::CommIsendSimcall observer(sender, mbox, task_size, rate,
-                                                    static_cast<unsigned char*>(src_buff), src_buff_size, match_fun,
-                                                    clean_fun, copy_data_fun, data, detached);
-  return simgrid::kernel::actor::simcall_answered(
-      [&observer] { return simgrid::kernel::activity::CommImpl::isend(&observer); });
-}
-
-void simcall_comm_recv(simgrid::kernel::actor::ActorImpl* receiver, simgrid::kernel::activity::MailboxImpl* mbox,
-                       void* dst_buff, size_t* dst_buff_size,
-                       bool (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
-                       void (*copy_data_fun)(simgrid::kernel::activity::CommImpl*, void*, size_t), void* data,
-                       double timeout, double rate) // XBT_ATTRIB_DEPRECATED_v335
-{
-  xbt_assert(mbox, "No rendez-vous point defined for recv");
-  simgrid::s4u::Comm::recv(receiver, mbox->get_iface(), dst_buff, dst_buff_size, match_fun, copy_data_fun, data,
-                           timeout, rate);
-}
-
-simgrid::kernel::activity::ActivityImplPtr
-simcall_comm_irecv(simgrid::kernel::actor::ActorImpl* receiver, simgrid::kernel::activity::MailboxImpl* mbox,
-                   void* dst_buff, size_t* dst_buff_size,
-                   bool (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
-                   void (*copy_data_fun)(simgrid::kernel::activity::CommImpl*, void*, size_t), void* data,
-                   double rate) // XBT_ATTRIB_DEPRECATED_v335
-{
-  xbt_assert(mbox, "No rendez-vous point defined for irecv");
-
-  simgrid::kernel::actor::CommIrecvSimcall observer(receiver, mbox, static_cast<unsigned char*>(dst_buff),
-                                                    dst_buff_size, match_fun, copy_data_fun, data, rate);
-  return simgrid::kernel::actor::simcall_answered(
-      [&observer] { return simgrid::kernel::activity::CommImpl::irecv(&observer); });
-}
-
-ssize_t simcall_comm_waitany(simgrid::kernel::activity::CommImpl* comms[], size_t count,
-                             double timeout) // XBT_ATTRIB_DEPRECATED_v335
-{
-  std::vector<simgrid::kernel::activity::ActivityImpl*> activities;
-  for (size_t i = 0; i < count; i++)
-    activities.push_back(static_cast<simgrid::kernel::activity::ActivityImpl*>(comms[i]));
-  simgrid::kernel::actor::ActorImpl* issuer = simgrid::kernel::actor::ActorImpl::self();
-  simgrid::kernel::actor::ActivityWaitanySimcall observer{issuer, activities, timeout};
-  ssize_t changed_pos = simgrid::kernel::actor::simcall_blocking(
-      [&observer] {
-        simgrid::kernel::activity::ActivityImpl::wait_any_for(observer.get_issuer(), observer.get_activities(),
-                                                              observer.get_timeout());
-      },
-      &observer);
-  if (changed_pos != -1)
-    activities.at(changed_pos)->get_iface()->complete(simgrid::s4u::Activity::State::FINISHED);
-  return changed_pos;
-}
-
-ssize_t simcall_comm_testany(simgrid::kernel::activity::CommImpl* comms[], size_t count) // XBT_ATTRIB_DEPRECATED_v335
-{
-  if (count == 0)
-    return -1;
-  std::vector<simgrid::kernel::activity::ActivityImpl*> activities;
-  for (size_t i = 0; i < count; i++)
-    activities.push_back(static_cast<simgrid::kernel::activity::ActivityImpl*>(comms[i]));
-
-  simgrid::kernel::actor::ActorImpl* issuer = simgrid::kernel::actor::ActorImpl::self();
-  simgrid::kernel::actor::ActivityTestanySimcall observer{issuer, activities};
-  ssize_t changed_pos = simgrid::kernel::actor::simcall_blocking(
-      [&observer] {
-        simgrid::kernel::activity::ActivityImpl::test_any(observer.get_issuer(), observer.get_activities());
-      },
-      &observer);
-  if (changed_pos != -1)
-    comms[changed_pos]->get_iface()->complete(simgrid::s4u::Activity::State::FINISHED);
-  return changed_pos;
-}
-
-void simcall_comm_wait(simgrid::kernel::activity::ActivityImpl* comm, double timeout) // XBT_ATTRIB_DEPRECATED_v335
-{
-  xbt_assert(std::isfinite(timeout), "timeout is not finite!");
-  simgrid::kernel::actor::ActorImpl* issuer = simgrid::kernel::actor::ActorImpl::self();
-  simgrid::kernel::actor::simcall_blocking([issuer, comm, timeout] { comm->wait_for(issuer, timeout); });
-}
-
-bool simcall_comm_test(simgrid::kernel::activity::ActivityImpl* comm) // XBT_ATTRIB_DEPRECATED_v335
-{
-  simgrid::kernel::actor::ActorImpl* issuer = simgrid::kernel::actor::ActorImpl::self();
-  simgrid::kernel::actor::ActivityTestSimcall observer{issuer, comm};
-  if (simgrid::kernel::actor::simcall_blocking([&observer] { observer.get_activity()->test(observer.get_issuer()); },
-                                               &observer)) {
-    comm->get_iface()->complete(simgrid::s4u::Activity::State::FINISHED);
-    return true;
-  }
-  return false;
-}
index 106acd4..e444c0c 100644 (file)
@@ -332,248 +332,6 @@ const std::set<std::string, std::less<>>& get_tracing_categories()
 
 } // namespace simgrid::instr
 
-static xbt_dynar_t instr_set_to_dynar(const std::set<std::string, std::less<>>& filter) // XBT_ATTRIB_DEPRECATED_v334
-{
-  if (not TRACE_is_enabled() || not TRACE_needs_platform())
-    return nullptr;
-
-  xbt_dynar_t ret = xbt_dynar_new (sizeof(char*), &xbt_free_ref);
-  for (auto const& name : filter)
-    xbt_dynar_push_as(ret, char*, xbt_strdup(name.c_str()));
-
-  return ret;
-}
-
-void TRACE_category(const char* category) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_tracing_category(category);
-}
-
-void TRACE_category_with_color(const char* category, const char* color) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_tracing_category(category, color);
-}
-
-xbt_dynar_t TRACE_get_categories() // XBT_ATTRIB_DEPRECATED_v334
-{
-  if (not TRACE_is_enabled() || not TRACE_categorized())
-    return nullptr;
-  return instr_set_to_dynar(created_categories);
-}
-
-void TRACE_declare_mark(const char* mark_type) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_mark(mark_type);
-}
-
-void TRACE_declare_mark_value_with_color(const char* mark_type, const char* mark_value,
-                                         const char* mark_color) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_mark_value(mark_type, mark_value, mark_color);
-}
-
-void TRACE_declare_mark_value(const char* mark_type, const char* mark_value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_mark_value(mark_type, mark_value);
-}
-
-void TRACE_mark(const char* mark_type, const char* mark_value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::mark(mark_type, mark_value);
-}
-
-xbt_dynar_t TRACE_get_marks() // XBT_ATTRIB_DEPRECATED_v334
-{
-  if (not TRACE_is_enabled())
-    return nullptr;
-
-  return instr_set_to_dynar(declared_marks);
-}
-
-int TRACE_platform_graph_export_graphviz(const char* filename) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::platform_graph_export_graphviz(filename);
-  return 1;
-}
-
-void TRACE_vm_variable_declare(const char* variable) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(0, "", variable, "VM", 0, InstrUserVariable::DECLARE, "", &user_vm_variables);
-}
-void TRACE_vm_variable_declare_with_color(const char* variable, const char* color) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(0, "", variable, "VM", 0, InstrUserVariable::DECLARE, color, &user_vm_variables);
-}
-
-void TRACE_vm_variable_set(const char* vm, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), vm, variable, "VM", value, InstrUserVariable::SET, "", &user_vm_variables);
-}
-
-void TRACE_vm_variable_add(const char* vm, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), vm, variable, "VM", value, InstrUserVariable::ADD, "", &user_vm_variables);
-}
-void TRACE_vm_variable_sub(const char* vm, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), vm, variable, "VM", value, InstrUserVariable::SUB, "", &user_vm_variables);
-}
-
-void TRACE_vm_variable_set_with_time(double time, const char* vm, const char* variable,
-                                     double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, vm, variable, "VM", value, InstrUserVariable::SET, "", &user_vm_variables);
-}
-
-void TRACE_vm_variable_add_with_time(double time, const char* vm, const char* variable,
-                                     double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, vm, variable, "VM", value, InstrUserVariable::ADD, "", &user_vm_variables);
-}
-void TRACE_vm_variable_sub_with_time(double time, const char* vm, const char* variable,
-                                     double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, vm, variable, "VM", value, InstrUserVariable::SUB, "", &user_vm_variables);
-}
-
-void TRACE_host_variable_declare(const char* variable) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_host_variable(variable);
-}
-
-void TRACE_host_variable_declare_with_color(const char* variable, const char* color) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_host_variable(variable, color);
-}
-
-void TRACE_host_variable_set(const char* host, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), host, variable, "HOST", value, InstrUserVariable::SET, "",
-                      &user_host_variables);
-}
-
-void TRACE_host_variable_add(const char* host, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), host, variable, "HOST", value, InstrUserVariable::ADD, "",
-                      &user_host_variables);
-}
-
-void TRACE_host_variable_sub(const char* host, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), host, variable, "HOST", value, InstrUserVariable::SUB, "",
-                      &user_host_variables);
-}
-
-void TRACE_host_variable_set_with_time(double time, const char* host, const char* variable,
-                                       double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, host, variable, "HOST", value, InstrUserVariable::SET, "", &user_host_variables);
-}
-
-void TRACE_host_variable_add_with_time(double time, const char* host, const char* variable,
-                                       double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, host, variable, "HOST", value, InstrUserVariable::ADD, "", &user_host_variables);
-}
-
-void TRACE_host_variable_sub_with_time(double time, const char* host, const char* variable,
-                                       double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, host, variable, "HOST", value, InstrUserVariable::SUB, "", &user_host_variables);
-}
-
-xbt_dynar_t TRACE_get_host_variables() // XBT_ATTRIB_DEPRECATED_v334
-{
-  return instr_set_to_dynar(user_host_variables);
-}
-
-void TRACE_link_variable_declare(const char* variable) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_link_variable(variable);
-}
-
-void TRACE_link_variable_declare_with_color(const char* variable, const char* color) // XBT_ATTRIB_DEPRECATED_v334
-{
-  simgrid::instr::declare_link_variable(variable, color);
-}
-
-void TRACE_link_variable_set(const char* link, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), link, variable, "LINK", value, InstrUserVariable::SET, "",
-                      &user_link_variables);
-}
-
-void TRACE_link_variable_add(const char* link, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), link, variable, "LINK", value, InstrUserVariable::ADD, "",
-                      &user_link_variables);
-}
-
-void TRACE_link_variable_sub(const char* link, const char* variable, double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(simgrid_get_clock(), link, variable, "LINK", value, InstrUserVariable::SUB, "",
-                      &user_link_variables);
-}
-
-void TRACE_link_variable_set_with_time(double time, const char* link, const char* variable,
-                                       double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, link, variable, "LINK", value, InstrUserVariable::SET, "", &user_link_variables);
-}
-
-void TRACE_link_variable_add_with_time(double time, const char* link, const char* variable,
-                                       double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, link, variable, "LINK", value, InstrUserVariable::ADD, "", &user_link_variables);
-}
-
-void TRACE_link_variable_sub_with_time(double time, const char* link, const char* variable,
-                                       double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_variable(time, link, variable, "LINK", value, InstrUserVariable::SUB, "", &user_link_variables);
-}
-
-void TRACE_link_srcdst_variable_set(const char* src, const char* dst, const char* variable,
-                                    double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_srcdst_variable(simgrid_get_clock(), src, dst, variable, value, InstrUserVariable::SET);
-}
-
-void TRACE_link_srcdst_variable_add(const char* src, const char* dst, const char* variable,
-                                    double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_srcdst_variable(simgrid_get_clock(), src, dst, variable, value, InstrUserVariable::ADD);
-}
-
-void TRACE_link_srcdst_variable_sub(const char* src, const char* dst, const char* variable,
-                                    double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_srcdst_variable(simgrid_get_clock(), src, dst, variable, value, InstrUserVariable::SUB);
-}
-
-void TRACE_link_srcdst_variable_set_with_time(double time, const char* src, const char* dst, const char* variable,
-                                              double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_srcdst_variable(time, src, dst, variable, value, InstrUserVariable::SET);
-}
-
-void TRACE_link_srcdst_variable_add_with_time(double time, const char* src, const char* dst, const char* variable,
-                                              double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_srcdst_variable(time, src, dst, variable, value, InstrUserVariable::ADD);
-}
-
-void TRACE_link_srcdst_variable_sub_with_time(double time, const char* src, const char* dst, const char* variable,
-                                              double value) // XBT_ATTRIB_DEPRECATED_v334
-{
-  instr_user_srcdst_variable(time, src, dst, variable, value, InstrUserVariable::SUB);
-}
-
-xbt_dynar_t TRACE_get_link_variables() // XBT_ATTRIB_DEPRECATED_v334
-{
-  return instr_set_to_dynar(user_link_variables);
-}
-
 /** @ingroup TRACE_user_variables
  *  @brief Declare a new user state associated to hosts.
  *
index 694a04a..f7cbcc9 100644 (file)
@@ -14,6 +14,7 @@
 #include <xbt/graph.h>
 
 #include "src/instr/instr_private.hpp"
+#include "src/kernel/activity/ExecImpl.hpp"
 #include "src/kernel/resource/CpuImpl.hpp"
 #include "src/kernel/resource/NetworkModel.hpp"
 
@@ -347,6 +348,15 @@ static void on_host_creation(s4u::Host const& host)
     root->get_type()->by_name_or_create("MIGRATE_LINK", mpi, mpi);
     mpi->by_name_or_create<StateType>("MIGRATE_STATE");
   }
+
+   if (TRACE_actor_is_enabled()) {
+    auto* host_type = container->get_type();
+    auto* state     = host_type->by_name_or_create<StateType>("HOST_STATE");
+    state->set_calling_container(container);
+    state->add_entity_value("receive", "1 0 0");
+    state->add_entity_value("send", "0 0 1");
+    state->add_entity_value("execute", "0 1 1");
+  }
 }
 
 static void on_action_state_change(kernel::resource::Action const& action,
@@ -362,12 +372,17 @@ static void on_action_state_change(kernel::resource::Action const& action,
       resource_set_utilization("HOST", "speed_used", cpu->get_cname(), action.get_category(), value,
                                action.get_last_update(), simgrid_get_clock() - action.get_last_update());
 
-    if (const auto* link = dynamic_cast<kernel::resource::StandardLinkImpl*>(resource))
+    else if (const auto* link = dynamic_cast<kernel::resource::StandardLinkImpl*>(resource))
       resource_set_utilization("LINK", "bandwidth_used", link->get_cname(), action.get_category(), value,
                                action.get_last_update(), simgrid_get_clock() - action.get_last_update());
   }
 }
 
+static void on_activity_suspend_resume(s4u::Activity const& activity)
+{
+  on_action_state_change(*activity.get_impl()->model_action_, /*ignored*/ kernel::resource::Action::State::STARTED);
+}
+
 static void on_platform_created()
 {
   currentContainer.clear();
@@ -462,14 +477,15 @@ void define_callbacks()
 
   s4u::NetZone::on_creation_cb(on_netzone_creation);
 
-  kernel::resource::CpuAction::on_state_change.connect(on_action_state_change);
+  s4u::Host::on_exec_state_change_cb(on_action_state_change);
   s4u::Link::on_communication_state_change_cb(on_action_state_change);
+  s4u::Exec::on_suspend_cb(on_activity_suspend_resume);
+  s4u::Exec::on_resume_cb(on_activity_suspend_resume);
 
   if (TRACE_actor_is_enabled()) {
     s4u::Actor::on_creation_cb(on_actor_creation);
     s4u::Actor::on_destruction_cb([](s4u::Actor const& actor) {
-      auto container = Container::by_name_or_null(instr_pid(actor));
-      if (container != nullptr)
+      if (auto* container = Container::by_name_or_null(instr_pid(actor)))
         container->remove_from_parent();
     });
     s4u::Actor::on_suspend_cb([](s4u::Actor const& actor) {
@@ -482,11 +498,38 @@ void define_callbacks()
     });
     s4u::Actor::on_wake_up_cb(
         [](s4u::Actor const& actor) { Container::by_name(instr_pid(actor))->get_state("ACTOR_STATE")->pop_event(); });
-    s4u::Exec::on_start_cb([](s4u::Exec const&) {
-      Container::by_name(instr_pid(*s4u::Actor::self()))->get_state("ACTOR_STATE")->push_event("execute");
+
+    s4u::Exec::on_start_cb([](s4u::Exec const& e) {
+      std::string pid = instr_pid(*s4u::Actor::self());
+      if (pid == "-0") //Exec is launched directly by Maestro, use the host as container
+        Container::by_name(e.get_host()->get_name())->get_state("HOST_STATE")->push_event("execute");
+      else
+        Container::by_name(pid)->get_state("ACTOR_STATE")->push_event("execute");
+    });
+
+    s4u::Exec::on_completion_cb([](const s4u::Exec& e) {
+      std::string pid = instr_pid(*s4u::Actor::self());
+      if (pid == "-0") //Exec is launched directly by Maestro, use the host as container
+        Container::by_name(e.get_host()->get_name())->get_state("HOST_STATE")->pop_event();
+      else
+        Container::by_name(pid)->get_state("ACTOR_STATE")->pop_event();
+    });
+
+    s4u::Comm::on_completion_cb([](const s4u::Comm& c) {
+      if (c.get_sender()) {
+        Container::by_name(instr_pid(*c.get_sender()))->get_state("ACTOR_STATE")->pop_event();
+        Container::by_name(instr_pid(*c.get_receiver()))->get_state("ACTOR_STATE")->pop_event();
+      } else {
+        Container::by_name(c.get_source()->get_name())->get_state("HOST_STATE")->pop_event();
+        Container::by_name(c.get_destination()->get_name())->get_state("HOST_STATE")->pop_event();
+      }
     });
-    s4u::Activity::on_completion_cb([](const s4u::Activity&) {
-      Container::by_name(instr_pid(*s4u::Actor::self()))->get_state("ACTOR_STATE")->pop_event();
+    s4u::Comm::on_start_cb([](s4u::Comm const& c) {
+      std::string pid = instr_pid(*s4u::Actor::self());
+      if (pid == "-0") { //Comm is launched directly by Maestro, use the host as container
+        Container::by_name(c.get_source()->get_name())->get_state("HOST_STATE")->push_event("start");
+        Container::by_name(c.get_destination()->get_name())->get_state("HOST_STATE")->push_event("start");
+      }
     });
     s4u::Comm::on_send_cb([](s4u::Comm const&) {
       Container::by_name(instr_pid(*s4u::Actor::self()))->get_state("ACTOR_STATE")->push_event("send");
@@ -503,7 +546,7 @@ void define_callbacks()
           ->get_state("MPI_STATE")
           ->push_event("computing", new CpuTIData("compute", exec.get_cost()));
     });
-    s4u::Activity::on_completion_cb([](const s4u::Activity&) {
+    s4u::Exec::on_completion_cb([](const s4u::Exec&) {
       Container::by_name("rank-" + std::to_string(s4u::Actor::self()->get_pid()))->get_state("MPI_STATE")->pop_event();
     });
   }
index 1108fea..d063328 100644 (file)
@@ -24,6 +24,7 @@ XBT_PRIVATE void TRACE_smpi_init(aid_t pid, const std::string& calling_func);
 
 class smpi_trace_call_location_t {
 public:
+  std::string func_call;
   std::string filename;
   int linenumber = 0;
 
@@ -35,6 +36,8 @@ public:
     return previous_filename + ':' + std::to_string(previous_linenumber) + ':' + filename + ':' +
            std::to_string(linenumber);
   }
+
+  std::string get_call_location() const { return filename + ":" + std::to_string(linenumber) + ":" + func_call + "()"; }
 };
 
 #endif
index e13c6ff..59761d5 100644 (file)
@@ -59,8 +59,6 @@
 #define PTH_STACKGROWTH @PTH_STACKGROWTH@
 
 /* MC variables */
-/* Did we compile mmalloc in? */
-#cmakedefine01 HAVE_MMALLOC
 /* process_vm_readv: transfer data between process address spaces */
 #cmakedefine01 HAVE_PROCESS_VM_READV
 
@@ -82,8 +80,6 @@
 /* Other function checks */
 /* Function dlfunc */
 #cmakedefine01 HAVE_DLFUNC
-/* Function mmap */
-#cmakedefine01 HAVE_MMAP
 /* Function mremap */
 #cmakedefine01 HAVE_MREMAP
 /* Function vasprintf */
@@ -95,3 +91,5 @@
 /* The boost_stacktrace_backtrace library */
 #cmakedefine01 HAVE_BOOST_STACKTRACE_BACKTRACE /* preferred */
 #cmakedefine01 HAVE_BOOST_STACKTRACE_ADDR2LINE /* fallback */
+/* Whether the ns-3 library has GetNextEventTime */
+#cmakedefine01 SIMGRID_HAVE_NS3_GetNextEventTime
index f7af9b4..8b7b60a 100644 (file)
 #include "src/kernel/resource/profile/Profile.hpp"
 #include "src/kernel/xml/platf.hpp"
 #include "src/mc/mc.h"
+#include "src/mc/mc_config.hpp"
 #include "src/mc/mc_record.hpp"
 #include "src/mc/mc_replay.hpp"
 #include "src/simgrid/math_utils.h"
 #include "src/simgrid/sg_config.hpp"
 #include "src/smpi/include/smpi_actor.hpp"
 
+#if SIMGRID_HAVE_MC
+#include "src/mc/remote/AppSide.hpp"
+#endif
+
 #include "xbt/log.hpp"
 
 #include <boost/algorithm/string/predicate.hpp>
 #include <dlfcn.h>
 
-#if SIMGRID_HAVE_MC
-#include "src/mc/remote/AppSide.hpp"
-#endif
-
 XBT_LOG_NEW_DEFAULT_CATEGORY(ker_engine, "Logging specific to Engine (kernel)");
 
 namespace simgrid::kernel {
@@ -154,6 +155,9 @@ EngineImpl::~EngineImpl()
   for (auto const& [_, mailbox] : mailboxes_)
     delete mailbox;
 
+  for (auto const& [_, queue] : mqueues_)
+    delete queue;
+
   /* Kill all actors (but maestro) */
   maestro_->kill_all();
   run_all_actors();
@@ -175,7 +179,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();
+  simgrid::mc::AppSide::get(); // To ensure that it's initialized
 #endif
 
   if (static bool inited = false; not inited) {
@@ -193,9 +197,6 @@ void EngineImpl::initialize(int* argc, char** argv)
 
   install_signal_handlers();
 
-  /* register a function to be called after the environment creation */
-  s4u::Engine::on_platform_created_cb([this]() { this->presolve(); });
-
   if (cfg_dbg_clean_atexit)
     atexit(shutdown);
 }
@@ -323,7 +324,7 @@ void EngineImpl::load_deployment(const std::string& file) const
   sg_platf_parser_finalize();
 
   simgrid_parse_open(file);
-  simgrid_parse();
+  simgrid_parse(false);
   simgrid_parse_close();
 }
 
@@ -358,24 +359,27 @@ void EngineImpl::handle_ended_actions() const
     while (auto* action = model->extract_failed_action()) {
       XBT_DEBUG("   Handling Action %p", action);
       if (action->get_activity() != nullptr) { // Skip vcpu actions
+        activity::ActivityImplPtr activity(action->get_activity());
         // Action failures are not automatically reported when the action is started by maestro (as in SimDAG)
-        if (action->get_activity()->get_actor() == maestro_)
-          action->get_activity()->get_iface()->complete(s4u::Activity::State::FAILED);
+        if (activity->get_actor() == maestro_)
+          activity->get_iface()->complete(s4u::Activity::State::FAILED);
 
-        activity::ActivityImplPtr(action->get_activity())->finish();
+        activity->finish();
       }
     }
     XBT_DEBUG("Handling the terminated actions (if any)");
     while (auto* action = model->extract_done_action()) {
       XBT_DEBUG("   Handling Action %p", action);
       if (action->get_activity() != nullptr) {
+        activity::ActivityImplPtr activity(action->get_activity());
+
         // Action termination are not automatically reported when the action is started by maestro (as in SimDAG)
-        action->get_activity()->set_finish_time(action->get_finish_time());
+        activity->set_finish_time(action->get_finish_time());
 
-        if (action->get_activity()->get_actor() == maestro_)
-          action->get_activity()->get_iface()->complete(s4u::Activity::State::FINISHED);
+        if (activity->get_actor() == maestro_)
+          activity->get_iface()->complete(s4u::Activity::State::FINISHED);
 
-        activity::ActivityImplPtr(action->get_activity())->finish();
+        activity->finish();
       }
     }
   }
@@ -452,6 +456,9 @@ void EngineImpl::display_all_actor_status() const
       if (boost::dynamic_pointer_cast<kernel::activity::CommImpl>(actor->waiting_synchro_) != nullptr)
         synchro_description = "communication";
 
+      if (boost::dynamic_pointer_cast<kernel::activity::MessImpl>(actor->waiting_synchro_) != nullptr)
+        synchro_description = "message";
+
       if (boost::dynamic_pointer_cast<kernel::activity::SleepImpl>(actor->waiting_synchro_) != nullptr)
         synchro_description = "sleeping";
 
@@ -476,27 +483,6 @@ void EngineImpl::display_all_actor_status() const
   }
 }
 
-void EngineImpl::presolve() const
-{
-  XBT_DEBUG("Consume all trace events occurring before the starting time.");
-  double next_event_date;
-  while ((next_event_date = profile::future_evt_set.next_date()) != -1.0) {
-    if (next_event_date > now_)
-      break;
-
-    double value                 = -1.0;
-    resource::Resource* resource = nullptr;
-    while (auto* event = profile::future_evt_set.pop_leq(next_event_date, &value, &resource)) {
-      if (value >= 0)
-        resource->apply_event(event, value);
-    }
-  }
-
-  XBT_DEBUG("Set every models in the right state by updating them to 0.");
-  for (auto const& model : models_)
-    model->update_actions_state(now_, 0.0);
-}
-
 double EngineImpl::solve(double max_date) const
 {
   double time_delta            = -1.0; /* duration */
@@ -510,10 +496,10 @@ double EngineImpl::solve(double max_date) const
   }
 
   XBT_DEBUG("Looking for next event in all models");
-  for (auto model : models_) {
-    if (not model->next_occurring_event_is_idempotent()) {
+  for (auto* model : models_) {
+    if (not model->next_occurring_event_is_idempotent())
       continue;
-    }
+
     double next_event = model->next_occurring_event(now_);
     if ((time_delta < 0.0 || next_event < time_delta) && next_event >= 0.0) {
       time_delta = next_event;
@@ -528,7 +514,7 @@ double EngineImpl::solve(double max_date) const
     double next_event_date = profile::future_evt_set.next_date();
     XBT_DEBUG("Next TRACE event: %f", next_event_date);
 
-    for (auto model : models_) {
+    for (auto* model : models_) {
       /* Skip all idempotent models, they were already treated above
        * NS3 is the one to handled here */
       if (model->next_occurring_event_is_idempotent())
@@ -604,6 +590,9 @@ void EngineImpl::run(double max_date)
 {
   seal_platform();
 
+  XBT_DEBUG("Running the main loop until t=%.3f in mode %s", max_date,
+            to_c_str(simgrid::mc::get_model_checking_mode()));
+
   if (MC_is_active()) {
 #if SIMGRID_HAVE_MC
     mc::AppSide::get()->main_loop();
index 6862409..149c0c2 100644 (file)
 #include "src/kernel/activity/ExecImpl.hpp"
 #include "src/kernel/activity/IoImpl.hpp"
 #include "src/kernel/activity/MailboxImpl.hpp"
+#include "src/kernel/activity/MessageQueueImpl.hpp"
 #include "src/kernel/activity/SleepImpl.hpp"
 #include "src/kernel/activity/Synchro.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
-#include "src/kernel/resource/SplitDuplexLinkImpl.hpp"
 
 #include <boost/intrusive/list.hpp>
 #include <map>
@@ -34,6 +34,7 @@ namespace simgrid::kernel {
 class EngineImpl {
   std::unordered_map<std::string, routing::NetPoint*> netpoints_;
   std::unordered_map<std::string, activity::MailboxImpl*> mailboxes_;
+  std::unordered_map<std::string, activity::MessageQueueImpl*> mqueues_;
 
   std::unordered_map<std::string, actor::ActorCodeFactory> registered_functions; // Maps function names to actor code
   actor::ActorCodeFactory default_function; // Function to use as a fallback when the provided name matches nothing
@@ -152,10 +153,6 @@ public:
   void display_all_actor_status() const;
   void run_all_actors();
 
-  /*  @brief Finish simulation initialization
-   *  This function must be called before the first call to solve()
-   */
-  void presolve() const;
   /** @brief Performs a part of the simulation
    *  @param max_date Maximum date to update the simulation to, or -1
    *  @return the elapsed time, or -1.0 if no event could be executed
index f425dc8..f1a9859 100644 (file)
@@ -108,6 +108,10 @@ void ActivityImpl::wait_for(actor::ActorImpl* issuer, double timeout)
   if (state_ != State::WAITING && state_ != State::RUNNING) {
     finish();
   } else {
+    /* As Messages in Message Queues are virtually instantaneous, we do not need a timeout */
+    /* Or maybe we do, and will have to implement a specific way to handle them is need arises */
+    if (dynamic_cast<MessImpl*>(this) != nullptr)
+      return;
     /* we need a sleep action (even when the timeout is infinite) to be notified of host failures */
     /* Comms handle that a bit differently of the other activities */
     if (auto* comm = dynamic_cast<CommImpl*>(this)) {
@@ -142,7 +146,7 @@ void ActivityImpl::wait_any_for(actor::ActorImpl* issuer, const std::vector<Acti
     xbt_assert(timeout <= 0.0, "Timeout not implemented for waitany in the model-checker");
     if (int idx = observer->get_value(); idx != -1) {
       auto* act = activities.at(idx);
-      act->simcalls_.push_back(&issuer->simcall_);
+      act->register_simcall(&issuer->simcall_);
       observer->set_result(idx);
       act->set_state(State::DONE);
       act->finish();
@@ -164,7 +168,7 @@ void ActivityImpl::wait_any_for(actor::ActorImpl* issuer, const std::vector<Acti
 
   for (auto* act : activities) {
     /* associate this simcall to the the synchro */
-    act->simcalls_.push_back(&issuer->simcall_);
+    act->register_simcall(&issuer->simcall_);
     /* see if the synchro is already finished */
     if (act->get_state() != State::WAITING && act->get_state() != State::RUNNING) {
       act->finish();
@@ -176,11 +180,10 @@ void ActivityImpl::wait_any_for(actor::ActorImpl* issuer, const std::vector<Acti
 
 void ActivityImpl::suspend()
 {
-  if (model_action_ == nullptr)
-    return;
   XBT_VERB("This activity is suspended (remain: %f)", model_action_->get_remains());
+  get_iface()->fire_on_suspend();
+  get_iface()->fire_on_this_suspend();
   model_action_->suspend();
-  s4u::Activity::on_suspended(*get_iface());
 }
 
 void ActivityImpl::resume()
@@ -188,8 +191,9 @@ void ActivityImpl::resume()
   if (model_action_ == nullptr)
     return;
   XBT_VERB("This activity is resumed (remain: %f)", model_action_->get_remains());
+  get_iface()->fire_on_resume();
+  get_iface()->fire_on_this_resume();
   model_action_->resume();
-  s4u::Activity::on_resumed(*get_iface());
 }
 
 void ActivityImpl::cancel()
index 44ec50b..f264993 100644 (file)
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_network, kernel, "Kernel network-related synchronization");
 
 namespace simgrid::kernel::activity {
-xbt::signal<void(CommImpl const&)> CommImpl::on_start;
-xbt::signal<void(CommImpl const&)> CommImpl::on_completion;
+
+unsigned CommImpl::next_id_ = 0;
 
 std::function<void(CommImpl*, void*, size_t)> CommImpl::copy_data_callback_ = [](kernel::activity::CommImpl* comm,
                                                                                  void* buff, size_t buff_size) {
   xbt_assert((buff_size == sizeof(void*)), "Cannot copy %zu bytes: must be sizeof(void*)", buff_size);
-  *(void**)(comm->dst_buff_) = buff;
+  if (comm->dst_buff_ != nullptr) // get_async provided a buffer
+    *(void**)(comm->dst_buff_) = buff;
+  comm->payload_ = buff; // Setup what will be retrieved by s4u::Comm::get_payload()
 };
 
 void CommImpl::set_copy_data_callback(const std::function<void(CommImpl*, void*, size_t)>& callback)
@@ -133,7 +135,6 @@ CommImpl* CommImpl::start()
     model_action_->set_category(get_tracing_category());
     set_start_time(model_action_->get_start_time());
     set_state(State::RUNNING);
-    on_start(*this);
 
     XBT_DEBUG("Starting communication %p from '%s' to '%s' (model action: %p; state: %s)", this, from_->get_cname(),
               to_->get_cname(), model_action_, get_state_str());
@@ -167,7 +168,7 @@ CommImpl* CommImpl::start()
 
 std::vector<s4u::Link*> CommImpl::get_traversed_links() const
 {
-  xbt_assert(get_state() != State::WAITING, "You cannot use %s() if your communication is not ready (%s)", __FUNCTION__,
+  xbt_assert(get_state() != State::WAITING, "You cannot use %s() if your communication is not ready (%s)", __func__,
              get_state_str());
   std::vector<s4u::Link*> vlinks;
   XBT_ATTRIB_UNUSED double res = 0;
@@ -180,7 +181,7 @@ void CommImpl::copy_data()
 {
   size_t buff_size = src_buff_size_;
   /* If there is no data to copy then return */
-  if (not src_buff_ || not dst_buff_ || copied_)
+  if (not src_buff_ || not dst_buff_size_ || copied_)
     return;
 
   XBT_DEBUG("Copying comm %p data from %s (%p) -> %s (%p) (%zu bytes)", this,
@@ -471,7 +472,12 @@ void CommImpl::finish()
   XBT_DEBUG("CommImpl::finish() comm %p, state %s, src_proc %p, dst_proc %p, detached: %d", this, get_state_str(),
             src_actor_.get(), dst_actor_.get(), detached_);
 
-  on_completion(*this);
+  if (get_iface()) {
+    const auto& piface = static_cast<const s4u::Comm&>(*get_iface());
+    set_iface(nullptr); // reset iface to protect against multiple trigger of the on_completion signals
+    piface.fire_on_completion_for_real();
+    piface.fire_on_this_completion_for_real();
+  }
 
   /* Update synchro state */
   if (src_timeout_ && src_timeout_->get_state() == resource::Action::State::FINISHED)
index 32fef45..4f249a4 100644 (file)
@@ -32,6 +32,9 @@ class XBT_PUBLIC CommImpl : public ActivityImpl_T<CommImpl> {
   s4u::Host* to_     = nullptr; /* Otherwise, computed at start() time from the actors */
   CommImplType type_ = CommImplType::SEND; /* Type of the communication (SEND or RECEIVE) */
 
+  static unsigned next_id_;        // Next ID to be given (for MC)
+  const unsigned id_ = ++next_id_; // ID of this comm (for MC) -- 0 as an ID denotes "invalid/unknown comm"
+
 public:
   CommImpl() = default;
 
@@ -52,7 +55,8 @@ public:
 
   double get_rate() const { return rate_; }
   MailboxImpl* get_mailbox() const { return mbox_; }
-  long get_mailbox_id() const { return mbox_id_; }
+  unsigned get_mailbox_id() const { return mbox_id_; }
+  unsigned get_id() const { return id_; }
   bool is_detached() const { return detached_; }
   bool is_assigned() const { return (to_ != nullptr && from_ != nullptr); }
 
@@ -91,11 +95,10 @@ expectations of the other side, too. See  */
   unsigned char* dst_buff_ = nullptr;
   size_t src_buff_size_    = 0;
   size_t* dst_buff_size_   = nullptr;
+  void* payload_           = nullptr; // If dst_buff_ is NULL, the default copy callback puts the data here
 
   void* src_data_ = nullptr; /* User data associated to the communication */
   void* dst_data_ = nullptr;
-  static xbt::signal<void(CommImpl const&)> on_start;
-  static xbt::signal<void(CommImpl const&)> on_completion;
 };
 } // namespace simgrid::kernel::activity
 
index 2315ebe..ec3fb6a 100644 (file)
@@ -6,7 +6,7 @@
 #include "src/kernel/activity/ConditionVariableImpl.hpp"
 #include "src/kernel/activity/MutexImpl.hpp"
 #include "src/kernel/activity/Synchro.hpp"
-#include "src/kernel/actor/SimcallObserver.hpp"
+#include "src/kernel/actor/SynchroObserver.hpp"
 #include <cmath> // std::isfinite
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_condition, ker_synchro, "Condition variables kernel-space implementation");
@@ -35,7 +35,7 @@ void ConditionVariableImpl::signal()
 
     /* Now transform the cond wait simcall into a mutex lock one */
     actor::Simcall* simcall = &proc.simcall_;
-    const auto* observer  = dynamic_cast<kernel::actor::ConditionWaitSimcall*>(simcall->observer_);
+    const auto* observer    = dynamic_cast<kernel::actor::ConditionVariableObserver*>(simcall->observer_);
     xbt_assert(observer != nullptr);
     observer->get_mutex()->lock_async(simcall->issuer_)->wait_for(simcall->issuer_, -1);
   }
@@ -62,18 +62,18 @@ void ConditionVariableImpl::wait(MutexImpl* mutex, double timeout, actor::ActorI
   XBT_DEBUG("Wait condition %p", this);
   xbt_assert(std::isfinite(timeout), "timeout is not finite!");
 
-  /* If there is a mutex unlock it */
-  if (mutex != nullptr) {
-    xbt_assert(mutex->get_owner() == issuer,
-               "Actor %s cannot wait on ConditionVariable %p since it does not own the provided mutex %p",
-               issuer->get_cname(), this, mutex);
-    mutex_ = mutex;
-    mutex->unlock(issuer);
-  }
+  /* Unlock the provided mutex (the simcall observer ensures that one is provided, no need to check) */
+  auto* owner = mutex->get_owner();
+  xbt_assert(owner == issuer,
+             "Actor %s cannot wait on ConditionVariable %p since it does not own the provided mutex %p (which is "
+             "owned by %s).",
+             issuer->get_cname(), this, mutex, (owner == nullptr ? "nobody" : owner->get_cname()));
+  mutex_ = mutex;
+  mutex->unlock(issuer);
 
   SynchroImplPtr synchro(new SynchroImpl([this, issuer]() {
     this->remove_sleeping_actor(*issuer);
-    auto* observer = dynamic_cast<kernel::actor::ConditionWaitSimcall*>(issuer->simcall_.observer_);
+    auto* observer = dynamic_cast<kernel::actor::ConditionVariableObserver*>(issuer->simcall_.observer_);
     xbt_assert(observer != nullptr);
     observer->set_result(true);
   }));
index 834b9e3..a142e90 100644 (file)
@@ -7,7 +7,9 @@
 #define SIMGRID_KERNEL_ACTIVITY_CONDITIONVARIABLE_HPP
 
 #include "simgrid/s4u/ConditionVariable.hpp"
+#include "src/kernel/activity/ActivityImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
+
 #include <boost/intrusive/list.hpp>
 
 namespace simgrid::kernel::activity {
index cb49f3b..aaeeb83 100644 (file)
@@ -46,7 +46,7 @@ void MailboxImpl::set_receiver(s4u::ActorPtr actor)
 /** @brief Pushes a communication activity into a mailbox
  *  @param comm What to add
  */
-void MailboxImpl::push(CommImplPtr comm)
+void MailboxImpl::push(const CommImplPtr& comm)
 {
   comm->set_mailbox(this);
   this->comm_queue_.push_back(std::move(comm));
@@ -61,12 +61,11 @@ void MailboxImpl::remove(const CommImplPtr& comm)
              (comm->get_mailbox() ? comm->get_mailbox()->get_cname() : "(null)"), this->get_cname());
 
   comm->set_mailbox(nullptr);
-  for (auto it = this->comm_queue_.begin(); it != this->comm_queue_.end(); it++)
-    if (*it == comm) {
-      this->comm_queue_.erase(it);
-      return;
-    }
-  xbt_die("Comm %p not found in mailbox %s", comm.get(), this->get_cname());
+  auto it = std::find(this->comm_queue_.begin(), this->comm_queue_.end(), comm);
+  if (it != this->comm_queue_.end())
+    this->comm_queue_.erase(it);
+  else
+    xbt_die("Comm %p not found in mailbox %s", comm.get(), this->get_cname());
 }
 
 /** @brief Removes all communication activities from a mailbox
@@ -74,7 +73,7 @@ void MailboxImpl::remove(const CommImplPtr& comm)
 void MailboxImpl::clear(bool do_finish)
 {
   // CommImpl::cancel() will remove the comm from the mailbox..
-  for (auto comm : done_comm_queue_) {
+  for (const auto& comm : done_comm_queue_) {
     comm->cancel();
     comm->set_state(State::FAILED);
     if (do_finish)
index 199fcd1..172bda4 100644 (file)
@@ -6,26 +6,24 @@
 #ifndef SIMGRID_KERNEL_ACTIVITY_MAILBOX_HPP
 #define SIMGRID_KERNEL_ACTIVITY_MAILBOX_HPP
 
+#include "simgrid/config.h" /* FIXME: KILLME. This makes the ABI config-dependent, but mandatory for the hack below */
 #include "simgrid/s4u/Engine.hpp"
 #include "simgrid/s4u/Mailbox.hpp"
 #include "src/kernel/activity/CommImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
 
-#include <boost/circular_buffer.hpp>
-
 namespace simgrid::kernel::activity {
 
 /** @brief Implementation of the s4u::Mailbox */
 
 class MailboxImpl {
-  static constexpr size_t MAX_MAILBOX_SIZE = 10000000;
-
   s4u::Mailbox piface_;
   std::string name_;
   actor::ActorImplPtr permanent_receiver_; // actor to which the mailbox is attached
-  boost::circular_buffer_space_optimized<CommImplPtr> comm_queue_{MAX_MAILBOX_SIZE};
+
+  std::deque<CommImplPtr> comm_queue_;
   // messages already received in the permanent receive mode
-  boost::circular_buffer_space_optimized<CommImplPtr> done_comm_queue_{MAX_MAILBOX_SIZE};
+  std::deque<CommImplPtr> done_comm_queue_;
 
   friend s4u::Engine;
   friend s4u::Mailbox;
@@ -50,8 +48,8 @@ public:
   const std::string& get_name() const { return name_; }
   const char* get_cname() const { return name_.c_str(); }
   void set_receiver(s4u::ActorPtr actor);
-  void push(CommImplPtr comm);
-  void push_done(CommImplPtr done_comm) { done_comm_queue_.push_back(done_comm); }
+  void push(const CommImplPtr& comm);
+  void push_done(const CommImplPtr& done_comm) { done_comm_queue_.push_back(done_comm); }
   void remove(const CommImplPtr& comm);
   void clear(bool do_finish);
   CommImplPtr iprobe(int type, const std::function<bool(void*, void*, CommImpl*)>& match_fun, void* data);
@@ -61,9 +59,9 @@ public:
   actor::ActorImplPtr get_permanent_receiver() const { return permanent_receiver_; }
   bool empty() const { return comm_queue_.empty(); }
   size_t size() const { return comm_queue_.size(); }
-  CommImplPtr front() const { return comm_queue_.front(); }
+  const CommImplPtr& front() const { return comm_queue_.front(); }
   bool has_some_done_comm() const { return not done_comm_queue_.empty(); }
-  CommImplPtr done_front() const { return done_comm_queue_.front(); }
+  const CommImplPtr& done_front() const { return done_comm_queue_.front(); }
 };
 } // namespace simgrid::kernel::activity
 
diff --git a/src/kernel/activity/MessImpl.cpp b/src/kernel/activity/MessImpl.cpp
new file mode 100644 (file)
index 0000000..3a3e307
--- /dev/null
@@ -0,0 +1,196 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <simgrid/Exception.hpp>
+#include <simgrid/s4u/Host.hpp>
+
+#include "src/kernel/EngineImpl.hpp"
+#include "src/kernel/activity/MessImpl.hpp"
+#include "src/kernel/activity/MessageQueueImpl.hpp"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_mess, kernel, "Kernel message synchronization");
+
+namespace simgrid::kernel::activity {
+
+MessImpl::~MessImpl()
+{
+  if (queue_)
+    queue_->remove(this);
+}
+
+MessImpl& MessImpl::set_type(MessImplType type)
+{
+  type_ = type;
+  return *this;
+}
+
+MessImpl& MessImpl::set_queue(MessageQueueImpl* queue)
+{
+  queue_ = queue;
+  return *this;
+}
+
+MessImpl& MessImpl::set_payload(void* payload)
+{
+  payload_ = payload;
+  return *this;
+}
+
+MessImpl& MessImpl::set_dst_buff(unsigned char* buff, size_t* size)
+{
+  dst_buff_      = buff;
+  dst_buff_size_ = size;
+  return *this;
+}
+
+MessImpl* MessImpl::start()
+{
+  if (get_state() == State::READY) {
+    XBT_DEBUG("Starting message exchange %p from '%s' to '%s' (state: %s)", this, src_actor_->get_host()->get_cname(),
+              dst_actor_->get_host()->get_cname(), get_state_str());
+    set_state(State::RUNNING);
+    finish();
+  }
+  return this;
+}
+
+ActivityImplPtr MessImpl::iput(actor::MessIputSimcall* observer)
+{
+  auto* queue = observer->get_queue();
+  XBT_DEBUG("put from message queue %p", queue);
+
+  /* Prepare a synchro describing us, so that it gets passed to the user-provided filter of other side */
+  MessImplPtr this_mess(new MessImpl());
+  this_mess->set_type(MessImplType::PUT);
+
+  /* Look for message synchro matching our needs.
+   *
+   * If it is not found then push our communication into the rendez-vous point */
+  MessImplPtr other_mess = queue->find_matching_message(MessImplType::GET);
+
+  if (not other_mess) {
+    other_mess = std::move(this_mess);
+    queue->push(other_mess);
+  } else {
+    XBT_DEBUG("Get already pushed");
+    other_mess->set_state(State::READY);
+  }
+
+  observer->set_message(other_mess.get());
+  observer->get_issuer()->activities_.insert(other_mess);
+
+  /* Setup synchro */
+  other_mess->src_actor_ = observer->get_issuer();
+  other_mess->payload_ = observer->get_payload();
+  other_mess->start();
+
+  return other_mess;
+}
+
+ActivityImplPtr MessImpl::iget(actor::MessIgetSimcall* observer)
+{
+  MessImplPtr this_mess(new MessImpl());
+  this_mess->set_type(MessImplType::GET);
+
+  auto* queue = observer->get_queue();
+  XBT_DEBUG("get from message queue %p. this_synchro=%p", queue, this_mess.get());
+
+  MessImplPtr other_mess = queue->find_matching_message(MessImplType::PUT);
+
+  if (other_mess == nullptr) {
+    XBT_DEBUG("Get pushed first (%zu comm enqueued so far)", queue->size());
+    other_mess = std::move(this_mess);
+    queue->push(other_mess);
+  } else {
+    XBT_DEBUG("Match my %p with the existing %p", this_mess.get(), other_mess.get());
+
+    other_mess->set_state(State::READY);
+  }
+
+  observer->get_issuer()->activities_.insert(other_mess);
+  observer->set_message(other_mess.get());
+
+  /* Setup synchro */
+  other_mess->set_dst_buff(observer->get_dst_buff(), observer->get_dst_buff_size());
+  other_mess->dst_actor_ = observer->get_issuer();
+
+  other_mess->start();
+
+  return other_mess;
+}
+
+void MessImpl::wait_for(actor::ActorImpl* issuer, double timeout)
+{
+  XBT_DEBUG("MessImpl::wait_for(%g), %p, state %s", timeout, this, get_state_str());
+
+  /* Associate this simcall to the wait synchro */
+  register_simcall(&issuer->simcall_);
+  ActivityImpl::wait_for(issuer, timeout);
+}
+
+void MessImpl::cancel()
+{
+  /* if the synchro is a waiting state means that it is still in a mbox so remove from it and delete it */
+  if (get_state() == State::WAITING) {
+      queue_->remove(this);
+      set_state(State::CANCELED);
+  }
+}
+
+void MessImpl::finish()
+{
+  XBT_DEBUG("MessImpl::finish() mess %p, state %s, src_proc %p, dst_proc %p", this, get_state_str(),
+            src_actor_.get(), dst_actor_.get());
+
+  if (get_iface()) {
+    const auto& piface = static_cast<const s4u::Mess&>(*get_iface());
+    set_iface(nullptr); // reset iface to protect against multiple trigger of the on_completion signals
+    piface.fire_on_completion_for_real();
+    piface.fire_on_this_completion_for_real();
+  }
+
+  /* Update synchro state */
+  if (get_state() == State::RUNNING) {
+    set_state(State::DONE);
+  }
+
+  /* If the synchro is still in a rendez-vous point then remove from it */
+  if (queue_)
+    queue_->remove(this);
+
+  if (get_state() == State::DONE && payload_ != nullptr)
+    *(void**)(dst_buff_) = payload_;
+
+  while (not simcalls_.empty()) {
+    actor::Simcall* simcall = simcalls_.front();
+    simcalls_.pop_front();
+
+    /* If a waitany simcall is waiting for this synchro to finish, then remove it from the other synchros in the waitany
+     * list. Afterwards, get the position of the actual synchro in the waitany list and return it as the result of the
+     * simcall */
+
+    if (simcall->call_ == actor::Simcall::Type::NONE) // FIXME: maybe a better way to handle this case
+      continue;                                       // if actor handling comm is killed
+
+    handle_activity_waitany(simcall);
+
+    /* Check out for errors */
+
+    if (not simcall->issuer_->get_host()->is_on()) {
+      simcall->issuer_->set_wannadie();
+    } else {
+      // Do not answer to dying actors
+      if (not simcall->issuer_->wannadie()) {
+        set_exception(simcall->issuer_);
+        simcall->issuer_->simcall_answer();
+      }
+    }
+
+    simcall->issuer_->waiting_synchro_ = nullptr;
+    simcall->issuer_->activities_.erase(this);
+  }
+}
+
+} // namespace simgrid::kernel::activity
diff --git a/src/kernel/activity/MessImpl.hpp b/src/kernel/activity/MessImpl.hpp
new file mode 100644 (file)
index 0000000..2b2932f
--- /dev/null
@@ -0,0 +1,53 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_KERNEL_ACTIVITY_MESS_HPP
+#define SIMGRID_KERNEL_ACTIVITY_MESS_HPP
+
+#include "src/kernel/activity/ActivityImpl.hpp"
+#include "src/kernel/actor/ActorImpl.hpp"
+#include "src/kernel/actor/CommObserver.hpp"
+
+namespace simgrid::kernel::activity {
+
+enum class MessImplType { PUT, GET };
+
+class XBT_PUBLIC MessImpl : public ActivityImpl_T<MessImpl> {
+  ~MessImpl() override;
+
+  MessageQueueImpl* queue_ = nullptr;
+  void* payload_           = nullptr;
+  MessImplType type_       = MessImplType::PUT;
+  unsigned char* dst_buff_ = nullptr;
+  size_t* dst_buff_size_   = nullptr;
+
+public:
+  MessImpl& set_type(MessImplType type);
+  MessImplType get_type() const { return type_; }
+  MessImpl& set_payload(void* payload);
+  void* get_payload() { return payload_; }
+
+  MessImpl& set_queue(MessageQueueImpl* queue);
+  MessageQueueImpl* get_queue() const { return queue_; }
+  MessImpl& set_dst_buff(unsigned char* buff, size_t* size);
+
+  static ActivityImplPtr iput(actor::MessIputSimcall* observer);
+  static ActivityImplPtr iget(actor::MessIgetSimcall* observer);
+
+  void wait_for(actor::ActorImpl* issuer, double timeout) override;
+
+  MessImpl* start();
+  void suspend() override { /* no action to suspend for Mess */ }
+  void resume() override { /* no action to resume for Mess */ }
+  void cancel() override;
+  void set_exception(actor::ActorImpl* issuer) override {};
+  void finish() override;
+
+  actor::ActorImplPtr src_actor_ = nullptr;
+  actor::ActorImplPtr dst_actor_ = nullptr;
+};
+} // namespace simgrid::kernel::activity
+
+#endif
diff --git a/src/kernel/activity/MessageQueueImpl.cpp b/src/kernel/activity/MessageQueueImpl.cpp
new file mode 100644 (file)
index 0000000..d649e6e
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/kernel/activity/MessageQueueImpl.hpp"
+
+#include <unordered_map>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_mq, kernel, "Message queue implementation");
+
+namespace simgrid::kernel::activity {
+
+unsigned MessageQueueImpl::next_id_ = 0;
+
+MessageQueueImpl::~MessageQueueImpl()
+{
+  try {
+    clear();
+  } catch (const std::bad_alloc& ba) {
+    XBT_ERROR("MessageQueueImpl::clear() failure: %s", ba.what());
+  }
+}
+
+/** @brief Removes all message activities from a message queue */
+void MessageQueueImpl::clear()
+{
+  while (not queue_.empty()) {
+    auto mess = queue_.back();
+    if (mess->get_state() == State::WAITING) {
+      mess->cancel();
+      mess->set_state(State::FAILED);
+    } else
+      queue_.pop_back();
+  }
+  xbt_assert(queue_.empty());
+}
+
+void MessageQueueImpl::push(const MessImplPtr& mess)
+{
+  mess->set_queue(this);
+  this->queue_.push_back(std::move(mess));
+}
+
+void MessageQueueImpl::remove(const MessImplPtr& mess)
+{
+  xbt_assert(mess->get_queue() == this, "Message %p is in queue %s, not queue %s", mess.get(),
+             (mess->get_queue() ? mess->get_queue()->get_cname() : "(null)"), get_cname());
+
+  mess->set_queue(nullptr);
+  auto it = std::find(queue_.begin(), queue_.end(), mess);
+  if (it != queue_.end())
+    queue_.erase(it);
+  else
+    xbt_die("Message %p not found in queue %s", mess.get(), get_cname());
+}
+
+MessImplPtr MessageQueueImpl::find_matching_message(MessImplType type)
+{
+  auto iter = std::find_if(queue_.begin(), queue_.end(), [&type](const MessImplPtr& mess)
+  {
+    return (mess->get_type() == type);
+  });
+  if (iter == queue_.end()) {
+    XBT_DEBUG("No matching message synchro found");
+    return nullptr;
+  }
+
+  const MessImplPtr& mess = *iter;
+  XBT_DEBUG("Found a matching message synchro %p", mess.get());
+  mess->set_queue(nullptr);
+  MessImplPtr mess_cpy = mess;
+  queue_.erase(iter);
+  return mess_cpy;
+}
+
+} // namespace simgrid::kernel::activity
diff --git a/src/kernel/activity/MessageQueueImpl.hpp b/src/kernel/activity/MessageQueueImpl.hpp
new file mode 100644 (file)
index 0000000..3016e04
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_KERNEL_ACTIVITY_MESSAGEQUEUE_HPP
+#define SIMGRID_KERNEL_ACTIVITY_MESSAGEQUEUE_HPP
+
+#include "simgrid/s4u/Engine.hpp"
+#include "simgrid/s4u/MessageQueue.hpp"
+#include "src/kernel/activity/MessImpl.hpp"
+
+namespace simgrid::kernel::activity {
+
+/** @brief Implementation of the s4u::MessageQueue */
+
+class MessageQueueImpl {
+  s4u::MessageQueue piface_;
+  std::string name_;
+  std::deque<MessImplPtr> queue_;
+
+  friend s4u::Engine;
+  friend s4u::MessageQueue;
+  friend s4u::MessageQueue* s4u::Engine::message_queue_by_name_or_create(const std::string& name) const;
+  friend s4u::MessageQueue* s4u::MessageQueue::by_name(const std::string& name);
+
+  static unsigned next_id_; // Next ID to be given
+  const unsigned id_ = next_id_++;
+  explicit MessageQueueImpl(const std::string& name) : piface_(this), name_(name) {}
+  MessageQueueImpl(const MailboxImpl&) = delete;
+  MessageQueueImpl& operator=(const MailboxImpl&) = delete;
+
+public:
+  ~MessageQueueImpl();
+
+  /** @brief Public interface */
+  unsigned get_id() const { return id_; }
+
+  const s4u::MessageQueue* get_iface() const { return &piface_; }
+  s4u::MessageQueue* get_iface() { return &piface_; }
+
+  const std::string& get_name() const { return name_; }
+  const char* get_cname() const { return name_.c_str(); }
+  void push(const MessImplPtr& mess);
+  void remove(const MessImplPtr& mess);
+  void clear();
+  bool empty() const { return queue_.empty(); }
+  size_t size() const { return queue_.size(); }
+  const MessImplPtr& front() const { return queue_.front(); }
+
+  MessImplPtr find_matching_message(MessImplType type);
+};
+} // namespace simgrid::kernel::activity
+
+#endif
index 43a511b..cac3e95 100644 (file)
@@ -47,13 +47,41 @@ unsigned MutexImpl::next_id_ = 0;
 
 MutexAcquisitionImplPtr MutexImpl::lock_async(actor::ActorImpl* issuer)
 {
-  auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true);
-
-  if (owner_ != nullptr) {
-    /* Somebody is using the mutex; register the acquisition */
+  /* If the mutex is recursive */
+  if (is_recursive_) {
+    if (owner_ == issuer) {
+      recursive_depth++;
+      auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true);
+      res->grant();
+      return res;
+    } else if (owner_ == nullptr) { // Free
+      owner_          = issuer;
+      recursive_depth = 1;
+      auto res        = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true);
+      res->grant();
+      return res;
+    }
+
+    for (auto acq : ongoing_acquisitions_)
+      if (acq->get_issuer() == issuer) {
+        acq->recursive_depth_++;
+        return acq;
+      }
+
+    // Not yet in the ongoing acquisition list. Get in there
+    auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true);
     ongoing_acquisitions_.push_back(res);
-  } else {
+    return res;
+  }
+
+  // Non-recursive mutex
+  auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true);
+  if (owner_ == nullptr) { // Lock is free, take it
     owner_  = issuer;
+    recursive_depth = 1;
+    res->grant();
+  } else { // Somebody is using the mutex; register the acquisition
+    ongoing_acquisitions_.push_back(res);
   }
   return res;
 }
@@ -65,14 +93,14 @@ MutexAcquisitionImplPtr MutexImpl::lock_async(actor::ActorImpl* issuer)
  */
 bool MutexImpl::try_lock(actor::ActorImpl* issuer)
 {
-  XBT_IN("(%p, %p)", this, issuer);
-  if (owner_ != nullptr) {
-    XBT_OUT();
-    return false;
+  if (owner_ == issuer && is_recursive_) {
+    recursive_depth++;
+    return true;
   }
+  if (owner_ != nullptr)
+    return false;
 
-  owner_  = issuer;
-  XBT_OUT();
+  owner_ = issuer;
   return true;
 }
 
@@ -88,12 +116,20 @@ void MutexImpl::unlock(actor::ActorImpl* issuer)
   xbt_assert(issuer == owner_, "Cannot release that mutex: you're not the owner. %s is (pid:%ld).",
              owner_ != nullptr ? owner_->get_cname() : "(nobody)", owner_ != nullptr ? owner_->get_pid() : -1);
 
+  if (is_recursive_) {
+    recursive_depth--;
+    if (recursive_depth > 0) // Still owning the lock
+      return;
+  }
+
   if (not ongoing_acquisitions_.empty()) {
     /* Give the ownership to the first waiting actor */
     auto acq = ongoing_acquisitions_.front();
     ongoing_acquisitions_.pop_front();
 
     owner_ = acq->get_issuer();
+    acq->grant();
+    recursive_depth = acq->recursive_depth_;
     if (acq == owner_->waiting_synchro_)
       acq->finish();
     // else, the issuer is not blocked on this acquisition so no need to release it
index 3eebec2..8bf71be 100644 (file)
@@ -9,6 +9,7 @@
 #include "simgrid/s4u/Mutex.hpp"
 #include "src/kernel/activity/ActivityImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
+#include "xbt/asserts.h"
 #include <boost/intrusive/list.hpp>
 
 namespace simgrid::kernel::activity {
@@ -42,11 +43,19 @@ namespace simgrid::kernel::activity {
 class XBT_PUBLIC MutexAcquisitionImpl : public ActivityImpl_T<MutexAcquisitionImpl> {
   actor::ActorImpl* issuer_ = nullptr;
   MutexImpl* mutex_         = nullptr;
+  int recursive_depth_      = 1;
+  // TODO: use granted_ this instead of owner_ == self to test().
+  // This is mandatory to get double-lock on non-recursive locks to properly deadlock
+  bool granted_ = false;
+
+  friend MutexImpl;
 
 public:
   MutexAcquisitionImpl(actor::ActorImpl* issuer, MutexImpl* mutex) : issuer_(issuer), mutex_(mutex) {}
-  MutexImplPtr get_mutex() { return mutex_; }
-  actor::ActorImpl* get_issuer() { return issuer_; }
+  MutexImplPtr get_mutex() const { return mutex_; }
+  actor::ActorImpl* get_issuer() const { return issuer_; }
+  void grant() { granted_ = true; }
+  bool is_granted() const { return granted_; }
 
   bool test(actor::ActorImpl* issuer = nullptr) override;
   void wait_for(actor::ActorImpl* issuer, double timeout) override;
@@ -63,11 +72,13 @@ class XBT_PUBLIC MutexImpl {
   std::deque<MutexAcquisitionImplPtr> ongoing_acquisitions_;
   static unsigned next_id_;
   unsigned id_ = next_id_++;
+  bool is_recursive_  = false;
+  int recursive_depth = 0;
 
   friend MutexAcquisitionImpl;
 
 public:
-  MutexImpl() : piface_(this) {}
+  explicit MutexImpl(bool recursive = false) : piface_(this), is_recursive_(recursive) {}
   MutexImpl(MutexImpl const&) = delete;
   MutexImpl& operator=(MutexImpl const&) = delete;
 
@@ -87,11 +98,15 @@ public:
 
   friend void intrusive_ptr_release(MutexImpl* mutex)
   {
-    if (mutex->refcount_.fetch_sub(1) == 1)
+    if (mutex->refcount_.fetch_sub(1) == 1) {
+      xbt_assert(mutex->ongoing_acquisitions_.empty(), "The destroyed mutex still had ongoing acquisitions");
+      xbt_assert(mutex->owner_ == nullptr, "The destroyed mutex is still owned by actor %s",
+                 mutex->owner_->get_cname());
       delete mutex;
+    }
   }
 
-  s4u::Mutex& mutex() { return piface_; }
+  s4u::Mutex& get_iface() { return piface_; }
 };
 } // namespace simgrid::kernel::activity
 #endif
index 8cba364..b53f457 100644 (file)
@@ -68,7 +68,7 @@ void SemAcquisitionImpl::finish()
 void SemAcquisitionImpl::cancel()
 {
   /* Remove myself from the list of interested parties */
-  auto issuer = get_issuer();
+  const auto* issuer = get_issuer();
   auto it     = std::find_if(semaphore_->ongoing_acquisitions_.begin(), semaphore_->ongoing_acquisitions_.end(),
                              [issuer](SemAcquisitionImplPtr acqui) { return acqui->get_issuer() == issuer; });
   xbt_assert(it != semaphore_->ongoing_acquisitions_.end(),
index ebb439b..e7b21d2 100644 (file)
@@ -49,7 +49,7 @@ class XBT_PUBLIC SemaphoreImpl {
   std::deque<SemAcquisitionImplPtr> ongoing_acquisitions_;
 
   static unsigned next_id_;
-  unsigned id_ = next_id_++;
+  const unsigned id_ = next_id_++;
 
   friend SemAcquisitionImpl;
   friend actor::SemaphoreObserver;
index c2e2b48..61e0479 100644 (file)
@@ -44,8 +44,10 @@ ActorImpl::ActorImpl(const std::string& name, s4u::Host* host, aid_t ppid)
 
 ActorImpl::~ActorImpl()
 {
-  if (EngineImpl::has_instance() && not EngineImpl::get_instance()->is_maestro(this))
+  if (EngineImpl::has_instance() && not EngineImpl::get_instance()->is_maestro(this)) {
     s4u::Actor::on_destruction(*get_ciface());
+    get_ciface()->on_this_destruction(*get_ciface());
+  }
 }
 
 /* Become an actor in the simulation
@@ -129,6 +131,7 @@ void ActorImpl::cleanup_from_kernel()
 
   undaemonize();
   s4u::Actor::on_termination(*get_ciface());
+  get_ciface()->on_this_termination(*get_ciface());
 
   while (not mailboxes_.empty())
     mailboxes_.back()->set_receiver(nullptr);
@@ -369,7 +372,7 @@ activity::ActivityImplPtr ActorImpl::sleep(double duration)
     throw_exception(std::make_exception_ptr(
         HostFailureException(XBT_THROW_POINT, "Host " + host_->get_name() + " failed, you cannot sleep there.")));
 
-  auto sleep_activity = new activity::SleepImpl();
+  auto* sleep_activity = new activity::SleepImpl();
   sleep_activity->set_name("sleep").set_host(host_).set_duration(duration).start();
   return activity::SleepImplPtr(sleep_activity);
 }
@@ -506,8 +509,10 @@ void create_maestro(const std::function<void()>& code)
 /** (in kernel mode) unpack the simcall and activate the handler */
 void ActorImpl::simcall_handle(int times_considered)
 {
-  XBT_DEBUG("Handling simcall %p: %s(%ld) %s", &simcall_, simcall_.issuer_->get_cname(), simcall_.issuer_->get_pid(),
-            (simcall_.observer_ != nullptr ? simcall_.observer_->to_string().c_str() : simcall_.get_cname()));
+  XBT_DEBUG("Handling simcall %p: %s(%ld) %s (times_considered:%d)", &simcall_, simcall_.issuer_->get_cname(),
+            simcall_.issuer_->get_pid(),
+            (simcall_.observer_ != nullptr ? simcall_.observer_->to_string().c_str() : simcall_.get_cname()),
+            times_considered);
   if (simcall_.observer_ != nullptr)
     simcall_.observer_->prepare(times_considered);
   if (wannadie())
index f3e4600..a7257d7 100644 (file)
@@ -6,6 +6,7 @@
 #include "simgrid/s4u/Host.hpp"
 #include "src/kernel/activity/CommImpl.hpp"
 #include "src/kernel/activity/MailboxImpl.hpp"
+#include "src/kernel/activity/MessageQueueImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
 #include "src/kernel/actor/SimcallObserver.hpp"
 #include "src/mc/mc_config.hpp"
@@ -16,8 +17,9 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(obs_comm, mc_observer, "Logging specific to the
 
 namespace simgrid::kernel::actor {
 
-ActivityTestanySimcall::ActivityTestanySimcall(ActorImpl* actor, const std::vector<activity::ActivityImpl*>& activities)
-    : ResultingSimcall(actor, -1), activities_(activities)
+ActivityTestanySimcall::ActivityTestanySimcall(ActorImpl* actor, const std::vector<activity::ActivityImpl*>& activities,
+                                               std::string_view fun_call)
+    : ResultingSimcall(actor, -1), activities_(activities), fun_call_(fun_call)
 {
   indexes_.clear();
   // list all the activities that are ready
@@ -38,83 +40,89 @@ void ActivityTestanySimcall::prepare(int times_considered)
   else
     next_value_ = -1;
 }
-static void serialize_activity_test(const activity::ActivityImpl* act, std::stringstream& stream)
+static void serialize_activity_test(const activity::ActivityImpl* act, std::string const& call_location,
+                                    std::stringstream& stream)
 {
-  if (auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
+  if (const auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
     stream << "  " << (short)mc::Transition::Type::COMM_TEST;
-    stream << ' ' << (uintptr_t)comm;
+    stream << ' ' << comm->get_id();
     stream << ' ' << (comm->src_actor_ != nullptr ? comm->src_actor_->get_pid() : -1);
     stream << ' ' << (comm->dst_actor_ != nullptr ? comm->dst_actor_->get_pid() : -1);
     stream << ' ' << comm->get_mailbox_id();
-    stream << ' ' << (uintptr_t)comm->src_buff_ << ' ' << (uintptr_t)comm->dst_buff_ << ' ' << comm->src_buff_size_;
+    stream << ' ' << call_location;
   } else {
     stream << (short)mc::Transition::Type::UNKNOWN;
+    XBT_CRITICAL("Unknown transition in a test any. Bad things may happen");
   }
 }
 static std::string to_string_activity_test(const activity::ActivityImpl* act)
 {
-  if (auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
-    const std::string src_buff_id = ptr_to_id<unsigned char>(comm->src_buff_);
-    const std::string dst_buff_id = ptr_to_id<unsigned char>(comm->dst_buff_);
-    return "CommTest(comm_id:" + ptr_to_id<activity::CommImpl const>(comm) +
+  if (const auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
+    return "CommTest(comm_id:" + std::to_string(comm->get_id()) +
            " src:" + std::to_string(comm->src_actor_ != nullptr ? comm->src_actor_->get_pid() : -1) +
            " dst:" + std::to_string(comm->dst_actor_ != nullptr ? comm->dst_actor_->get_pid() : -1) +
-           " mbox:" + std::to_string(comm->get_mailbox_id()) + " srcbuf:" + src_buff_id + " dstbuf:" + dst_buff_id +
-           " bufsize:" + std::to_string(comm->src_buff_size_);
+           " mbox:" + std::to_string(comm->get_mailbox_id()) + ")";
   } else {
     return "TestUnknownType()";
   }
 }
 void ActivityTestanySimcall::serialize(std::stringstream& stream) const
 {
+  XBT_DEBUG("Serialize %s", to_string().c_str());
   stream << (short)mc::Transition::Type::TESTANY << ' ' << activities_.size() << ' ';
-  for (auto const& act : activities_) {
-    serialize_activity_test(act, stream);
+  for (auto const* act : activities_) {
+    // fun_call of each activity embedded in the TestAny is not known, so let's use the location of the TestAny itself
+    serialize_activity_test(act, fun_call_, stream);
     stream << ' ';
   }
+  stream << fun_call_;
 }
 std::string ActivityTestanySimcall::to_string() const
 {
   std::stringstream buffer("TestAny(");
-  for (auto const& act : activities_) {
+  bool first = true;
+  for (auto const* act : activities_) {
+    if (first)
+      first = false;
+    else
+      buffer << " | ";
     buffer << to_string_activity_test(act);
   }
+  buffer << ")";
   return buffer.str();
 }
 
 void ActivityTestSimcall::serialize(std::stringstream& stream) const
 {
-  serialize_activity_test(activity_, stream);
+  serialize_activity_test(activity_, fun_call_, stream);
 }
 std::string ActivityTestSimcall::to_string() const
 {
   return to_string_activity_test(activity_);
 }
-static void serialize_activity_wait(const activity::ActivityImpl* act, bool timeout, std::stringstream& stream)
+static void serialize_activity_wait(const activity::ActivityImpl* act, bool timeout, std::string const& call_location,
+                                    std::stringstream& stream)
 {
-  if (auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
+  if (const auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
     stream << (short)mc::Transition::Type::COMM_WAIT << ' ';
-    stream << timeout << ' ' << (uintptr_t)comm;
+    stream << timeout << ' ' << comm->get_id();
 
     stream << ' ' << (comm->src_actor_ != nullptr ? comm->src_actor_->get_pid() : -1);
     stream << ' ' << (comm->dst_actor_ != nullptr ? comm->dst_actor_->get_pid() : -1);
     stream << ' ' << comm->get_mailbox_id();
-    stream << ' ' << (uintptr_t)comm->src_buff_ << ' ' << (uintptr_t)comm->dst_buff_ << ' ' << comm->src_buff_size_;
+    stream << ' ' << call_location;
   } else {
     stream << (short)mc::Transition::Type::UNKNOWN;
   }
 }
 static std::string to_string_activity_wait(const activity::ActivityImpl* act)
 {
-  if (auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
-    const std::string src_buff_id = ptr_to_id<unsigned char>(comm->src_buff_);
-    const std::string dst_buff_id = ptr_to_id<unsigned char>(comm->dst_buff_);
-    return "CommWait(comm_id:" + ptr_to_id<activity::CommImpl const>(comm) +
+  if (const auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
+    return "CommWait(comm_id:" + std::to_string(comm->get_id()) +
            " src:" + std::to_string(comm->src_actor_ != nullptr ? comm->src_actor_->get_pid() : -1) +
            " dst:" + std::to_string(comm->dst_actor_ != nullptr ? comm->dst_actor_->get_pid() : -1) +
            " mbox:" + (comm->get_mailbox() == nullptr ? "-" : comm->get_mailbox()->get_name()) +
-           "(id:" + std::to_string(comm->get_mailbox_id()) + ") srcbuf:" + src_buff_id + " dstbuf:" + dst_buff_id +
-           " bufsize:" + std::to_string(comm->src_buff_size_) + ")";
+           "(id:" + std::to_string(comm->get_mailbox_id()) + "))";
   } else {
     return "WaitUnknownType()";
   }
@@ -122,15 +130,18 @@ static std::string to_string_activity_wait(const activity::ActivityImpl* act)
 
 void ActivityWaitSimcall::serialize(std::stringstream& stream) const
 {
-  serialize_activity_wait(activity_, timeout_ > 0, stream);
+  serialize_activity_wait(activity_, timeout_ > 0, fun_call_, stream);
 }
 void ActivityWaitanySimcall::serialize(std::stringstream& stream) const
 {
+  XBT_DEBUG("Serialize %s", to_string().c_str());
   stream << (short)mc::Transition::Type::WAITANY << ' ' << activities_.size() << ' ';
-  for (auto const& act : activities_) {
-    serialize_activity_wait(act, timeout_ > 0, stream);
+  for (auto const* act : activities_) {
+    // fun_call of each activity embedded in the WaitAny is not known, so let's use the location of the WaitAny itself
+    serialize_activity_wait(act, timeout_ > 0, fun_call_, stream);
     stream << ' ';
   }
+  stream << fun_call_;
 }
 std::string ActivityWaitSimcall::to_string() const
 {
@@ -139,14 +150,20 @@ std::string ActivityWaitSimcall::to_string() const
 std::string ActivityWaitanySimcall::to_string() const
 {
   std::stringstream buffer("WaitAny(");
-  for (auto const& act : activities_) {
-    buffer << to_string_activity_wait(act);
+  bool first = true;
+  for (auto const* act : activities_) {
+    if (first)
+      first = false;
+    else
+      buffer << " | ";
+    buffer << to_string_activity_test(act);
   }
+  buffer << ")";
   return buffer.str();
 }
 ActivityWaitanySimcall::ActivityWaitanySimcall(ActorImpl* actor, const std::vector<activity::ActivityImpl*>& activities,
-                                               double timeout)
-    : ResultingSimcall(actor, -1), activities_(activities), timeout_(timeout)
+                                               double timeout, std::string_view fun_call)
+    : ResultingSimcall(actor, -1), activities_(activities), timeout_(timeout), fun_call_(fun_call)
 {
   // list all the activities that are ready
   indexes_.clear();
@@ -197,30 +214,55 @@ void ActivityWaitanySimcall::prepare(int times_considered)
 
 void CommIsendSimcall::serialize(std::stringstream& stream) const
 {
+  /* Note that the comm_ is 0 until after the execution of the simcall */
   stream << (short)mc::Transition::Type::COMM_ASYNC_SEND << ' ';
-  stream << (uintptr_t)comm_ << ' ' << mbox_->get_id() << ' ' << (uintptr_t)src_buff_ << ' ' << src_buff_size_ << ' '
-         << tag_;
-  XBT_DEBUG("SendObserver comm:%p mbox:%u buff:%p size:%zu tag:%d", comm_, mbox_->get_id(), src_buff_, src_buff_size_,
-            tag_);
+  stream << (comm_ ? comm_->get_id() : 0) << ' ' << mbox_->get_id() << ' ' << tag_;
+  XBT_DEBUG("SendObserver comm:%p mbox:%u tag:%d", comm_, mbox_->get_id(), tag_);
+  stream << ' ' << fun_call_;
 }
 std::string CommIsendSimcall::to_string() const
 {
-  return "CommAsyncSend(comm_id: " + std::to_string((uintptr_t)comm_) + " mbox:" + std::to_string(mbox_->get_id()) +
-         " srcbuf:" + ptr_to_id<unsigned char>(src_buff_) + " bufsize:" + std::to_string(src_buff_size_) +
-         " tag: " + std::to_string(tag_) + ")";
+  return "CommAsyncSend(comm_id: " + std::to_string(comm_ ? comm_->get_id() : 0) +
+         " mbox:" + std::to_string(mbox_->get_id()) + " tag: " + std::to_string(tag_) + ")";
 }
 
 void CommIrecvSimcall::serialize(std::stringstream& stream) const
 {
+  /* Note that the comm_ is 0 until after the execution of the simcall */
   stream << (short)mc::Transition::Type::COMM_ASYNC_RECV << ' ';
-  stream << (uintptr_t)comm_ << ' ' << mbox_->get_id() << ' ' << (uintptr_t)dst_buff_ << ' ' << tag_;
-  XBT_DEBUG("RecvObserver comm:%p mbox:%u buff:%p tag:%d", comm_, mbox_->get_id(), dst_buff_, tag_);
+  stream << (comm_ ? comm_->get_id() : 0) << ' ' << mbox_->get_id() << ' ' << tag_;
+  XBT_DEBUG("RecvObserver comm:%p mbox:%u tag:%d", comm_, mbox_->get_id(), tag_);
+  stream << ' ' << fun_call_;
 }
+
 std::string CommIrecvSimcall::to_string() const
 {
-  return "CommAsyncRecv(comm_id: " + ptr_to_id<activity::CommImpl const>(comm_) +
-         " mbox:" + std::to_string(mbox_->get_id()) + " dstbuf:" + ptr_to_id<unsigned char>(dst_buff_) +
-         " tag: " + std::to_string(tag_) + ")";
+  return "CommAsyncRecv(comm_id: " + std::to_string(comm_ ? comm_->get_id() : 0) +
+         " mbox:" + std::to_string(mbox_->get_id()) + " tag: " + std::to_string(tag_) + ")";
+}
+
+void MessIputSimcall::serialize(std::stringstream& stream) const
+{
+  stream << mess_  << ' ' << queue_;
+  XBT_DEBUG("PutObserver mess:%p queue:%p", mess_, queue_);
+}
+
+std::string MessIputSimcall::to_string() const
+{
+  return "MessAsyncPut(queue:" + queue_->get_name() + ")";
 }
 
+void MessIgetSimcall::serialize(std::stringstream& stream) const
+{
+  stream << mess_ << ' ' << queue_;
+  XBT_DEBUG("GettObserver mess:%p queue:%p", mess_, queue_);
+}
+
+std::string MessIgetSimcall::to_string() const
+{
+  return "MessAsyncGet(queue:" + queue_->get_name() + ")";
+}
+
+
+
 } // namespace simgrid::kernel::actor
index 7758425..161e095 100644 (file)
 #include "xbt/asserts.h"
 
 #include <string>
+#include <string_view>
 
 namespace simgrid::kernel::actor {
 
 class ActivityTestSimcall final : public ResultingSimcall<bool> {
   activity::ActivityImpl* const activity_;
+  std::string fun_call_;
 
 public:
-  ActivityTestSimcall(ActorImpl* actor, activity::ActivityImpl* activity)
-      : ResultingSimcall(actor, true), activity_(activity)
+  ActivityTestSimcall(ActorImpl* actor, activity::ActivityImpl* activity, std::string_view fun_call)
+      : ResultingSimcall(actor, true), activity_(activity), fun_call_(fun_call)
   {
   }
-  bool is_visible() const override { return true; }
   activity::ActivityImpl* get_activity() const { return activity_; }
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
@@ -33,10 +34,11 @@ class ActivityTestanySimcall final : public ResultingSimcall<ssize_t> {
   const std::vector<activity::ActivityImpl*>& activities_;
   std::vector<int> indexes_; // indexes in activities_ pointing to ready activities (=whose test() is positive)
   int next_value_ = 0;
+  std::string fun_call_;
 
 public:
-  ActivityTestanySimcall(ActorImpl* actor, const std::vector<activity::ActivityImpl*>& activities);
-  bool is_visible() const override { return true; }
+  ActivityTestanySimcall(ActorImpl* actor, const std::vector<activity::ActivityImpl*>& activities,
+                         std::string_view fun_call);
   bool is_enabled() override { return true; /* can return -1 if no activity is ready */ }
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
@@ -49,15 +51,15 @@ public:
 class ActivityWaitSimcall final : public ResultingSimcall<bool> {
   activity::ActivityImpl* activity_;
   const double timeout_;
+  std::string fun_call_;
 
 public:
-  ActivityWaitSimcall(ActorImpl* actor, activity::ActivityImpl* activity, double timeout)
-      : ResultingSimcall(actor, false), activity_(activity), timeout_(timeout)
+  ActivityWaitSimcall(ActorImpl* actor, activity::ActivityImpl* activity, double timeout, std::string_view fun_call)
+      : ResultingSimcall(actor, false), activity_(activity), timeout_(timeout), fun_call_(fun_call)
   {
   }
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
-  bool is_visible() const override { return true; }
   bool is_enabled() override;
   activity::ActivityImpl* get_activity() const { return activity_; }
   void set_activity(activity::ActivityImpl* activity) { activity_ = activity; }
@@ -69,13 +71,14 @@ class ActivityWaitanySimcall final : public ResultingSimcall<ssize_t> {
   std::vector<int> indexes_; // indexes in activities_ pointing to ready activities (=whose test() is positive)
   const double timeout_;
   int next_value_ = 0;
+  std::string fun_call_;
 
 public:
-  ActivityWaitanySimcall(ActorImpl* actor, const std::vector<activity::ActivityImpl*>& activities, double timeout);
+  ActivityWaitanySimcall(ActorImpl* actor, const std::vector<activity::ActivityImpl*>& activities, double timeout,
+                         std::string_view fun_call);
   bool is_enabled() override;
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
-  bool is_visible() const override { return true; }
   void prepare(int times_considered) override;
   int get_max_consider() const override;
   const std::vector<activity::ActivityImpl*>& get_activities() const { return activities_; }
@@ -98,6 +101,8 @@ class CommIsendSimcall final : public SimcallObserver {
   std::function<void(void*)> clean_fun_; // used to free the synchro in case of problem after a detached send
   std::function<void(activity::CommImpl*, void*, size_t)> copy_data_fun_; // used to copy data if not default one
 
+  std::string fun_call_;
+
 public:
   CommIsendSimcall(
       ActorImpl* actor, activity::MailboxImpl* mbox, double payload_size, double rate, unsigned char* src_buff,
@@ -105,7 +110,7 @@ public:
       const std::function<void(void*)>& clean_fun, // used to free the synchro in case of problem after a detached send
       const std::function<void(activity::CommImpl*, void*, size_t)>&
           copy_data_fun, // used to copy data if not default one
-      void* payload, bool detached)
+      void* payload, bool detached, std::string_view fun_call)
       : SimcallObserver(actor)
       , mbox_(mbox)
       , payload_size_(payload_size)
@@ -117,11 +122,11 @@ public:
       , match_fun_(match_fun)
       , clean_fun_(clean_fun)
       , copy_data_fun_(copy_data_fun)
+      , fun_call_(fun_call)
   {
   }
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
-  bool is_visible() const override { return true; }
   activity::MailboxImpl* get_mailbox() const { return mbox_; }
   double get_payload_size() const { return payload_size_; }
   double get_rate() const { return rate_; }
@@ -149,11 +154,13 @@ class CommIrecvSimcall final : public SimcallObserver {
   std::function<bool(void*, void*, activity::CommImpl*)> match_fun_;
   std::function<void(activity::CommImpl*, void*, size_t)> copy_data_fun_; // used to copy data if not default one
 
+  std::string fun_call_;
+
 public:
   CommIrecvSimcall(ActorImpl* actor, activity::MailboxImpl* mbox, unsigned char* dst_buff, size_t* dst_buff_size,
                    const std::function<bool(void*, void*, activity::CommImpl*)>& match_fun,
                    const std::function<void(activity::CommImpl*, void*, size_t)>& copy_data_fun, void* payload,
-                   double rate)
+                   double rate, std::string_view fun_call)
       : SimcallObserver(actor)
       , mbox_(mbox)
       , dst_buff_(dst_buff)
@@ -162,11 +169,11 @@ public:
       , rate_(rate)
       , match_fun_(match_fun)
       , copy_data_fun_(copy_data_fun)
+      , fun_call_(fun_call)
   {
   }
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
-  bool is_visible() const override { return true; }
   activity::MailboxImpl* get_mailbox() const { return mbox_; }
   double get_rate() const { return rate_; }
   unsigned char* get_dst_buff() const { return dst_buff_; }
@@ -179,6 +186,52 @@ public:
   auto const& get_copy_data_fun() const { return copy_data_fun_; }
 };
 
+class MessIputSimcall final : public SimcallObserver {
+  activity::MessageQueueImpl* queue_;
+  void* payload_;
+  activity::MessImpl* mess_ = {};
+
+public:
+  MessIputSimcall(
+      ActorImpl* actor, activity::MessageQueueImpl* queue, void* payload)
+      : SimcallObserver(actor)
+      , queue_(queue)
+      , payload_(payload)
+  {
+  }
+  void serialize(std::stringstream& stream) const override;
+  std::string to_string() const override;
+  activity::MessageQueueImpl* get_queue() const { return queue_; }
+  void* get_payload() const { return payload_; }
+  void set_message(activity::MessImpl* mess) { mess_ = mess; }
+};
+
+class MessIgetSimcall final : public SimcallObserver {
+  activity::MessageQueueImpl* queue_;
+  unsigned char* dst_buff_;
+  size_t* dst_buff_size_;
+  void* payload_;
+  activity::MessImpl* mess_ = {};
+
+public:
+  MessIgetSimcall(ActorImpl* actor, activity::MessageQueueImpl* queue, unsigned char* dst_buff, size_t* dst_buff_size,
+                  void* payload)
+      : SimcallObserver(actor)
+      , queue_(queue)
+      , dst_buff_(dst_buff)
+      , dst_buff_size_(dst_buff_size)
+      , payload_(payload)
+  {
+  }
+  void serialize(std::stringstream& stream) const override;
+  std::string to_string() const override;
+  activity::MessageQueueImpl* get_queue() const { return queue_; }
+  unsigned char* get_dst_buff() const { return dst_buff_; }
+  size_t* get_dst_buff_size() const { return dst_buff_size_; }
+  void* get_payload() const { return payload_; }
+  void set_message(activity::MessImpl* mess) { mess_ = mess; }
+};
+
 } // namespace simgrid::kernel::actor
 
 #endif
index d34a22d..05f232f 100644 (file)
@@ -4,17 +4,14 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/kernel/actor/Simcall.hpp"
+#include "simgrid/modelchecker.h"
 #include "simgrid/s4u/Host.hpp"
 #include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
 #include "src/kernel/actor/SimcallObserver.hpp"
 #include "src/kernel/context/Context.hpp"
-#include "xbt/log.h"
-
-#if SIMGRID_HAVE_MC
-#include "simgrid/modelchecker.h"
 #include "src/mc/mc_replay.hpp"
-#endif
+#include "xbt/log.h"
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_simcall, kernel, "transmuting from user request into kernel handlers");
 
@@ -48,7 +45,7 @@ void ObjectAccessSimcallItem::take_ownership()
 static void simcall(simgrid::kernel::actor::Simcall::Type call, std::function<void()> const& code,
                     simgrid::kernel::actor::SimcallObserver* observer)
 {
-  auto self                = simgrid::kernel::actor::ActorImpl::self();
+  auto* self               = simgrid::kernel::actor::ActorImpl::self();
   self->simcall_.call_     = call;
   self->simcall_.code_     = &code;
   self->simcall_.observer_ = observer;
@@ -77,16 +74,12 @@ void simcall_run_blocking(std::function<void()> const& code, simgrid::kernel::ac
 
 void simcall_run_object_access(std::function<void()> const& code, simgrid::kernel::actor::ObjectAccessSimcallItem* item)
 {
-  auto self = simgrid::kernel::actor::ActorImpl::self();
+  auto* self = simgrid::kernel::actor::ActorImpl::self();
 
   // We only need a simcall if the order of the setters is important (parallel run or MC execution).
   // Otherwise, just call the function with no simcall
 
-  if (simgrid::kernel::context::Context::is_parallel()
-#if SIMGRID_HAVE_MC
-      || MC_is_active() || MC_record_replay_is_active()
-#endif
-  ) {
+  if (simgrid::kernel::context::Context::is_parallel() || MC_is_active() || MC_record_replay_is_active()) {
     simgrid::kernel::actor::ObjectAccessSimcallObserver observer{self, item};
     simcall(simgrid::kernel::actor::Simcall::Type::RUN_ANSWERED, code, &observer);
     item->take_ownership();
index 2d2cf88..d7657a4 100644 (file)
@@ -38,24 +38,6 @@ int RandomSimcall::get_max_consider() const
   return max_ - min_ + 1;
 }
 
-bool ConditionWaitSimcall::is_enabled()
-{
-  if (static bool warned = false; not warned) {
-    XBT_INFO("Using condition variables in model-checked code is still experimental. Use at your own risk");
-    warned = true;
-  }
-  return true;
-}
-void ConditionWaitSimcall::serialize(std::stringstream& stream) const
-{
-  THROW_UNIMPLEMENTED;
-}
-std::string ConditionWaitSimcall::to_string() const
-{
-  return "ConditionWait(cond_id:" + ptr_to_id<activity::ConditionVariableImpl const>(get_cond()) +
-         " mutex_id:" + std::to_string(get_mutex()->get_id()) + ")";
-}
-
 ActorJoinSimcall::ActorJoinSimcall(ActorImpl* actor, ActorImpl* other, double timeout)
     : SimcallObserver(actor), other_(s4u::ActorPtr(other->get_iface())), timeout_(timeout)
 {
@@ -73,6 +55,15 @@ std::string ActorJoinSimcall::to_string() const
 {
   return "ActorJoin(pid:" + std::to_string(other_->get_pid()) + ")";
 }
+void ActorSleepSimcall::serialize(std::stringstream& stream) const
+{
+  stream << (short)mc::Transition::Type::ACTOR_SLEEP;
+}
+
+std::string ActorSleepSimcall::to_string() const
+{
+  return "ActorSleep()";
+}
 
 void ObjectAccessSimcallObserver::serialize(std::stringstream& stream) const
 {
index 4cb7f22..de3f4fc 100644 (file)
@@ -94,37 +94,26 @@ public:
   int get_value() const { return next_value_; }
 };
 
-class ConditionWaitSimcall final : public ResultingSimcall<bool> {
-  activity::ConditionVariableImpl* const cond_;
-  activity::MutexImpl* const mutex_;
+class ActorJoinSimcall final : public SimcallObserver {
+  s4u::ActorPtr const other_; // We need a Ptr to ensure access to the actor after its end, but Ptr requires s4u
   const double timeout_;
 
 public:
-  ConditionWaitSimcall(ActorImpl* actor, activity::ConditionVariableImpl* cond, activity::MutexImpl* mutex,
-                       double timeout = -1.0)
-      : ResultingSimcall(actor, false), cond_(cond), mutex_(mutex), timeout_(timeout)
-  {
-  }
+  ActorJoinSimcall(ActorImpl* actor, ActorImpl* other, double timeout = -1.0);
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
   bool is_enabled() override;
-  activity::ConditionVariableImpl* get_cond() const { return cond_; }
-  activity::MutexImpl* get_mutex() const { return mutex_; }
+
+  s4u::ActorPtr get_other_actor() const { return other_; }
   double get_timeout() const { return timeout_; }
 };
 
-class ActorJoinSimcall final : public SimcallObserver {
-  s4u::ActorPtr const other_; // We need a Ptr to ensure access to the actor after its end, but Ptr requires s4u
-  const double timeout_;
+class ActorSleepSimcall final : public SimcallObserver {
 
 public:
-  ActorJoinSimcall(ActorImpl* actor, ActorImpl* other, double timeout = -1.0);
+  explicit ActorSleepSimcall(ActorImpl* actor) : SimcallObserver(actor) {}
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
-  bool is_enabled() override;
-
-  s4u::ActorPtr get_other_actor() const { return other_; }
-  double get_timeout() const { return timeout_; }
 };
 
 class ObjectAccessSimcallObserver final : public SimcallObserver {
index efe5bff..50a4ce3 100644 (file)
@@ -31,7 +31,8 @@ void MutexObserver::serialize(std::stringstream& stream) const
 std::string MutexObserver::to_string() const
 {
   return std::string(mc::Transition::to_c_str(type_)) + "(mutex_id:" + std::to_string(get_mutex()->get_id()) +
-         " owner:" + std::to_string(get_mutex()->get_owner()->get_pid()) + ")";
+         " owner:" +
+         (get_mutex()->get_owner() == nullptr ? "none" : std::to_string(get_mutex()->get_owner()->get_pid())) + ")";
 }
 
 bool MutexObserver::is_enabled()
@@ -48,7 +49,8 @@ SemaphoreObserver::SemaphoreObserver(ActorImpl* actor, mc::Transition::Type type
 
 void SemaphoreObserver::serialize(std::stringstream& stream) const
 {
-  stream << (short)type_ << ' ' << get_sem()->get_id() << ' ' << false /* Granted is ignored for LOCK/UNLOCK */;
+  stream << (short)type_ << ' ' << get_sem()->get_id() << ' ' << false /* Granted is ignored for LOCK/UNLOCK */ << ' '
+         << get_sem()->get_capacity();
 }
 std::string SemaphoreObserver::to_string() const
 {
@@ -66,7 +68,8 @@ bool SemaphoreAcquisitionObserver::is_enabled()
 }
 void SemaphoreAcquisitionObserver::serialize(std::stringstream& stream) const
 {
-  stream << (short)type_ << ' ' << acquisition_->semaphore_->get_id() << ' ' << acquisition_->granted_;
+  stream << (short)type_ << ' ' << acquisition_->semaphore_->get_id() << ' ' << acquisition_->granted_ << ' '
+         << acquisition_->semaphore_->get_capacity();
 }
 std::string SemaphoreAcquisitionObserver::to_string() const
 {
@@ -103,4 +106,22 @@ bool BarrierObserver::is_enabled()
          (type_ == mc::Transition::Type::BARRIER_WAIT && acquisition_ != nullptr && acquisition_->granted_);
 }
 
+bool ConditionVariableObserver::is_enabled()
+{
+  if (static bool warned = false; not warned) {
+    XBT_INFO("Using condition variables in model-checked code is still experimental. Use at your own risk");
+    warned = true;
+  }
+  return true;
+}
+void ConditionVariableObserver::serialize(std::stringstream& stream) const
+{
+  THROW_UNIMPLEMENTED;
+}
+std::string ConditionVariableObserver::to_string() const
+{
+  return "ConditionWait(cond_id:" + ptr_to_id<activity::ConditionVariableImpl const>(get_cond()) +
+         " mutex_id:" + std::to_string(get_mutex()->get_id()) + ")";
+}
+
 } // namespace simgrid::kernel::actor
index b707161..ffcfcab 100644 (file)
@@ -7,6 +7,7 @@
 #define SIMGRID_MC_MUTEX_OBSERVER_HPP
 
 #include "simgrid/forward.h"
+#include "src/kernel/activity/ConditionVariableImpl.hpp"
 #include "src/kernel/activity/MutexImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
 #include "src/kernel/actor/SimcallObserver.hpp"
@@ -80,6 +81,27 @@ public:
   double get_timeout() const { return timeout_; }
 };
 
+class ConditionVariableObserver final : public ResultingSimcall<bool> {
+  //mc::Transition::Type type_; Will be used when we implement CV on the MC side
+  activity::ConditionVariableImpl* const cond_;
+  activity::MutexImpl* const mutex_;
+  const double timeout_;
+
+public:
+  ConditionVariableObserver(ActorImpl* actor, activity::ConditionVariableImpl* cond, activity::MutexImpl* mutex,
+                            double timeout = -1.0)
+      : ResultingSimcall(actor, false), cond_(cond), mutex_(mutex), timeout_(timeout)
+  {
+    xbt_assert(mutex != nullptr, "Cannot wait on a condition variable without a valid mutex");
+  }
+  void serialize(std::stringstream& stream) const override;
+  std::string to_string() const override;
+  bool is_enabled() override;
+  activity::ConditionVariableImpl* get_cond() const { return cond_; }
+  activity::MutexImpl* get_mutex() const { return mutex_; }
+  double get_timeout() const { return timeout_; }
+};
+
 } // namespace simgrid::kernel::actor
 
 #endif
index c4f79b4..5736b26 100644 (file)
@@ -54,12 +54,6 @@ void Context::set_current(Context* self)
   current_context_ = self;
 }
 
-void Context::declare_context(std::size_t size)
-{
-  /* Store the address of the stack in heap to compare it apart of heap comparison */
-  MC_ignore_heap(this, size);
-}
-
 Context* ContextFactory::attach(actor::ActorImpl*)
 {
   xbt_die("Cannot attach with this ContextFactory.\n"
index 1961399..16c5e82 100644 (file)
@@ -35,7 +35,6 @@ protected:
   template <class T, class... Args> T* new_context(Args&&... args)
   {
     auto* context = new T(std::forward<Args>(args)...);
-    context->declare_context(sizeof(T));
     return context;
   }
 };
@@ -49,7 +48,6 @@ class XBT_PUBLIC Context {
   std::function<void()> code_;
   actor::ActorImpl* actor_ = nullptr;
   bool is_maestro_;
-  void declare_context(std::size_t size);
 
 public:
   static e_xbt_parmap_mode_t parallel_mode;
index 1c29c66..de72fce 100644 (file)
@@ -190,8 +190,6 @@ RawContext::RawContext(std::function<void()>&& code, actor::ActorImpl* actor, Sw
   XBT_VERB("Creating a context of stack %uMb", actor->get_stacksize() / 1024 / 1024);
   if (has_code()) {
     this->stack_top_ = raw_makecontext(get_stack(), actor->get_stacksize(), smx_ctx_wrapper, this);
-  } else {
-    MC_ignore_heap(&stack_top_, sizeof stack_top_);
   }
 }
 
index 13e7e9a..aff10af 100644 (file)
@@ -82,17 +82,9 @@ SwappedContext::SwappedContext(std::function<void()>&& code, actor::ActorImpl* a
 #endif
 
       size_t size = actor->get_stacksize() + guard_size;
-#if SIMGRID_HAVE_MC
-      /* Cannot use posix_memalign when SIMGRID_HAVE_MC. Align stack by hand, and save the
-       * pointer returned by xbt_malloc0. */
-      auto* alloc          = static_cast<unsigned char*>(xbt_malloc0(size + xbt_pagesize));
-      stack_               = alloc - (reinterpret_cast<uintptr_t>(alloc) & (xbt_pagesize - 1)) + xbt_pagesize;
-      reinterpret_cast<unsigned char**>(stack_)[-1] = alloc;
-#else
       void* alloc;
       xbt_assert(posix_memalign(&alloc, xbt_pagesize, size) == 0, "Failed to allocate stack.");
       this->stack_ = static_cast<unsigned char*>(alloc);
-#endif
 
       /* This is fatal. We are going to fail at some point when we try reusing this. */
       xbt_assert(
@@ -146,10 +138,6 @@ SwappedContext::~SwappedContext()
       XBT_WARN("Failed to remove page protection: %s", strerror(errno));
       /* try to pursue anyway */
     }
-#if SIMGRID_HAVE_MC
-    /* Retrieve the saved pointer.  See the initialization above. */
-    stack_ = reinterpret_cast<unsigned char**>(stack_)[-1];
-#endif
   }
 
   xbt_free(stack_);
index 7515e93..2061a25 100644 (file)
@@ -60,11 +60,6 @@ UContext::UContext(std::function<void()>&& code, actor::ActorImpl* actor, Swappe
     UContext* arg = this;
     memcpy(ctx_addr, &arg, sizeof arg);
     makecontext(&this->uc_, (void (*)())sysv_ctx_wrapper, 2, ctx_addr[0], ctx_addr[1]);
-
-#if SIMGRID_HAVE_MC
-    if (MC_is_active())
-      simgrid::mc::AppSide::get()->declare_stack(get_stack(), stack_size, &uc_);
-#endif
   }
 }
 
index 75eb88a..cebcb96 100644 (file)
@@ -747,7 +747,7 @@ void System::remove_all_modified_cnst_set()
  * If the resource is not shared (ie in FATPIPE mode), then the load is the max (not the sum)
  * of all resource usages located on this resource.
  */
-double Constraint::get_usage() const
+double Constraint::get_load() const
 {
   double result              = 0.0;
   if (sharing_policy_ != SharingPolicy::FATPIPE) {
index bfbe7d2..25fa550 100644 (file)
@@ -220,8 +220,8 @@ public:
   /** @brief Check how a constraint is shared  */
   SharingPolicy get_sharing_policy() const { return sharing_policy_; }
 
-  /** @brief Get the usage of the constraint after the last lmm solve */
-  double get_usage() const;
+  /** @brief Get the load of the constraint after the last lmm solve */
+  double get_load() const;
 
   /** @brief Sets the concurrency limit for this constraint */
   void set_concurrency_limit(int limit)
index a754fd5..d6950bf 100644 (file)
@@ -85,7 +85,7 @@ template <typename C> std::string BmfSolver::debug_vector(const C& container) co
 {
   std::stringstream debug;
   std::copy(container.begin(), container.end(),
-            std::ostream_iterator<typename std::remove_reference<decltype(container)>::type::value_type>(debug, " "));
+            std::ostream_iterator<typename std::remove_reference_t<decltype(container)>::value_type>(debug, " "));
   return debug.str();
 }
 
index c69d23a..acd7aa4 100644 (file)
@@ -4,7 +4,6 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/kernel/resource/CpuImpl.hpp"
-#include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/resource/models/cpu_ti.hpp"
 #include "src/kernel/resource/profile/Profile.hpp"
 #include "src/simgrid/math_utils.h"
@@ -67,9 +66,9 @@ CpuImpl* CpuImpl::set_pstate(unsigned long pstate_index)
 {
   xbt_assert(
       pstate_index < speed_per_pstate_.size(),
-      "Invalid parameters for CPU %s (pstate %lu >= length of pstates %d). Please fix your platform file, or your "
+      "Invalid parameters for CPU %s (pstate %lu >= length of pstates %zu). Please fix your platform file, or your "
       "call to change the pstate.",
-      get_cname(), pstate_index, static_cast<int>(speed_per_pstate_.size()));
+      get_cname(), pstate_index, speed_per_pstate_.size());
 
   double new_peak_speed = speed_per_pstate_[pstate_index];
   pstate_               = pstate_index;
@@ -90,14 +89,15 @@ CpuImpl* CpuImpl::set_pstate_speed(const std::vector<double>& speed_per_state)
 
 double CpuImpl::get_pstate_peak_speed(unsigned long pstate_index) const
 {
-  xbt_assert((pstate_index <= speed_per_pstate_.size()), "Invalid parameters (pstate index out of bounds)");
-
+  xbt_assert(pstate_index < speed_per_pstate_.size(), "Invalid parameters (pstate index %lu out of bounds %zu)",
+             pstate_index, speed_per_pstate_.size());
   return speed_per_pstate_[pstate_index];
 }
 
 void CpuImpl::on_speed_change()
 {
   s4u::Host::on_speed_change(*piface_);
+  piface_->on_this_speed_change(*piface_);
 }
 
 CpuImpl* CpuImpl::set_core_count(int core_count)
@@ -156,16 +156,7 @@ void CpuImpl::turn_off()
 {
   if (is_on()) {
     Resource::turn_off();
-
-    const kernel::lmm::Element* elem = nullptr;
-    double now                       = EngineImpl::get_clock();
-    while (const auto* var = get_constraint()->get_variable(&elem)) {
-      Action* action = var->get_id();
-      if (action->get_state() == Action::State::INITED || action->get_state() == Action::State::STARTED) {
-        action->set_finish_time(now);
-        action->set_state(Action::State::FAILED);
-      }
-    }
+    cancel_actions();
   }
 }
 
@@ -193,27 +184,11 @@ void CpuAction::update_remains_lazy(double now)
   set_last_value(get_rate());
 }
 
-xbt::signal<void(CpuAction const&, Action::State)> CpuAction::on_state_change;
-
-void CpuAction::suspend()
-{
-  Action::State previous = get_state();
-  on_state_change(*this, previous);
-  Action::suspend();
-}
-
-void CpuAction::resume()
-{
-  Action::State previous = get_state();
-  on_state_change(*this, previous);
-  Action::resume();
-}
-
 void CpuAction::set_state(Action::State state)
 {
   Action::State previous = get_state();
   Action::set_state(state);
-  on_state_change(*this, previous);
+  s4u::Host::on_exec_state_change(*this, previous);
 }
 
 /** @brief returns a list of all CPUs that this action is using */
index 6237702..ae35bd5 100644 (file)
@@ -180,18 +180,10 @@ class XBT_PUBLIC CpuAction : public Action {
 public:
   using Action::Action;
 
-  /** @brief Signal emitted when the action state changes (ready/running/done, etc)
-   *  Signature: `void(CpuAction const& action, simgrid::kernel::resource::Action::State previous)`
-   */
-  static xbt::signal<void(CpuAction const&, Action::State)> on_state_change;
-
   void set_state(Action::State state) override;
 
   void update_remains_lazy(double now) override;
   std::list<CpuImpl*> cpus() const;
-
-  void suspend() override;
-  void resume() override;
 };
 } // namespace simgrid::kernel::resource
 
index 1903b81..20c23ac 100644 (file)
@@ -53,6 +53,7 @@ DiskImpl* DiskImpl::set_write_constraint(lmm::Constraint* constraint_write)
 void DiskImpl::destroy()
 {
   s4u::Disk::on_destruction(piface_);
+  piface_.on_this_destruction(piface_);
   delete this;
 }
 
@@ -60,24 +61,17 @@ void DiskImpl::turn_on()
 {
   if (not is_on()) {
     Resource::turn_on();
-    s4u::Disk::on_state_change(piface_);
+    s4u::Disk::on_onoff(piface_);
+    piface_.on_this_onoff(piface_);
   }
 }
 void DiskImpl::turn_off()
 {
   if (is_on()) {
     Resource::turn_off();
-    s4u::Disk::on_state_change(piface_);
-
-    const kernel::lmm::Element* elem = nullptr;
-    double now                       = EngineImpl::get_clock();
-    while (const auto* var = get_constraint()->get_variable(&elem)) {
-      Action* action = var->get_id();
-      if (action->get_state() == Action::State::INITED || action->get_state() == Action::State::STARTED) {
-        action->set_finish_time(now);
-        action->set_state(Action::State::FAILED);
-      }
-    }
+    s4u::Disk::on_onoff(piface_);
+    piface_.on_this_onoff(piface_);
+    cancel_actions();
   }
 }
 
index 55f6857..a1bdb8a 100644 (file)
@@ -50,6 +50,7 @@ class DiskImpl : public Resource_T<DiskImpl>, public xbt::PropertyHolder {
   Metric read_bw_      = {0.0, 0, nullptr};
   Metric write_bw_     = {0.0, 0, nullptr};
   double readwrite_bw_ = -1; /* readwrite constraint bound, usually max(read, write) */
+  std::atomic_int_fast32_t refcount_{0};
 
   void apply_sharing_policy_cfg();
 
@@ -60,6 +61,17 @@ public:
   explicit DiskImpl(const std::string& name, double read_bandwidth, double write_bandwidth);
   DiskImpl(const DiskImpl&) = delete;
   DiskImpl& operator=(const DiskImpl&) = delete;
+  friend void intrusive_ptr_add_ref(DiskImpl* disk)
+  {
+    disk->refcount_.fetch_add(1, std::memory_order_acq_rel);
+  }
+  friend void intrusive_ptr_release(DiskImpl* disk)
+  {
+    if (disk->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
+      std::atomic_thread_fence(std::memory_order_acquire);
+      delete disk;
+    }
+  }
 
   /** @brief Public interface */
   const s4u::Disk* get_iface() const { return &piface_; }
index 4dd7089..da11f9a 100644 (file)
@@ -8,6 +8,7 @@
 #include <simgrid/s4u/Host.hpp>
 
 #include "src/kernel/EngineImpl.hpp"
+#include "src/kernel/resource/NetworkModel.hpp"
 #include "src/kernel/resource/VirtualMachineImpl.hpp"
 #include "xbt/asserts.hpp"
 
@@ -16,7 +17,7 @@
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(res_host, ker_resource, "Host resources agregate CPU, networking and I/O features");
 
 /*************
- * Callbacks *t
+ * Callbacks *
  *************/
 
 namespace simgrid::kernel::resource {
@@ -24,6 +25,28 @@ namespace simgrid::kernel::resource {
 /*********
  * Model *
  *********/
+Action* HostModel::io_stream(s4u::Host* src_host, DiskImpl* src_disk, s4u::Host* dst_host, DiskImpl* dst_disk,
+                                double size)
+{
+  auto* net_model = src_host->get_englobing_zone()->get_network_model();
+  auto* system    = net_model->get_maxmin_system();
+  auto* action   = net_model->communicate(src_host, dst_host, size, -1, true);
+
+  // We don't want to apply the network model bandwidth factor to the I/O constraints
+  double bw_factor = net_model->get_bandwidth_factor();
+  if (src_disk != nullptr) {
+    // FIXME: if the stream starts from a disk, we might not want to pay the network latency
+    system->expand(src_disk->get_constraint(), action->get_variable(), bw_factor);
+    system->expand(src_disk->get_read_constraint(), action->get_variable(), bw_factor);
+  }
+  if (dst_disk != nullptr) {
+    system->expand(dst_disk->get_constraint(), action->get_variable(), bw_factor);
+    system->expand(dst_disk->get_write_constraint(), action->get_variable(), bw_factor);
+  }
+
+  return action;
+}
+
 /************
  * Resource *
  ************/
@@ -53,9 +76,6 @@ HostImpl::~HostImpl()
     delete arg;
   actors_at_boot_.clear();
 
-  for (auto const& [_, d] : disks_)
-    d->destroy();
-
   for (auto const& [_, vm] : vms_)
     vm->vm_destroy();
 }
@@ -67,6 +87,7 @@ HostImpl::~HostImpl()
 void HostImpl::destroy()
 {
   s4u::Host::on_destruction(*this->get_iface());
+  this->get_iface()->on_this_destruction(*this->get_iface());
   delete this;
 }
 
@@ -127,6 +148,7 @@ std::vector<s4u::ActorPtr> HostImpl::get_all_actors()
     res.emplace_back(actor.get_ciface());
   return res;
 }
+
 size_t HostImpl::get_actor_count() const
 {
   return actor_list_.size();
@@ -206,8 +228,8 @@ std::vector<s4u::VirtualMachine*> HostImpl::get_vms() const
 
 s4u::Disk* HostImpl::create_disk(const std::string& name, double read_bandwidth, double write_bandwidth)
 {
-  auto disk = piface_.get_netpoint()->get_englobing_zone()->get_disk_model()->create_disk(name, read_bandwidth,
-                                                                                          write_bandwidth);
+  auto* disk = piface_.get_netpoint()->get_englobing_zone()->get_disk_model()->create_disk(name, read_bandwidth,
+                                                                                           write_bandwidth);
   if (sealed_)
     disk->seal();
   return disk->set_host(&piface_)->get_iface();
@@ -215,7 +237,7 @@ s4u::Disk* HostImpl::create_disk(const std::string& name, double read_bandwidth,
 
 void HostImpl::add_disk(const s4u::Disk* disk)
 {
-  disks_[disk->get_name()] = disk->get_impl();
+  disks_.insert({disk->get_name(), kernel::resource::DiskImplPtr(disk->get_impl())});
 }
 
 void HostImpl::remove_disk(const std::string& name)
index 0de2d0b..506a3d6 100644 (file)
@@ -29,8 +29,8 @@ public:
 
   virtual Action* execute_parallel(const std::vector<s4u::Host*>& host_list, const double* flops_amount,
                                    const double* bytes_amount, double rate) = 0;
-  virtual Action* io_stream(s4u::Host* src_host, DiskImpl* src_disk, s4u::Host* dst_host, DiskImpl* dst_disk,
-                            double size)                                    = 0;
+  Action* io_stream(s4u::Host* src_host, DiskImpl* src_disk, s4u::Host* dst_host, DiskImpl* dst_disk,
+                            double size);
 };
 
 /************
@@ -49,7 +49,7 @@ class XBT_PRIVATE HostImpl : public xbt::PropertyHolder, public actor::ObjectAcc
   ActorList actor_list_;
   std::vector<actor::ProcessArg*> actors_at_boot_;
   s4u::Host piface_;
-  std::map<std::string, DiskImpl*, std::less<>> disks_;
+  std::map<std::string, DiskImplPtr, std::less<>> disks_;
   std::map<std::string, VirtualMachineImpl*, std::less<>> vms_;
   std::string name_{"noname"};
   routing::NetZoneImpl* englobing_zone_ = nullptr;
index f7f269f..8b6ac8a 100644 (file)
@@ -38,10 +38,6 @@ public:
   /* setup the profile file with latency events (peak latency changes due to external load).
    * Profile must contain absolute values */
   virtual void set_latency_profile(kernel::profile::Profile* profile) = 0;
-  /** @brief Set the concurrency limit for this link */
-  virtual void set_concurrency_limit(int limit) const = 0;
-  /** @brief Get the concurrency limit of this link */
-  virtual int get_concurrency_limit() const = 0;
 };
 
 } // namespace simgrid::kernel::resource
index bf67c6a..1ed1e35 100644 (file)
@@ -7,6 +7,7 @@
 #define SIMGRID_KERNEL_RESOURCE_RESOURCE_HPP
 
 #include "simgrid/forward.h"
+#include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/actor/Simcall.hpp"
 #include "src/kernel/lmm/maxmin.hpp" // Constraint
 #include "src/kernel/resource/profile/Event.hpp"
@@ -72,6 +73,21 @@ template <class AnyResource> class Resource_T : public Resource {
   Model* model_                = nullptr;
   lmm::Constraint* constraint_ = nullptr;
 
+protected:
+  void cancel_actions()
+  {
+    const kernel::lmm::Element* elem = nullptr;
+    double now                       = EngineImpl::get_clock();
+    while (const auto* var = get_constraint()->get_variable(&elem)) {
+      Action* action = var->get_id();
+      if (action->get_state() == Action::State::INITED || action->get_state() == Action::State::STARTED ||
+          action->get_state() == Action::State::IGNORED) {
+        action->set_finish_time(now);
+        action->set_state(Action::State::FAILED);
+      }
+    }
+  }
+
 public:
   using Resource::Resource;
   /** @brief setup the profile file with states events (ON or OFF). The profile must contain boolean values. */
@@ -101,10 +117,21 @@ public:
 
   lmm::Constraint* get_constraint() const { return constraint_; }
 
+  /** @brief Set the concurrency limit for this resource */
+  virtual void set_concurrency_limit(int limit) const
+  {
+    if (limit != -1)
+      get_constraint()->reset_concurrency_maximum();
+    get_constraint()->set_concurrency_limit(limit);
+  }
+
+  /** @brief Get the concurrency limit of this resource */
+  virtual int get_concurrency_limit() const { return get_constraint()->get_concurrency_limit(); }
+
   /** @brief returns the current load due to activities (in flops per second, byte per second or similar)
    *
    * The load due to external usages modeled by profile files is ignored.*/
-  virtual double get_load() const { return constraint_->get_usage(); }
+  virtual double get_load() const { return constraint_->get_load(); }
 
   bool is_used() const override { return model_->get_maxmin_system()->constraint_used(constraint_); }
 };
index 9e50e7a..9df40d0 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <simgrid/s4u/Engine.hpp>
 
-#include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/resource/StandardLinkImpl.hpp"
 #include <numeric>
 
@@ -37,6 +36,7 @@ void StandardLinkImpl::Deleter::operator()(resource::StandardLinkImpl* link) con
 void StandardLinkImpl::destroy()
 {
   s4u::Link::on_destruction(piface_);
+  piface_.on_this_destruction(piface_);
   delete this;
 }
 
@@ -81,7 +81,8 @@ void StandardLinkImpl::turn_on()
 {
   if (not is_on()) {
     Resource::turn_on();
-    s4u::Link::on_state_change(piface_);
+    s4u::Link::on_onoff(piface_);
+    piface_.on_this_onoff(piface_);
   }
 }
 
@@ -89,17 +90,9 @@ void StandardLinkImpl::turn_off()
 {
   if (is_on()) {
     Resource::turn_off();
-    s4u::Link::on_state_change(piface_);
-
-    const kernel::lmm::Element* elem = nullptr;
-    double now                       = EngineImpl::get_clock();
-    while (const auto* var = get_constraint()->get_variable(&elem)) {
-      Action* action = var->get_id();
-      if (action->get_state() == Action::State::INITED || action->get_state() == Action::State::STARTED) {
-        action->set_finish_time(now);
-        action->set_state(Action::State::FAILED);
-      }
-    }
+    s4u::Link::on_onoff(piface_);
+    piface_.on_this_onoff(piface_);
+    cancel_actions();
   }
 }
 
@@ -115,6 +108,7 @@ void StandardLinkImpl::seal()
 void StandardLinkImpl::on_bandwidth_change() const
 {
   s4u::Link::on_bandwidth_change(piface_);
+  piface_.on_this_bandwidth_change(piface_);
 }
 
 void StandardLinkImpl::set_bandwidth_profile(profile::Profile* profile)
@@ -133,16 +127,4 @@ void StandardLinkImpl::set_latency_profile(profile::Profile* profile)
   }
 }
 
-void StandardLinkImpl::set_concurrency_limit(int limit) const
-{
-  if (limit != -1) {
-    get_constraint()->reset_concurrency_maximum();
-  }
-  get_constraint()->set_concurrency_limit(limit);
-}
-int StandardLinkImpl::get_concurrency_limit() const
-{
-  return get_constraint()->get_concurrency_limit();
-}
-
 } // namespace simgrid::kernel::resource
index 4a10210..d573fe1 100644 (file)
@@ -70,9 +70,6 @@ public:
   /* setup the profile file with latency events (peak latency changes due to external load).
    * Profile must contain absolute values */
   void set_latency_profile(kernel::profile::Profile* profile) override;
-
-  void set_concurrency_limit(int limit) const override;
-  int get_concurrency_limit() const override;
 };
 
 } // namespace simgrid::kernel::resource
index 1cf155f..e8d813f 100644 (file)
@@ -55,15 +55,15 @@ std::deque<s4u::VirtualMachine*> VirtualMachineImpl::allVms_;
  */
 const double virt_overhead = 1; // 0.95
 
-static void host_state_change(s4u::Host const& host)
+static void host_onoff(s4u::Host const& host)
 {
   if (not host.is_on()) { // just turned off.
     std::vector<s4u::VirtualMachine*> trash;
     /* Find all VMs living on that host */
-    for (s4u::VirtualMachine* const& vm : VirtualMachineImpl::allVms_)
+    for (auto* vm : VirtualMachineImpl::allVms_)
       if (vm->get_pm() == &host)
         trash.push_back(vm);
-    for (s4u::VirtualMachine* vm : trash)
+    for (auto* vm : trash)
       vm->shutdown();
   }
 }
@@ -79,17 +79,14 @@ static void add_active_exec(s4u::Exec const& task)
   }
 }
 
-static void remove_active_exec(s4u::Activity const& task)
+static void remove_active_exec(s4u::Exec const& exec)
 {
-  const auto* exec = dynamic_cast<s4u::Exec const*>(&task);
-  if (exec == nullptr)
+  if (not exec.is_assigned())
     return;
-  if (not exec->is_assigned())
-    return;
-  const s4u::VirtualMachine* vm = dynamic_cast<s4u::VirtualMachine*>(exec->get_host());
+  const s4u::VirtualMachine* vm = dynamic_cast<s4u::VirtualMachine*>(exec.get_host());
   if (vm != nullptr) {
     VirtualMachineImpl* vm_impl = vm->get_vm_impl();
-    for (int i = 1; i <= exec->get_thread_count(); i++)
+    for (int i = 1; i <= exec.get_thread_count(); i++)
       vm_impl->remove_active_exec();
     vm_impl->update_action_weight();
   }
@@ -97,7 +94,7 @@ static void remove_active_exec(s4u::Activity const& task)
 
 static s4u::VirtualMachine* get_vm_from_activity(s4u::Activity const& act)
 {
-  auto* exec = dynamic_cast<kernel::activity::ExecImpl const*>(act.get_impl());
+  const auto* exec = dynamic_cast<kernel::activity::ExecImpl const*>(act.get_impl());
   return exec != nullptr ? dynamic_cast<s4u::VirtualMachine*>(exec->get_host()) : nullptr;
 }
 
@@ -123,11 +120,11 @@ static void remove_active_activity(s4u::Activity const& act)
 
 VMModel::VMModel(const std::string& name) : HostModel(name)
 {
-  s4u::Host::on_state_change_cb(host_state_change);
+  s4u::Host::on_onoff_cb(host_onoff);
   s4u::Exec::on_start_cb(add_active_exec);
-  s4u::Activity::on_completion_cb(remove_active_exec);
-  s4u::Activity::on_resumed_cb(add_active_activity);
-  s4u::Activity::on_suspended_cb(remove_active_activity);
+  s4u::Exec::on_completion_cb(remove_active_exec);
+  s4u::Exec::on_resume_cb(add_active_activity);
+  s4u::Exec::on_suspend_cb(remove_active_activity);
 }
 
 double VMModel::next_occurring_event(double now)
@@ -157,7 +154,7 @@ double VMModel::next_occurring_event(double now)
    **/
 
   /* iterate for all virtual machines */
-  for (s4u::VirtualMachine* const& ws_vm : VirtualMachineImpl::allVms_) {
+  for (auto const* ws_vm : VirtualMachineImpl::allVms_) {
     if (ws_vm->get_state() == s4u::VirtualMachine::State::SUSPENDED) // Ignore suspended VMs
       continue;
 
@@ -176,7 +173,7 @@ double VMModel::next_occurring_event(double now)
 
 Action* VMModel::execute_thread(const s4u::Host* host, double flops_amount, int thread_count)
 {
-  auto cpu = host->get_cpu();
+  auto* cpu = host->get_cpu();
   return cpu->execution_start(thread_count * flops_amount, thread_count, -1);
 }
 
@@ -239,6 +236,7 @@ void VirtualMachineImpl::vm_destroy()
 void VirtualMachineImpl::start()
 {
   s4u::VirtualMachine::on_start(*get_iface());
+  get_iface()->on_this_start(*get_iface());
   s4u::VmHostExt::ensureVmExtInstalled();
 
   if (physical_host_->extension<s4u::VmHostExt>() == nullptr)
@@ -249,7 +247,7 @@ void VirtualMachineImpl::start()
       not physical_host_->extension<s4u::VmHostExt>()->overcommit) { /* Need to verify that we don't overcommit */
     /* Retrieve the memory occupied by the VMs on that host. Yep, we have to traverse all VMs of all hosts for that */
     size_t total_ramsize_of_vms = 0;
-    for (auto* const& ws_vm : allVms_)
+    for (auto const* ws_vm : allVms_)
       if (physical_host_ == ws_vm->get_pm())
         total_ramsize_of_vms += ws_vm->get_ramsize();
 
@@ -264,11 +262,13 @@ void VirtualMachineImpl::start()
   vm_state_ = s4u::VirtualMachine::State::RUNNING;
 
   s4u::VirtualMachine::on_started(*get_iface());
+  get_iface()->on_this_started(*get_iface());
 }
 
 void VirtualMachineImpl::suspend(const actor::ActorImpl* issuer)
 {
   s4u::VirtualMachine::on_suspend(*get_iface());
+  get_iface()->on_this_suspend(*get_iface());
 
   if (vm_state_ != s4u::VirtualMachine::State::RUNNING)
     throw VmFailureException(XBT_THROW_POINT,
@@ -308,6 +308,7 @@ void VirtualMachineImpl::resume()
 
   vm_state_ = s4u::VirtualMachine::State::RUNNING;
   s4u::VirtualMachine::on_resume(*get_iface());
+  get_iface()->on_this_resume(*get_iface());
 }
 
 /** @brief Power off a VM.
@@ -334,6 +335,7 @@ void VirtualMachineImpl::shutdown(actor::ActorImpl* issuer)
   set_state(s4u::VirtualMachine::State::DESTROYED);
 
   s4u::VirtualMachine::on_shutdown(*get_iface());
+  get_iface()->on_this_shutdown(*get_iface());
 }
 
 /** @brief Change the physical host on which the given VM is running
@@ -402,12 +404,14 @@ void VirtualMachineImpl::start_migration()
 {
   is_migrating_ = true;
   s4u::VirtualMachine::on_migration_start(*get_iface());
+  get_iface()->on_this_migration_start(*get_iface());
 }
 
 void VirtualMachineImpl::end_migration()
 {
   is_migrating_ = false;
   s4u::VirtualMachine::on_migration_end(*get_iface());
+  get_iface()->on_this_migration_end(*get_iface());
 }
 
 void VirtualMachineImpl::seal()
index 8d51c7d..781a33b 100644 (file)
@@ -99,7 +99,6 @@ public:
   {
     return nullptr;
   };
-  Action* io_stream(s4u::Host* src_host, DiskImpl* src_disk, s4u::Host* dst_host, DiskImpl* dst_disk, double size) override { return nullptr; }
 };
 } // namespace kernel::resource
 } // namespace simgrid
index 0d5ed17..a40a12a 100644 (file)
@@ -3,6 +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 <simgrid/s4u/Comm.hpp>
 #include <simgrid/s4u/Host.hpp>
 
 #include "src/kernel/activity/CommImpl.hpp"
@@ -15,6 +16,21 @@ namespace simgrid::kernel::resource {
 /************
  * Resource *
  ************/
+static void update_bw_comm_start(const s4u::Comm& comm)
+{
+  const auto* pimpl = static_cast<activity::CommImpl*>(comm.get_impl());
+
+  auto const* actionWifi = dynamic_cast<const kernel::resource::WifiLinkAction*>(pimpl->model_action_);
+  if (actionWifi == nullptr)
+    return;
+
+  if (auto* link_src = actionWifi->get_src_link()) {
+    link_src->inc_active_flux();
+  }
+  if (auto* link_dst = actionWifi->get_dst_link()) {
+    link_dst->inc_active_flux();
+  }
+}
 
 WifiLinkImpl::WifiLinkImpl(const std::string& name, const std::vector<double>& bandwidths, lmm::System* system)
     : StandardLinkImpl(name)
@@ -22,7 +38,7 @@ WifiLinkImpl::WifiLinkImpl(const std::string& name, const std::vector<double>& b
   this->set_constraint(system->constraint_new(this, 1));
   for (auto bandwidth : bandwidths)
     bandwidths_.push_back({bandwidth, 1.0, nullptr});
-  kernel::activity::CommImpl::on_start.connect(&update_bw_comm_start);
+  s4u::Comm::on_start_cb(&update_bw_comm_start);
   s4u::Link::on_communication_state_change_cb(&update_bw_comm_end);
 }
 
@@ -79,20 +95,6 @@ void WifiLinkImpl::dec_active_flux()
   nb_active_flux_--;
 }
 
-void WifiLinkImpl::update_bw_comm_start(const kernel::activity::CommImpl& comm)
-{
-  auto const* actionWifi = dynamic_cast<const simgrid::kernel::resource::WifiLinkAction*>(comm.model_action_);
-  if (actionWifi == nullptr)
-    return;
-
-  if (auto* link_src = actionWifi->get_src_link()) {
-    link_src->inc_active_flux();
-  }
-  if (auto* link_dst = actionWifi->get_dst_link()) {
-    link_dst->inc_active_flux();
-  }
-}
-
 void WifiLinkImpl::update_bw_comm_end(const simgrid::kernel::resource::NetworkAction& action,
                                       simgrid::kernel::resource::Action::State /*state*/)
 {
index cd08f6d..969eeeb 100644 (file)
@@ -53,9 +53,7 @@ public:
   void set_latency(double) override;
   bool toggle_callback();
 
-  static void update_bw_comm_start(const kernel::activity::CommImpl&);
-  static void update_bw_comm_end(const simgrid::kernel::resource::NetworkAction& action,
-                                 simgrid::kernel::resource::Action::State state);
+  static void update_bw_comm_end(const NetworkAction& action, Action::State state);
   void inc_active_flux();
   void dec_active_flux();
   static double wifi_link_dynamic_sharing(const WifiLinkImpl& link, double capacity, int n);
index c938624..35af6fa 100644 (file)
@@ -113,20 +113,8 @@ void CpuCas01::apply_event(profile::Event* event, double value)
         get_iface()->turn_on();
       }
     } else {
-      const lmm::Element* elem = nullptr;
-      double date              = EngineImpl::get_clock();
-
       get_iface()->turn_off();
-
-      while (const auto* var = get_constraint()->get_variable(&elem)) {
-        Action* action = var->get_id();
-
-        if (action->get_state() == Action::State::INITED || action->get_state() == Action::State::STARTED ||
-            action->get_state() == Action::State::IGNORED) {
-          action->set_finish_time(date);
-          action->set_state(Action::State::FAILED);
-        }
-      }
+      cancel_actions();
     }
     unref_state_event();
 
index c927bec..6b522bb 100644 (file)
@@ -387,13 +387,13 @@ void CpuTi::apply_event(kernel::profile::Event* event, double value)
       }
     } else {
       get_iface()->turn_off();
-      double date = EngineImpl::get_clock();
 
       /* put all action running on cpu to failed */
+      double now = EngineImpl::get_clock();
       for (CpuTiAction& action : action_set_) {
         if (action.get_state() == Action::State::INITED || action.get_state() == Action::State::STARTED ||
             action.get_state() == Action::State::IGNORED) {
-          action.set_finish_time(date);
+          action.set_finish_time(now);
           action.set_state(Action::State::FAILED);
           get_model()->get_action_heap().remove(&action);
         }
index 2c4afc6..5050b1f 100644 (file)
@@ -50,28 +50,6 @@ static inline double has_cost(const double* array, size_t pos)
   return -1.0;
 }
 
-Action* HostCLM03Model::io_stream(s4u::Host* src_host, DiskImpl* src_disk, s4u::Host* dst_host, DiskImpl* dst_disk,
-                                  double size)
-{
-  auto net_model = src_host->get_englobing_zone()->get_network_model();
-  auto system    = net_model->get_maxmin_system();
-  auto* action   = net_model->communicate(src_host, dst_host, size, -1, true);
-
-  // We don't want to apply the network model bandwidth factor to the I/O constraints
-  double bw_factor = net_model->get_bandwidth_factor();
-  if (src_disk != nullptr) {
-    // FIXME: if the stream starts from a disk, we might not want to pay the network latency
-    system->expand(src_disk->get_constraint(), action->get_variable(), bw_factor);
-    system->expand(src_disk->get_read_constraint(), action->get_variable(), bw_factor);
-  }
-  if (dst_disk != nullptr) {
-    system->expand(dst_disk->get_constraint(), action->get_variable(), bw_factor);
-    system->expand(dst_disk->get_write_constraint(), action->get_variable(), bw_factor);
-  }
-
-  return action;
-}
-
 Action* HostCLM03Model::execute_parallel(const std::vector<s4u::Host*>& host_list, const double* flops_amount,
                                          const double* bytes_amount, double rate)
 {
@@ -112,7 +90,7 @@ Action* HostCLM03Model::execute_parallel(const std::vector<s4u::Host*>& host_lis
 
 Action* HostCLM03Model::execute_thread(const s4u::Host* host, double flops_amount, int thread_count)
 {
-  auto cpu = host->get_cpu();
+  auto* cpu = host->get_cpu();
   /* Create a single action whose cost is thread_count * flops_amount and that requests thread_count cores. */
   return cpu->execution_start(thread_count * flops_amount, thread_count, -1);
 }
index 65715c4..cc5fc9f 100644 (file)
@@ -22,8 +22,6 @@ public:
   Action* execute_thread(const s4u::Host* host, double flops_amount, int thread_count) override;
   Action* execute_parallel(const std::vector<s4u::Host*>& host_list, const double* flops_amount,
                            const double* bytes_amount, double rate) override;
-  Action* io_stream(s4u::Host* src_host, DiskImpl* src_disk, s4u::Host* dst_host, DiskImpl* dst_disk,
-                    double size) override;
 };
 } // namespace simgrid::kernel::resource
 
index 2b1e5d1..1a3f926 100644 (file)
@@ -149,14 +149,14 @@ NetworkCm02Model::NetworkCm02Model(const std::string& name) : NetworkModel(name)
 StandardLinkImpl* NetworkCm02Model::create_link(const std::string& name, const std::vector<double>& bandwidths)
 {
   xbt_assert(bandwidths.size() == 1, "Non-WIFI links must use only 1 bandwidth.");
-  auto link = new NetworkCm02Link(name, bandwidths[0], get_maxmin_system());
+  auto* link = new NetworkCm02Link(name, bandwidths[0], get_maxmin_system());
   link->set_model(this);
   return link;
 }
 
 StandardLinkImpl* NetworkCm02Model::create_wifi_link(const std::string& name, const std::vector<double>& bandwidths)
 {
-  auto link = new WifiLinkImpl(name, bandwidths, get_maxmin_system());
+  auto* link = new WifiLinkImpl(name, bandwidths, get_maxmin_system());
   link->set_model(this);
   return link;
 }
@@ -445,7 +445,7 @@ Action* NetworkCm02Model::communicate(s4u::Host* src, s4u::Host* dst, double siz
 
   if (cfg_weight_S_parameter > 0) {
     action->sharing_penalty_ = std::accumulate(route.begin(), route.end(), action->sharing_penalty_,
-                                               [](double total, StandardLinkImpl* const& link) {
+                                               [](double total, StandardLinkImpl const* link) {
                                                  return total + cfg_weight_S_parameter / link->get_bandwidth();
                                                });
   }
index afec012..df4abf1 100644 (file)
@@ -41,7 +41,7 @@ SIMGRID_REGISTER_NETWORK_MODEL(
       engine->get_netzone_root()->set_network_model(net_model);
 
       simgrid::s4u::Link::on_communication_state_change_cb(NetworkIBModel::IB_action_state_changed_callback);
-      simgrid::kernel::activity::CommImpl::on_start.connect(NetworkIBModel::IB_comm_start_callback);
+      simgrid::s4u::Comm::on_start_cb(NetworkIBModel::IB_comm_start_callback);
       simgrid::s4u::Host::on_creation_cb(NetworkIBModel::IB_create_host_callback);
       simgrid::config::set_default<double>("network/weight-S", 8775);
     });
@@ -68,9 +68,9 @@ void NetworkIBModel::IB_action_state_changed_callback(NetworkAction& action, Act
   ibModel->active_comms.erase(&action);
 }
 
-void NetworkIBModel::IB_comm_start_callback(const activity::CommImpl& comm)
+void NetworkIBModel::IB_comm_start_callback(const s4u::Comm& comm)
 {
-  auto* action  = static_cast<NetworkAction*>(comm.model_action_);
+  auto* action  = static_cast<NetworkAction*>(static_cast<activity::CommImpl*>(comm.get_impl())->model_action_);
   auto* ibModel = static_cast<NetworkIBModel*>(action->get_model());
   auto* act_src = &ibModel->active_nodes.at(action->get_src().get_name());
   auto* act_dst = &ibModel->active_nodes.at(action->get_dst().get_name());
index 572f18b..1400d83 100644 (file)
@@ -51,7 +51,7 @@ public:
 
   static void IB_create_host_callback(s4u::Host const& host);
   static void IB_action_state_changed_callback(NetworkAction& action, Action::State /*previous*/);
-  static void IB_comm_start_callback(const activity::CommImpl& comm);
+  static void IB_comm_start_callback(const s4u::Comm& comm);
 };
 } // namespace simgrid::kernel::resource
 #endif
index 423ed3c..3d4c065 100644 (file)
@@ -50,7 +50,6 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(res_ns3, res_network, "Network model based on ns
  *****************/
 
 extern std::map<std::string, SgFlow*, std::less<>> flow_from_sock;
-extern std::map<std::string, ns3::ApplicationContainer, std::less<>> sink_from_sock;
 
 static int number_of_links    = 1;
 static int number_of_networks = 1;
@@ -120,8 +119,14 @@ static void zoneCreation_cb(simgrid::s4u::NetZone const& zone)
   wifiPhy.Set("Antennas", ns3::UintegerValue(nss_value));
   wifiPhy.Set("MaxSupportedTxSpatialStreams", ns3::UintegerValue(nss_value));
   wifiPhy.Set("MaxSupportedRxSpatialStreams", ns3::UintegerValue(nss_value));
-#if NS3_MINOR_VERSION > 33
+#if NS3_MINOR_VERSION < 33
+  // This fails with "The channel width does not uniquely identify an operating channel" on v3.34,
+  // so we specified the ChannelWidth of wifiPhy to 40, above, when creating wifiPhy with v3.34 and higher
+  ns3::Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/ChannelWidth", ns3::UintegerValue(40));
+#elif NS3_MINOR_VERSION < 36
   wifiPhy.Set("ChannelWidth", ns3::UintegerValue(40));
+#else
+  wifiPhy.Set("ChannelSettings", ns3::StringValue("{0, 40, BAND_UNSPECIFIED, 0}"));
 #endif
   wifiMac.SetType("ns3::ApWifiMac", "Ssid", ns3::SsidValue(ssid));
 
@@ -167,12 +172,6 @@ static void zoneCreation_cb(simgrid::s4u::NetZone const& zone)
     ns3::Simulator::Schedule(ns3::Seconds(start_time_value), &resumeWifiDevice, device);
   }
 
-#if NS3_MINOR_VERSION < 33
-  // This fails with "The channel width does not uniquely identify an operating channel" on v3.34,
-  // so we specified the ChannelWidth of wifiPhy to 40, above, when creating wifiPhy with v3.34 and higher
-  ns3::Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/ChannelWidth", ns3::UintegerValue(40));
-#endif
-
   mobility.SetPositionAllocator(positionAllocS);
   mobility.Install(nodes);
   ns3::Ipv4AddressHelper address;
@@ -288,8 +287,9 @@ static void XBT_ATTRIB_CONSTRUCTOR(800) simgrid_ns3_network_model_register()
       });
 }
 
-static simgrid::config::Flag<std::string>
-    ns3_tcp_model("ns3/TcpModel", "The ns-3 tcp model can be: NewReno or Reno or Tahoe", "default");
+static simgrid::config::Flag<std::string> ns3_network_model_name("ns3/NetworkModel", {"ns3/TcpModel"},
+                                                                 "The ns-3 tcp model can be: NewReno or Cubic",
+                                                                 "default", [](const std::string&) {});
 static simgrid::config::Flag<std::string> ns3_seed(
     "ns3/seed",
     "The random seed provided to ns-3. Either 'time' to seed with time(), blank to not set (default), or a number.", "",
@@ -317,20 +317,34 @@ NetworkNS3Model::NetworkNS3Model(const std::string& name) : NetworkModel(name)
              "LinkEnergy plugin and ns-3 network models are not compatible. Are you looking for Ecofen, maybe?");
 
   NetPointNs3::EXTENSION_ID = routing::NetPoint::extension_create<NetPointNs3>();
+  auto const& NetworkProtocol = ns3_network_model_name.get();
+
+  if (NetworkProtocol == "UDP") {
+    /*UdpClient=0
+UdpEchoClientApplication=0
+UdpEchoServerApplication=0
+UdpL4Protocol=0
+UdpServer=0
+UdpSocket=0
+UdpSocketImpl=0
+UdpTraceClient=0*/
+    LogComponentEnable("UdpSocket", ns3::LOG_LEVEL_DEBUG);
+    LogComponentEnable("UdpL4Protocol", ns3::LOG_LEVEL_DEBUG);
+  } else {
+    ns3::Config::SetDefault("ns3::TcpSocket::SegmentSize", ns3::UintegerValue(1000));
+    ns3::Config::SetDefault("ns3::TcpSocket::DelAckCount", ns3::UintegerValue(1));
+    ns3::Config::SetDefault("ns3::TcpSocketBase::Timestamp", ns3::BooleanValue(false));
+  }
 
-  ns3::Config::SetDefault("ns3::TcpSocket::SegmentSize", ns3::UintegerValue(1000));
-  ns3::Config::SetDefault("ns3::TcpSocket::DelAckCount", ns3::UintegerValue(1));
-  ns3::Config::SetDefault("ns3::TcpSocketBase::Timestamp", ns3::BooleanValue(false));
-
-  if (auto const& TcpProtocol = ns3_tcp_model.get(); TcpProtocol == "default") {
-    /* nothing to do */
+  if (NetworkProtocol == "NewReno" || NetworkProtocol == "Cubic") {
+    XBT_INFO("Switching Tcp protocol to '%s'", NetworkProtocol.c_str());
+    ns3::Config::SetDefault("ns3::TcpL4Protocol::SocketType", ns3::StringValue("ns3::Tcp" + NetworkProtocol));
 
-  } else if (TcpProtocol == "Reno" || TcpProtocol == "NewReno" || TcpProtocol == "Tahoe") {
-    XBT_INFO("Switching Tcp protocol to '%s'", TcpProtocol.c_str());
-    ns3::Config::SetDefault("ns3::TcpL4Protocol::SocketType", ns3::StringValue("ns3::Tcp" + TcpProtocol));
+  } else if (NetworkProtocol == "UDP") {
+    XBT_INFO("Switching network protocol to UDP.");
 
-  } else {
-    xbt_die("The ns3/TcpModel must be: NewReno or Reno or Tahoe");
+  } else if (NetworkProtocol != "default") {
+    xbt_die("The ns3/NetworkModel must be: NewReno, Cubic or UDP but it's '%s'", NetworkProtocol.c_str());
   }
 
   routing::NetPoint::on_creation.connect([](routing::NetPoint& pt) {
@@ -340,7 +354,6 @@ NetworkNS3Model::NetworkNS3Model(const std::string& name) : NetworkModel(name)
 
   s4u::Engine::on_platform_created_cb([]() {
     /* Create the ns3 topology based on routing strategy */
-    ns3::GlobalRouteManager::DeleteGlobalRoutes(); // just in case this callback is called twice
     ns3::GlobalRouteManager::BuildGlobalRoutingDatabase();
     ns3::GlobalRouteManager::InitializeRoutes();
   });
@@ -377,6 +390,31 @@ Action* NetworkNS3Model::communicate(s4u::Host* src, s4u::Host* dst, double size
   return new NetworkNS3Action(this, size, src, dst);
 }
 
+#if SIMGRID_HAVE_NS3_GetNextEventTime
+/* If patched, ns3 is idempotent and nice to use */
+bool NetworkNS3Model::next_occurring_event_is_idempotent()
+{
+  return true;
+}
+
+double NetworkNS3Model::next_occurring_event(double sg_time)
+{
+  if (get_started_action_set()->empty()) {
+    return -1.0;
+  }
+
+  double ns3_time = ns3::Simulator::GetNextEventTime().GetSeconds();
+  XBT_DEBUG("NS3 tells that the next occuring event is at %f (it's %f in SimGrid), so NS3 returns a delta of %f.",
+            ns3_time, sg_time, ns3_time - sg_time);
+  return ns3_time - sg_time;
+}
+#else
+/* NS3 is only idempotent with the appropriate patch */
+bool NetworkNS3Model::next_occurring_event_is_idempotent()
+{
+  return false;
+}
+
 double NetworkNS3Model::next_occurring_event(double now)
 {
   double time_to_next_flow_completion = 0.0;
@@ -406,11 +444,25 @@ double NetworkNS3Model::next_occurring_event(double now)
 
   return time_to_next_flow_completion;
 }
+#endif
 
 void NetworkNS3Model::update_actions_state(double now, double delta)
 {
   static std::vector<std::string> socket_to_destroy;
 
+#if SIMGRID_HAVE_NS3_GetNextEventTime
+  /* If the ns-3 model is idempotent, it won't get updated in next_occurring_event() */
+
+  if (delta >= 0) {
+    XBT_DEBUG("DO START simulator delta: %f (current simgrid time: %f; current ns3 time: %f)", delta,
+              simgrid::kernel::EngineImpl::get_clock(), ns3::Simulator::Now().GetSeconds());
+    ns3_simulator(delta);
+  } else {
+    XBT_DEBUG("don't start simulator delta: %f (current simgrid time: %f; current ns3 time: %f)", delta,
+              simgrid::kernel::EngineImpl::get_clock(), ns3::Simulator::Now().GetSeconds());
+  }
+#endif
+
   for (const auto& [ns3_socket, sgFlow] : flow_from_sock) {
     NetworkNS3Action* action = sgFlow->action_;
     XBT_DEBUG("Processing flow %p (socket %s, action %p)", sgFlow, ns3_socket.c_str(), action);
@@ -427,7 +479,7 @@ void NetworkNS3Model::update_actions_state(double now, double delta)
 
       std::vector<StandardLinkImpl*> route;
       action->get_src().route_to(&action->get_dst(), route, nullptr);
-      for (auto const& link : route)
+      for (auto const* link : route)
         instr::resource_set_utilization("LINK", "bandwidth_used", link->get_cname(), action->get_category(),
                                         data_delta_sent / delta, now - delta, delta);
 
@@ -455,7 +507,6 @@ void NetworkNS3Model::update_actions_state(double now, double delta)
     }
     delete flow;
     flow_from_sock.erase(ns3_socket);
-    sink_from_sock.erase(ns3_socket);
   }
 }
 
@@ -506,7 +557,7 @@ NetworkNS3Action::NetworkNS3Action(Model* model, double totalBytes, s4u::Host* s
   if (src == dst) {
     if (static bool warned = false; not warned) {
       XBT_WARN("Sending from a host %s to itself is not supported by ns-3. Every such communication finishes "
-               "immediately upon startup.",
+               "immediately upon startup in the SimGrid+ns-3 system.",
                src->get_cname());
       warned = true;
     }
@@ -533,17 +584,18 @@ NetworkNS3Action::NetworkNS3Action(Model* model, double totalBytes, s4u::Host* s
              dst->get_netpoint()->get_cname());
 
   ns3::PacketSinkHelper sink("ns3::TcpSocketFactory", ns3::InetSocketAddress(ns3::Ipv4Address::GetAny(), port_number));
-  ns3::ApplicationContainer apps = sink.Install(dst_node);
+  sink.Install(dst_node);
 
   ns3::Ptr<ns3::Socket> sock = ns3::Socket::CreateSocket(src_node, ns3::TcpSocketFactory::GetTypeId());
 
-  XBT_DEBUG("Create socket %s for a flow of %.0f Bytes from %s to %s with Interface %s",
-            transform_socket_ptr(sock).c_str(), totalBytes, src->get_cname(), dst->get_cname(), addr.c_str());
+  auto sock_addr = transform_socket_ptr(sock);
+  XBT_DEBUG("Create socket %s for a flow of %.0f Bytes from %s to %s with Interface %s", sock_addr.c_str(), totalBytes,
+            src->get_cname(), dst->get_cname(), addr.c_str());
 
-  flow_from_sock.try_emplace(transform_socket_ptr(sock), new SgFlow(static_cast<uint32_t>(totalBytes), this));
-  sink_from_sock.try_emplace(transform_socket_ptr(sock), apps);
+  flow_from_sock.try_emplace(sock_addr, new SgFlow(static_cast<uint32_t>(totalBytes), this));
 
   sock->Bind(ns3::InetSocketAddress(port_number));
+
   ns3::Simulator::ScheduleNow(&start_flow, sock, addr.c_str(), port_number);
 
   port_number = 1 + (port_number % UINT16_MAX);
@@ -574,22 +626,27 @@ void NetworkNS3Action::update_remains_lazy(double /*now*/)
 
 ns3::Ptr<ns3::Node> get_ns3node_from_sghost(const simgrid::s4u::Host* host)
 {
-  xbt_assert(host->get_netpoint()->extension<NetPointNs3>() != nullptr, "Please only use this function on ns-3 nodes");
-  return host->get_netpoint()->extension<NetPointNs3>()->ns3_node_;
+  auto* netext = host->get_netpoint()->extension<NetPointNs3>();
+  xbt_assert(netext != nullptr, "Please only use this function on ns-3 nodes");
+  return netext->ns3_node_;
 }
 } // namespace simgrid
 
-void ns3_simulator(double maxSeconds)
+void ns3_simulator(double maxSeconds) // maxSecond is a delay, not an absolute time
 {
   ns3::EventId id;
-  if (maxSeconds > 0.0) // If there is a maximum amount of time to run
+  if (maxSeconds >= 0.0) // If there is a maximum amount of time to run
     id = ns3::Simulator::Schedule(ns3::Seconds(maxSeconds), &ns3::Simulator::Stop);
 
-  XBT_DEBUG("Start simulator for at most %fs (current time: %f)", maxSeconds, simgrid::kernel::EngineImpl::get_clock());
+  XBT_DEBUG("Start simulator for at most %fs (current simgrid time: %f; current ns3 time: %f)", maxSeconds,
+            simgrid::kernel::EngineImpl::get_clock(), ns3::Simulator::Now().GetSeconds());
+#if SIMGRID_HAVE_NS3_GetNextEventTime
+  xbt_assert(maxSeconds >= 0.0);
+#endif
   ns3::Simulator::Run();
-  XBT_DEBUG("Simulator stopped at %fs", ns3::Simulator::Now().GetSeconds());
+  XBT_DEBUG("ns3 simulator stopped at %fs", ns3::Simulator::Now().GetSeconds());
 
-  if (maxSeconds > 0.0)
+  if (maxSeconds >= 0.0)
     id.Cancel();
 }
 
index 9ec2c4b..f68c1f5 100644 (file)
@@ -12,7 +12,7 @@
 #include "src/kernel/resource/NetworkModel.hpp"
 #include "src/kernel/resource/StandardLinkImpl.hpp"
 
-namespace simgrid ::kernel::resource {
+namespace simgrid::kernel::resource {
 
 class NetworkNS3Model : public NetworkModel {
 public:
@@ -22,7 +22,7 @@ public:
   StandardLinkImpl* create_wifi_link(const std::string& name, const std::vector<double>& bandwidth) override;
   Action* communicate(s4u::Host* src, s4u::Host* dst, double size, double rate, bool streamed) override;
   double next_occurring_event(double now) override;
-  bool next_occurring_event_is_idempotent() override { return false; }
+  bool next_occurring_event_is_idempotent() override;
   void update_actions_state(double now, double delta) override;
 };
 
index 0c13eab..bbc6206 100644 (file)
 
 #include <algorithm>
 
-std::map<std::string, SgFlow*, std::less<>> flow_from_sock;                   // ns3::sock -> SgFlow
-std::map<std::string, ns3::ApplicationContainer, std::less<>> sink_from_sock; // ns3::sock -> ns3::PacketSink
+std::map<std::string, SgFlow*, std::less<>> flow_from_sock; // ns3::sock -> SgFlow
 
 static void receive_callback(ns3::Ptr<ns3::Socket> socket);
 static void datasent_cb(ns3::Ptr<ns3::Socket> socket, uint32_t dataSent);
 
 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(res_ns3);
 
-SgFlow::SgFlow(uint32_t totalBytes, simgrid::kernel::resource::NetworkNS3Action* action)
-    : total_bytes_(totalBytes), remaining_(totalBytes), action_(action)
-{
-}
-
 static SgFlow* getFlowFromSocket(ns3::Ptr<ns3::Socket> socket)
 {
   auto it = flow_from_sock.find(transform_socket_ptr(socket));
   return (it == flow_from_sock.end()) ? nullptr : it->second;
 }
 
-static ns3::ApplicationContainer* getSinkFromSocket(ns3::Ptr<ns3::Socket> socket)
-{
-  auto it = sink_from_sock.find(transform_socket_ptr(socket));
-  return (it == sink_from_sock.end()) ? nullptr : &(it->second);
-}
-
 static void receive_callback(ns3::Ptr<ns3::Socket> socket)
 {
   SgFlow* flow = getFlowFromSocket(socket);
@@ -57,8 +45,7 @@ static void receive_callback(ns3::Ptr<ns3::Socket> socket)
 
 static void send_cb(ns3::Ptr<ns3::Socket> sock, uint32_t /*txSpace*/)
 {
-  SgFlow* flow                          = getFlowFromSocket(sock);
-  const ns3::ApplicationContainer* sink = getSinkFromSocket(sock);
+  SgFlow* flow = getFlowFromSocket(sock);
   XBT_DEBUG("Asked to write on F[%p, total: %u, remain: %u]", flow, flow->total_bytes_, flow->remaining_);
 
   if (flow->remaining_ == 0) // all data was already buffered (and socket was already closed)
@@ -85,15 +72,7 @@ static void send_cb(ns3::Ptr<ns3::Socket> sock, uint32_t /*txSpace*/)
   }
 
   if (flow->buffered_bytes_ >= flow->total_bytes_) {
-    XBT_DEBUG("Closing Sockets of flow %p", flow);
-    // Closing the sockets of the receiving application
-    ns3::Ptr<ns3::PacketSink> app        = ns3::DynamicCast<ns3::PacketSink, ns3::Application>(sink->Get(0));
-    ns3::Ptr<ns3::Socket> listening_sock = app->GetListeningSocket();
-    listening_sock->Close();
-    listening_sock->SetRecvCallback(ns3::MakeNullCallback<void, ns3::Ptr<ns3::Socket>>());
-    for (ns3::Ptr<ns3::Socket> accepted_sock : app->GetAcceptedSockets())
-      accepted_sock->Close();
-    // Closing the socket of the sender
+    XBT_DEBUG("Closing sender's socket of flow %p", flow);
     sock->Close();
   }
 }
@@ -141,10 +120,11 @@ XBT_ATTRIB_NORETURN static void failedConnect_callback(ns3::Ptr<ns3::Socket> soc
 void start_flow(ns3::Ptr<ns3::Socket> sock, const char* to, uint16_t port_number)
 {
   SgFlow* flow = getFlowFromSocket(sock);
-  ns3::InetSocketAddress serverAddr(to, port_number);
 
+  ns3::InetSocketAddress serverAddr(to, port_number);
   sock->Connect(serverAddr);
-  // tell the tcp implementation to call send_cb again
+
+  // tell the network implementation to call send_cb again
   // if we blocked and new tx buffer space becomes available
   sock->SetSendCallback(MakeCallback(&send_cb));
   // Notice when we actually sent some data (mostly for the TRACING module)
index 375b6bb..d7e35a4 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <ns3/node.h>
 #include <ns3/tcp-socket-factory.h>
+#include <ns3/udp-socket-factory.h>
 #include <ns3/wifi-module.h>
 
 #include <cstdint>
@@ -31,7 +32,10 @@ XBT_PRIVATE void ns3_add_direct_route(const simgrid::kernel::routing::NetPoint*
 
 class XBT_PRIVATE SgFlow {
 public:
-  SgFlow(uint32_t total_bytes, simgrid::kernel::resource::NetworkNS3Action* action);
+  SgFlow(uint32_t totalBytes, simgrid::kernel::resource::NetworkNS3Action* action)
+      : total_bytes_(totalBytes), remaining_(totalBytes), action_(action)
+  {
+  }
 
   // private:
   std::uint32_t buffered_bytes_ = 0;
index 769292c..13f4986 100644 (file)
@@ -56,7 +56,7 @@ HostL07Model::HostL07Model(const std::string& name, lmm::System* sys) : HostMode
   set_maxmin_system(sys);
 
   auto net_model = std::make_shared<NetworkL07Model>("Network_Ptask", this, sys);
-  auto engine    = EngineImpl::get_instance();
+  auto* engine   = EngineImpl::get_instance();
   engine->add_model(net_model);
   engine->get_netzone_root()->set_network_model(net_model);
 
@@ -194,7 +194,7 @@ L07Action::L07Action(Model* model, const std::vector<s4u::Host*>& host_list, con
       host_list_[k / host_nb]->route_to(host_list_[k % host_nb], route, &lat);
       latency = std::max(latency, lat);
 
-      for (auto const& link : route)
+      for (auto const* link : route)
         affected_links.insert(link->get_cname());
     }
 
@@ -204,7 +204,8 @@ L07Action::L07Action(Model* model, const std::vector<s4u::Host*>& host_list, con
   XBT_DEBUG("Creating a parallel task (%p) with %zu hosts and %zu unique links.", this, host_nb, link_nb);
   latency_ = latency;
 
-  set_variable(model->get_maxmin_system()->variable_new(this, 1.0, (rate > 0 ? rate : -1.0), host_nb + link_nb));
+  // Allocate more space for constraints (+4) in case users want to mix ptasks and io streams
+  set_variable(model->get_maxmin_system()->variable_new(this, 1.0, (rate > 0 ? rate : -1.0), host_nb + link_nb + 4));
 
   if (latency_ > 0)
     model->get_maxmin_system()->update_variable_penalty(get_variable(), 0.0);
@@ -223,7 +224,7 @@ L07Action::L07Action(Model* model, const std::vector<s4u::Host*>& host_list, con
       std::vector<StandardLinkImpl*> route;
       host_list_[k / host_nb]->route_to(host_list_[k % host_nb], route, nullptr);
 
-      for (auto const& link : route)
+      for (auto const* link : route)
         model->get_maxmin_system()->expand(link->get_constraint(), this->get_variable(), bytes_amount[k]);
     }
   }
@@ -257,7 +258,7 @@ CpuImpl* CpuL07Model::create_cpu(s4u::Host* host, const std::vector<double>& spe
 StandardLinkImpl* NetworkL07Model::create_link(const std::string& name, const std::vector<double>& bandwidths)
 {
   xbt_assert(bandwidths.size() == 1, "Non WIFI link must have only 1 bandwidth.");
-  auto link = new LinkL07(name, bandwidths[0], get_maxmin_system());
+  auto* link = new LinkL07(name, bandwidths[0], get_maxmin_system());
   link->set_model(this);
   return link;
 }
index d7db18f..0683aff 100644 (file)
@@ -3,15 +3,16 @@
 /* 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 HOST_L07_HPP_
+#define HOST_L07_HPP_
+
 #include "src/kernel/resource/HostImpl.hpp"
 #include "src/kernel/resource/NetworkModel.hpp"
+#include "src/simgrid/math_utils.h"
 #include <cstdlib>
 #include <vector>
 #include <xbt/base.h>
 
-#ifndef HOST_L07_HPP_
-#define HOST_L07_HPP_
-
 namespace simgrid::kernel::resource {
 
 /***********
@@ -41,11 +42,6 @@ public:
   Action* execute_thread(const s4u::Host* host, double flops_amount, int thread_count) override { return nullptr; }
   CpuAction* execute_parallel(const std::vector<s4u::Host*>& host_list, const double* flops_amount,
                               const double* bytes_amount, double rate) override;
-  Action* io_stream(s4u::Host* src_host, DiskImpl* src_disk, s4u::Host* dst_host, DiskImpl* dst_disk,
-                    double size) override
-  {
-    return nullptr;
-  }
 };
 
 class CpuL07Model : public CpuModel {
index 74a0605..34b4071 100644 (file)
@@ -4,8 +4,10 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/kernel/resource/profile/FutureEvtSet.hpp"
+#include "src/kernel/resource/Resource.hpp"
 #include "src/kernel/resource/profile/Event.hpp"
 #include "src/kernel/resource/profile/Profile.hpp"
+#include <simgrid/s4u/Engine.hpp>
 
 namespace simgrid::kernel::profile {
 
@@ -23,6 +25,23 @@ FutureEvtSet::~FutureEvtSet()
 /** @brief Schedules an event to a future date */
 void FutureEvtSet::add_event(double date, Event* evt)
 {
+  if (heap_.empty())
+    s4u::Engine::on_platform_created_cb([this]() {
+      /* Handle the events of time = 0 right after the platform creation */
+      double next_event_date;
+      while ((next_event_date = this->next_date()) != -1.0) {
+        if (next_event_date > 0)
+          break;
+
+        double value                 = -1.0;
+        resource::Resource* resource = nullptr;
+        while (auto* event = this->pop_leq(next_event_date, &value, &resource)) {
+          if (value >= 0)
+            resource->apply_event(event, value);
+        }
+      }
+    });
+
   heap_.emplace(date, evt);
 }
 
index e32e6ae..97ff0ab 100644 (file)
@@ -44,7 +44,7 @@ static std::vector<simgrid::kernel::profile::DatedValue> trace2vector(const char
 
   MockedResource daResource;
   simgrid::kernel::profile::FutureEvtSet fes;
-  simgrid::kernel::profile::Event* insertedIt = trace->schedule(&fes, &daResource);
+  const simgrid::kernel::profile::Event* insertedIt = trace->schedule(&fes, &daResource);
 
   while (fes.next_date() <= 20.0 && fes.next_date() >= 0) {
     MockedResource::the_date = fes.next_date();
index 72f6dca..fa82dd4 100644 (file)
@@ -3,6 +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 "simgrid/s4u/Host.hpp"
 #include "simgrid/kernel/routing/ClusterZone.hpp"
 #include "simgrid/kernel/routing/NetPoint.hpp"
 #include "src/kernel/resource/StandardLinkImpl.hpp"
@@ -82,7 +83,17 @@ void ClusterBase::fill_leaf_from_cb(unsigned long position, const std::vector<un
   kernel::routing::NetPoint* netpoint = nullptr;
   kernel::routing::NetPoint* gw       = nullptr;
   auto dims                           = index_to_dims(position);
-  std::tie(netpoint, gw)              = set_callbacks.netpoint(get_iface(), dims, position);
+  if (set_callbacks.is_by_netpoint()) { // XBT_ATTRIB_DEPRECATED_v339
+    std::tie(netpoint, gw) = set_callbacks.netpoint(get_iface(), dims, position); // XBT_ATTRIB_DEPRECATED_v339
+  } else if (set_callbacks.is_by_netzone()) {
+    s4u::NetZone* netzone = set_callbacks.netzone(get_iface(), dims, position);
+    netpoint              = netzone->get_netpoint();
+    gw                    = netzone->get_gateway();
+  } else {
+    s4u::Host* host = set_callbacks.host(get_iface(), dims, position);
+    netpoint        = host->get_netpoint();
+  }
+
   xbt_assert(netpoint, "set_netpoint(elem=%lu): Invalid netpoint (nullptr)", position);
   if (netpoint->is_netzone()) {
     xbt_assert(gw && not gw->is_netzone(),
index 379f431..9a1c89a 100644 (file)
@@ -30,7 +30,6 @@ TEST_CASE("kernel::routing::DijkstraZone: mix new routes and hosts", "")
   for (int i = 0; i < 10; i++) {
     std::string cpu_name          = "CPU" + std::to_string(i);
     const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9)->seal();
-    REQUIRE_NOTHROW(zone->add_route(cpu->get_netpoint(), nic->get_netpoint(), nullptr, nullptr,
-                                    {simgrid::s4u::LinkInRoute(link)}, true));
+    REQUIRE_NOTHROW(zone->add_route(cpu, nic,{link}));
   }
 }
index e0c751b..f4fbe4a 100644 (file)
@@ -24,12 +24,11 @@ TEST_CASE("kernel::routing::FloydZone: mix new routes and hosts", "")
   simgrid::s4u::Engine e("test");
   auto* zone = simgrid::s4u::create_floyd_zone("test");
 
-  const simgrid::s4u::Host* nic  = zone->create_host("nic", 1e9)->seal();
-  const simgrid::s4u::Link* link = zone->create_link("my_link", 1e6)->seal();
+  const simgrid::s4u::Host* nic  = zone->create_host("nic", 1e9);
+  const simgrid::s4u::Link* link = zone->create_link("my_link", 1e6);
   for (int i = 0; i < 10; i++) {
     std::string cpu_name          = "CPU" + std::to_string(i);
-    const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9)->seal();
-    REQUIRE_NOTHROW(zone->add_route(cpu->get_netpoint(), nic->get_netpoint(), nullptr, nullptr,
-                                    {simgrid::s4u::LinkInRoute(link)}, true));
+    const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9);
+    REQUIRE_NOTHROW(zone->add_route(cpu, nic, {link}));
   }
 }
index 1be4da6..9ffcab7 100644 (file)
@@ -24,12 +24,11 @@ TEST_CASE("kernel::routing::FullZone: mix new routes and hosts", "[bug]")
   simgrid::s4u::Engine e("test");
   auto* zone = simgrid::s4u::create_full_zone("test");
 
-  const simgrid::s4u::Host* nic  = zone->create_host("nic", 1e9)->seal();
-  const simgrid::s4u::Link* link = zone->create_link("my_link", 1e6)->seal();
+  const simgrid::s4u::Host* nic  = zone->create_host("nic", 1e9);
+  const simgrid::s4u::Link* link = zone->create_link("my_link", 1e6);
   for (int i = 0; i < 10; i++) {
     std::string cpu_name          = "CPU" + std::to_string(i);
-    const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9)->seal();
-    REQUIRE_NOTHROW(zone->add_route(cpu->get_netpoint(), nic->get_netpoint(), nullptr, nullptr,
-                                    {simgrid::s4u::LinkInRoute(link)}, true));
+    const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9);
+    REQUIRE_NOTHROW(zone->add_route(cpu, nic, {link}));
   }
 }
index 9030233..08df429 100644 (file)
@@ -622,8 +622,8 @@ void NetZoneImpl::get_graph(const s_xbt_graph_t* graph, std::map<std::string, xb
 {
   std::vector<NetPoint*> vertices = get_vertices();
 
-  for (auto const& my_src : vertices) {
-    for (auto const& my_dst : vertices) {
+  for (auto const* my_src : vertices) {
+    for (auto const* my_dst : vertices) {
       if (my_src == my_dst)
         continue;
 
@@ -669,6 +669,24 @@ void NetZoneImpl::get_graph(const s_xbt_graph_t* graph, std::map<std::string, xb
   }
 }
 
+void NetZoneImpl::set_gateway(const std::string& name, NetPoint* router)
+{
+  xbt_enforce(not sealed_, "Impossible to create gateway: %s. NetZone %s already sealed", name.c_str(), get_cname());
+  if (auto gateway_it = gateways_.find(name); gateway_it != gateways_.end())
+    xbt_die("Impossible to create a gateway named %s. It already exists", name.c_str());
+  else
+    gateways_[name] = router;
+}
+
+NetPoint* NetZoneImpl::get_gateway() const
+{
+  xbt_enforce(not gateways_.empty(), "No default gateway has been defined for NetZone '%s'. Try to seal it first", get_cname());
+  xbt_enforce(gateways_.size() < 2, "NetZone '%s' has more than one gateway, please provide a gateway name", get_cname());
+  auto gateway_it = gateways_.find("default");
+  xbt_enforce(gateway_it != gateways_.end(), "NetZone '%s' hasno default gateway, please define one", get_cname());
+  return gateway_it->second;
+}
+
 void NetZoneImpl::seal()
 {
   /* already sealed netzone */
@@ -676,6 +694,10 @@ void NetZoneImpl::seal()
     return;
   do_seal(); // derived class' specific sealing procedure
 
+  // for zone with a single host, this host is its own default gateway
+  if (gateways_.empty() && hosts_.size() == 1)
+    gateways_["default"] = hosts_.begin()->second->get_iface()->get_netpoint();
+
   /* seals sub-netzones and hosts */
   for (auto* host : get_all_hosts()) {
     host->seal();
index 3cc1c7a..76a955b 100644 (file)
@@ -6,17 +6,16 @@
 #ifndef NETZONE_TEST_HPP
 #define NETZONE_TEST_HPP
 
-#include "simgrid/kernel/routing/NetPoint.hpp"
-#include "simgrid/s4u/Host.hpp"
 #include "simgrid/s4u/NetZone.hpp"
+#include "xbt/log.h"
+XBT_LOG_EXTERNAL_CATEGORY(ker_platform);
 
 // Callback function common to several routing unit tests
 struct CreateHost {
-  std::pair<simgrid::kernel::routing::NetPoint*, simgrid::kernel::routing::NetPoint*>
-  operator()(simgrid::s4u::NetZone* zone, const std::vector<unsigned long>& /*coord*/, unsigned long id) const
+  simgrid::s4u::Host* operator()(simgrid::s4u::NetZone* zone, const std::vector<unsigned long>& /*coord*/,
+                                    unsigned long id) const
   {
-    const simgrid::s4u::Host* host = zone->create_host(std::to_string(id), 1e9)->seal();
-    return std::make_pair(host->get_netpoint(), nullptr);
+    return zone->create_host(std::to_string(id), "1Gf");
   }
 };
 
index 66dac29..4c7ff4d 100644 (file)
@@ -287,7 +287,6 @@ TEST_CASE("kernel::routing::StarZone: mix new routes and hosts", "")
   for (int i = 0; i < 10; i++) {
     std::string cpu_name          = "CPU" + std::to_string(i);
     const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9)->seal();
-    REQUIRE_NOTHROW(
-        zone->add_route(cpu->get_netpoint(), nullptr, nullptr, nullptr, {simgrid::s4u::LinkInRoute(link)}, true));
+    REQUIRE_NOTHROW(zone->add_route(cpu, nullptr, {link}));
   }
 }
index 11fd3b4..8019943 100644 (file)
@@ -17,7 +17,7 @@
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_routing_torus, ker_platform, "Kernel Torus Routing");
 
 namespace simgrid {
-namespace kernel ::routing {
+namespace kernel::routing {
 
 void TorusZone::create_torus_links(unsigned long id, int rank, unsigned long position)
 {
index 79374c1..9e3d355 100644 (file)
@@ -23,7 +23,7 @@ XBT_PUBLIC void simgrid_parse_assert_netpoint(const std::string& hostname, const
 XBT_PUBLIC double simgrid_parse_get_double(const std::string& s);
 XBT_PUBLIC int simgrid_parse_get_int(const std::string& s);
 
-XBT_PUBLIC void simgrid_parse(); /* Entry-point to the parser */
+XBT_PUBLIC void simgrid_parse(bool fire_on_platform_created_callback); /* Entry-point to the parser */
 XBT_PUBLIC void parse_platform_file(const std::string& file);
 
 #endif
index be3a2d1..64f1627 100644 (file)
@@ -13,6 +13,7 @@
 #include "src/kernel/xml/simgrid_dtd.h"
 
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
index df5b5cc..d48b491 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <simgrid/Exception.hpp>
 #include <simgrid/kernel/routing/NetPoint.hpp>
+#include <simgrid/s4u/Disk.hpp>
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/s4u/Host.hpp>
 #include <xbt/file.hpp>
@@ -31,6 +32,8 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(platf_parse, ker_platform, "Logging specific to
 std::string simgrid_parsed_filename;                            // Currently parsed file (for the error messages)
 static std::vector<simgrid::s4u::LinkInRoute> parsed_link_list; /* temporary store of current link list of a route */
 
+static bool fire_on_platform_created_callback;
+
 /* Helping functions */
 void simgrid_parse_assert(bool cond, const std::string& msg)
 {
@@ -257,9 +260,56 @@ void STag_simgrid_parse_platform()
                            "The most recent formalism that this version of SimGrid understands is v4.1.\n"
                            "Please update your code, or use another, more adapted, file.");
 }
+
+static void add_remote_disks()
+{
+  for (auto const& host : simgrid::s4u::Engine::get_instance()->get_all_hosts()) {
+    const char* remote_disk_str = host->get_property("remote_disk");
+    if (not remote_disk_str)
+      continue;
+    std::vector<std::string> tokens;
+    boost::split(tokens, remote_disk_str, boost::is_any_of(":"));
+    const 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");
+    host->add_disk(disk);
+
+    XBT_DEBUG("Host '%s' wants to access a remote disk: %s of %s", host->get_cname(), disk->get_cname(),
+              remote_host->get_cname());
+    XBT_DEBUG("Host '%s' now has %zu disks", host->get_cname(), host->get_disks().size());
+  }
+}
+
+static void remove_remote_disks()
+{
+  XBT_DEBUG("Simulation is over, time to unregister remote disks if any");
+  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(":"));
+      XBT_DEBUG("Host '%s' wants to unmount a remote disk: %s of %s", host->get_cname(),
+                tokens[1].c_str(), tokens[2].c_str());
+      host->remove_disk(tokens[1]);
+      XBT_DEBUG("Host '%s' now has %zu disks", host->get_cname(), host->get_disks().size());
+    }
+  }
+}
+
 void ETag_simgrid_parse_platform()
 {
-  simgrid::s4u::Engine::on_platform_created();
+  simgrid::s4u::Engine::on_platform_created_cb(&add_remote_disks);
+  simgrid::s4u::Engine::on_simulation_end_cb(&remove_remote_disks);
+  if (fire_on_platform_created_callback)
+    simgrid::s4u::Engine::on_platform_created();
 }
 
 void STag_simgrid_parse_prop()
@@ -532,7 +582,7 @@ void ETag_simgrid_parse_link()
 
 void STag_simgrid_parse_link___ctn()
 {
-  const auto engine = simgrid::s4u::Engine::get_instance();
+  const auto* engine = simgrid::s4u::Engine::get_instance();
   const simgrid::s4u::Link* link;
   simgrid::s4u::LinkInRoute::Direction direction = simgrid::s4u::LinkInRoute::Direction::NONE;
   switch (A_simgrid_parse_link___ctn_direction) {
@@ -947,20 +997,21 @@ void simgrid_parse_close()
 }
 
 /* Call the lexer to parse the currently opened file */
-void simgrid_parse()
+void simgrid_parse(bool fire_on_platform_created_callback_param)
 {
+  fire_on_platform_created_callback = fire_on_platform_created_callback_param;
   bool err = simgrid_parse_lex();
   simgrid_parse_assert(not err, "Flex returned an error code");
 
   /* Actually connect the traces now that every elements are created */
-  const auto engine = simgrid::s4u::Engine::get_instance();
+  const auto* engine = simgrid::s4u::Engine::get_instance();
 
   for (auto const& [trace, name] : trace_connect_list_host_avail) {
     simgrid_parse_assert(traces_set_list.find(trace) != traces_set_list.end(),
                          "<trace_connect kind=\"HOST_AVAIL\">: Trace " + trace + " undefined.");
-    auto profile = traces_set_list.at(trace);
+    auto* profile = traces_set_list.at(trace);
 
-    auto host = engine->host_by_name_or_null(name);
+    auto* host = engine->host_by_name_or_null(name);
     simgrid_parse_assert(host, "<trace_connect kind=\"HOST_AVAIL\">: Host " + name + " undefined.");
     host->set_state_profile(profile);
   }
@@ -969,9 +1020,9 @@ void simgrid_parse()
   for (auto const& [trace, name] : trace_connect_list_host_speed) {
     simgrid_parse_assert(traces_set_list.find(trace) != traces_set_list.end(),
                          "<trace_connect kind=\"SPEED\">: Trace " + trace + " undefined.");
-    auto profile = traces_set_list.at(trace);
+    auto* profile = traces_set_list.at(trace);
 
-    auto host = engine->host_by_name_or_null(name);
+    auto* host = engine->host_by_name_or_null(name);
     simgrid_parse_assert(host, "<trace_connect kind=\"SPEED\">: Host " + name + " undefined.");
     host->set_speed_profile(profile);
   }
@@ -980,9 +1031,9 @@ void simgrid_parse()
   for (auto const& [trace, name] : trace_connect_list_link_avail) {
     simgrid_parse_assert(traces_set_list.find(trace) != traces_set_list.end(),
                          "<trace_connect kind=\"LINK_AVAIL\">: Trace " + trace + " undefined.");
-    auto profile = traces_set_list.at(trace);
+    auto* profile = traces_set_list.at(trace);
 
-    auto link = engine->link_by_name_or_null(name);
+    auto* link = engine->link_by_name_or_null(name);
     simgrid_parse_assert(link, "<trace_connect kind=\"LINK_AVAIL\">: Link " + name + " undefined.");
     link->set_state_profile(profile);
   }
@@ -991,9 +1042,9 @@ void simgrid_parse()
   for (auto const& [trace, name] : trace_connect_list_link_bw) {
     simgrid_parse_assert(traces_set_list.find(trace) != traces_set_list.end(),
                          "<trace_connect kind=\"BANDWIDTH\">: Trace " + trace + " undefined.");
-    auto profile = traces_set_list.at(trace);
+    auto* profile = traces_set_list.at(trace);
 
-    auto link = engine->link_by_name_or_null(name);
+    auto* link = engine->link_by_name_or_null(name);
     simgrid_parse_assert(link, "<trace_connect kind=\"BANDWIDTH\">: Link " + name + " undefined.");
     link->set_bandwidth_profile(profile);
   }
@@ -1002,9 +1053,9 @@ void simgrid_parse()
   for (auto const& [trace, name] : trace_connect_list_link_lat) {
     simgrid_parse_assert(traces_set_list.find(trace) != traces_set_list.end(),
                          "<trace_connect kind=\"LATENCY\">: Trace " + trace + " undefined.");
-    auto profile = traces_set_list.at(trace);
+    auto* profile = traces_set_list.at(trace);
 
-    auto link = engine->link_by_name_or_null(name);
+    auto* link = engine->link_by_name_or_null(name);
     simgrid_parse_assert(link, "<trace_connect kind=\"LATENCY\">: Link " + name + " undefined.");
     link->set_latency_profile(profile);
   }
index 888944a..d953e00 100644 (file)
@@ -23,6 +23,7 @@
 #include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/resource/DiskImpl.hpp"
 #include "src/kernel/resource/HostImpl.hpp"
+#include "src/kernel/resource/StandardLinkImpl.hpp"
 #include "src/kernel/resource/profile/Profile.hpp"
 #include "src/kernel/xml/platf.hpp"
 #include "src/kernel/xml/platf_private.hpp"
@@ -40,7 +41,7 @@ void parse_platform_file(const std::string& file)
   simgrid_parse_open(file);
 
   /* Do the actual parsing */
-  simgrid_parse();
+  simgrid_parse(true);
 
   simgrid_parse_close();
 }
@@ -148,7 +149,7 @@ void sg_platf_new_disk(const simgrid::kernel::routing::DiskCreationArgs* disk)
 
 /*************************************************************************************************/
 /** @brief Auxiliary function to create hosts */
-static std::pair<simgrid::kernel::routing::NetPoint*, simgrid::kernel::routing::NetPoint*>
+static simgrid::s4u::Host*
 sg_platf_cluster_create_host(const simgrid::kernel::routing::ClusterCreationArgs* cluster, simgrid::s4u::NetZone* zone,
                              const std::vector<unsigned long>& /*coord*/, unsigned long id)
 {
@@ -159,11 +160,10 @@ sg_platf_cluster_create_host(const simgrid::kernel::routing::ClusterCreationArgs
 
   std::string host_id = cluster->prefix + std::to_string(cluster->radicals[id]) + cluster->suffix;
   XBT_DEBUG("Cluster: creating host=%s speed=%f", host_id.c_str(), cluster->speeds.front());
-  const simgrid::s4u::Host* host = zone->create_host(host_id, cluster->speeds)
-                                       ->set_core_count(cluster->core_amount)
-                                       ->set_properties(cluster->properties)
-                                       ->seal();
-  return std::make_pair(host->get_netpoint(), nullptr);
+  simgrid::s4u::Host* host = zone->create_host(host_id, cluster->speeds)
+                                 ->set_core_count(cluster->core_amount)
+                                 ->set_properties(cluster->properties);
+  return host;
 }
 
 /** @brief Auxiliary function to create loopback links */
@@ -209,7 +209,8 @@ static void sg_platf_new_cluster_hierarchical(const simgrid::kernel::routing::Cl
   using simgrid::kernel::routing::FatTreeZone;
   using simgrid::kernel::routing::TorusZone;
 
-  auto set_host = std::bind(sg_platf_cluster_create_host, cluster, _1, _2, _3);
+  std::function<simgrid::s4u::ClusterCallbacks::ClusterHostCb> set_host =
+    std::bind(sg_platf_cluster_create_host, cluster, _1, _2, _3);
   std::function<simgrid::s4u::ClusterCallbacks::ClusterLinkCb> set_loopback{};
   std::function<simgrid::s4u::ClusterCallbacks::ClusterLinkCb> set_limiter{};
 
@@ -292,8 +293,7 @@ static void sg_platf_new_cluster_flat(simgrid::kernel::routing::ClusterCreationA
                                  ->set_latency(cluster->loopback_lat)
                                  ->seal();
 
-      zone->add_route(host->get_netpoint(), host->get_netpoint(), nullptr, nullptr,
-                      {simgrid::s4u::LinkInRoute(loopback)});
+      zone->add_route(host, host, {simgrid::s4u::LinkInRoute(loopback)});
     }
 
     // add a limiter link (shared link to account for maximal bandwidth of the node)
@@ -321,7 +321,7 @@ static void sg_platf_new_cluster_flat(simgrid::kernel::routing::ClusterCreationA
     if (backbone)
       links.emplace_back(backbone);
 
-    zone->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, links, true);
+    zone->add_route(host, nullptr, links, true);
   }
 
   // Add a router.
@@ -329,8 +329,7 @@ static void sg_platf_new_cluster_flat(simgrid::kernel::routing::ClusterCreationA
   XBT_DEBUG("<router id=\"%s\"/>", cluster->router_id.c_str());
   if (cluster->router_id.empty())
     cluster->router_id = cluster->prefix + cluster->id + "_router" + cluster->suffix;
-  auto* router = zone->create_router(cluster->router_id);
-  zone->add_route(router, nullptr, nullptr, nullptr, {});
+  zone->create_router(cluster->router_id);
 
   simgrid::kernel::routing::on_cluster_creation(*cluster);
 }
@@ -373,12 +372,12 @@ static void sg_platf_build_hostlink(simgrid::kernel::routing::StarZone* zone,
                                     const simgrid::kernel::routing::HostLinkCreationArgs* hostlink,
                                     const simgrid::s4u::Link* backbone)
 {
-  const auto engine = simgrid::s4u::Engine::get_instance();
-  auto netpoint     = engine->host_by_name(hostlink->id)->get_netpoint();
+  const auto* engine = simgrid::s4u::Engine::get_instance();
+  auto* netpoint     = engine->host_by_name(hostlink->id)->get_netpoint();
   xbt_assert(netpoint, "Host '%s' not found!", hostlink->id.c_str());
 
-  const auto linkUp   = engine->link_by_name_or_null(hostlink->link_up);
-  const auto linkDown = engine->link_by_name_or_null(hostlink->link_down);
+  const auto* linkUp   = engine->link_by_name_or_null(hostlink->link_up);
+  const auto* linkDown = engine->link_by_name_or_null(hostlink->link_down);
 
   xbt_assert(linkUp, "Link '%s' not found!", hostlink->link_up.c_str());
   xbt_assert(linkDown, "Link '%s' not found!", hostlink->link_down.c_str());
diff --git a/src/mc/AddressSpace.hpp b/src/mc/AddressSpace.hpp
deleted file mode 100644 (file)
index f817bf0..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_ADDRESS_SPACE_H
-#define SIMGRID_MC_ADDRESS_SPACE_H
-
-#include "src/mc/mc_forward.hpp"
-#include "src/mc/remote/RemotePtr.hpp"
-
-namespace simgrid::mc {
-
-/** Options for read operations
- *
- *  This is a set of flags managed with bitwise operators. Only the
- *  meaningful operations are defined: addition, conversions to/from
- *  integers are not allowed.
- */
-class ReadOptions {
-  std::uint32_t value_ = 0;
-  constexpr explicit ReadOptions(std::uint32_t value) : value_(value) {}
-
-public:
-  constexpr ReadOptions() = default;
-
-  explicit constexpr operator bool() const { return value_ != 0; }
-  constexpr bool operator!() const { return value_ == 0; }
-
-  constexpr ReadOptions operator|(ReadOptions const& that) const
-  {
-    return ReadOptions(value_ | that.value_);
-  }
-  constexpr ReadOptions operator&(ReadOptions const& that) const
-  {
-    return ReadOptions(value_ & that.value_);
-  }
-  constexpr ReadOptions operator^(ReadOptions const& that) const
-  {
-    return ReadOptions(value_ ^ that.value_);
-  }
-  constexpr ReadOptions operator~() const
-  {
-    return ReadOptions(~value_);
-  }
-
-  ReadOptions& operator|=(ReadOptions const& that)
-  {
-    value_ |= that.value_;
-    return *this;
-  }
-  ReadOptions& operator&=(ReadOptions const& that)
-  {
-    value_ &= that.value_;
-    return *this;
-  }
-  ReadOptions& operator^=(ReadOptions const& that)
-  {
-    value_ ^= that.value_;
-    return *this;
-  }
-
-  /** Copy the data to the given buffer */
-  static constexpr ReadOptions none() { return ReadOptions(0); }
-
-  /** Allows to return a pointer to another buffer where the data is
-   *  available instead of copying the data into the buffer
-   */
-  static constexpr ReadOptions lazy() { return ReadOptions(1); }
-};
-
-/** A given state of a given process (abstract base class)
- *
- *  Currently, this might either be:
- *
- *  * the current state of an existing process;
- *
- *  * a snapshot.
- */
-class AddressSpace {
-private:
-  RemoteProcessMemory* remote_process_memory_;
-
-public:
-  explicit AddressSpace(RemoteProcessMemory* process) : remote_process_memory_(process) {}
-  virtual ~AddressSpace() = default;
-
-  /** The process of this address space
-   *
-   *  This is where we can get debug information, memory layout, etc.
-   */
-  simgrid::mc::RemoteProcessMemory* get_remote_process_memory() const { return remote_process_memory_; }
-
-  /** Read data from the address space
-   *
-   *  @param buffer        target buffer for the data
-   *  @param size          number of bytes to read
-   *  @param address       remote source address of the data
-   *  @param options
-   */
-  virtual void* read_bytes(void* buffer, std::size_t size, RemotePtr<void> address,
-                           ReadOptions options = ReadOptions::none()) const = 0;
-
-  /** Read a given data structure from the address space */
-  template <class T> inline void read(T* buffer, RemotePtr<T> ptr) const { this->read_bytes(buffer, sizeof(T), ptr); }
-
-  template <class T> inline void read(Remote<T>& buffer, RemotePtr<T> ptr) const
-  {
-    this->read_bytes(buffer.get_buffer(), sizeof(T), ptr);
-  }
-
-  /** Read a given data structure from the address space
-   *
-   *  This version returns by value.
-   */
-  template <class T> inline Remote<T> read(RemotePtr<T> ptr) const
-  {
-    Remote<T> res;
-    this->read_bytes(&res, sizeof(T), ptr);
-    return res;
-  }
-
-  /** Read a string of known size */
-  std::string read_string(RemotePtr<char> address, std::size_t len) const
-  {
-    std::string res;
-    res.resize(len);
-    this->read_bytes(&res[0], len, address);
-    return res;
-  }
-};
-
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/VisitedState.cpp b/src/mc/VisitedState.cpp
deleted file mode 100644 (file)
index 8e19472..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Copyright (c) 2011-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/VisitedState.hpp"
-#include "src/mc/explo/Exploration.hpp"
-#include "src/mc/mc_config.hpp"
-#include "src/mc/mc_private.hpp"
-
-#include <unistd.h>
-#include <sys/wait.h>
-#include <memory>
-#include <boost/range/algorithm.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, unsigned int actor_count, RemoteApp& remote_app)
-    : heap_bytes_used_(remote_app.get_remote_process_memory()->get_remote_heap_bytes())
-    , actor_count_(actor_count)
-    , num_(state_number)
-{
-  this->system_state_ = std::make_shared<simgrid::mc::Snapshot>(state_number, remote_app.get_page_store(),
-                                                                *remote_app.get_remote_process_memory());
-}
-
-void VisitedStates::prune()
-{
-  while (states_.size() > (std::size_t)_sg_mc_max_visited_states) {
-    XBT_DEBUG("Try to remove visited state (maximum number of stored states reached)");
-    auto min_element = boost::range::min_element(
-        states_, [](const std::unique_ptr<simgrid::mc::VisitedState>& a,
-                    const std::unique_ptr<simgrid::mc::VisitedState>& b) { return a->num_ < b->num_; });
-    xbt_assert(min_element != states_.end());
-    // and drop it:
-    states_.erase(min_element);
-    XBT_DEBUG("Remove visited state (maximum number of stored states reached)");
-  }
-}
-
-/** @brief Checks whether a given state has already been visited by the algorithm. */
-std::unique_ptr<simgrid::mc::VisitedState>
-VisitedStates::addVisitedState(unsigned long state_number, simgrid::mc::State* graph_state, RemoteApp& remote_app)
-{
-  auto new_state =
-      std::make_unique<simgrid::mc::VisitedState>(state_number, graph_state->get_actor_count(), remote_app);
-
-  graph_state->set_system_state(new_state->system_state_);
-  XBT_DEBUG("Snapshot %p of visited state %ld (exploration stack state %ld)", new_state->system_state_.get(),
-            new_state->num_, graph_state->get_num());
-
-  auto [range_begin, range_end] = boost::range::equal_range(states_, new_state.get(), [](auto const& a, auto const& b) {
-    return std::make_pair(a->actor_count_, a->heap_bytes_used_) < std::make_pair(b->actor_count_, b->heap_bytes_used_);
-  });
-
-  for (auto i = range_begin; i != range_end; ++i) {
-    auto& visited_state = *i;
-    if (visited_state->system_state_->equals_to(*new_state->system_state_.get(),
-                                                *remote_app.get_remote_process_memory())) {
-      // The state has been visited:
-
-      std::unique_ptr<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_;
-
-      XBT_DEBUG("State %ld already visited ! (equal to state %ld (state %ld in dot_output))", new_state->num_,
-                old_state->num_, new_state->original_num_);
-
-      /* Replace the old state with the new one (with a bigger num)
-          (when the max number of visited states is reached,  the oldest
-          one is removed according to its number (= with the min number) */
-      XBT_DEBUG("Replace visited state %ld with the new visited state %ld", old_state->num_, new_state->num_);
-
-      visited_state = std::move(new_state);
-      return old_state;
-    }
-  }
-
-  XBT_DEBUG("Insert new visited state %ld (total : %lu)", new_state->num_, (unsigned long)states_.size());
-  states_.insert(range_begin, std::move(new_state));
-  this->prune();
-  return nullptr;
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/VisitedState.hpp b/src/mc/VisitedState.hpp
deleted file mode 100644 (file)
index b2f2694..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_VISITED_STATE_HPP
-#define SIMGRID_MC_VISITED_STATE_HPP
-
-#include "src/mc/api/State.hpp"
-#include "src/mc/sosp/Snapshot.hpp"
-
-#include <cstddef>
-#include <memory>
-
-namespace simgrid::mc {
-
-class XBT_PRIVATE VisitedState {
-public:
-  std::shared_ptr<simgrid::mc::Snapshot> system_state_ = nullptr;
-  std::size_t heap_bytes_used_                         = 0;
-  int actor_count_;
-  long num_;               // unique id of that state in the storage of all stored IDs
-  long original_num_ = -1; // num field of the VisitedState to which I was declared equal to (used for dot_output)
-
-  explicit VisitedState(unsigned long state_number, unsigned int actor_count, RemoteApp& remote_app);
-};
-
-class XBT_PRIVATE VisitedStates {
-  std::vector<std::unique_ptr<simgrid::mc::VisitedState>> states_;
-public:
-  void clear() { states_.clear(); }
-  std::unique_ptr<simgrid::mc::VisitedState> addVisitedState(unsigned long state_number,
-                                                             simgrid::mc::State* graph_state, RemoteApp& remote_app);
-
-private:
-  void prune();
-};
-
-} // namespace simgrid::mc
-
-#endif
index 97cf05a..ed40454 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/kernel/activity/CommImpl.hpp"
 #include "src/mc/remote/RemotePtr.hpp"
 
+#include <algorithm>
 #include <exception>
 #include <vector>
 
@@ -97,7 +98,10 @@ public:
       mark_done();
     return times_considered_++;
   }
+  unsigned int get_max_considered() const { return max_consider_; }
   unsigned int get_times_considered() const { return times_considered_; }
+  unsigned int get_times_not_considered() const { return max_consider_ - times_considered_; }
+  bool has_more_to_consider() const { return get_times_not_considered() > 0; }
   aid_t get_aid() const { return aid_; }
 
   /* returns whether the actor is marked as enabled in the application side */
@@ -114,16 +118,42 @@ public:
   }
   void mark_done() { this->state_ = InterleavingType::done; }
 
-  inline Transition* get_transition(unsigned times_considered)
+  /**
+   * @brief Retrieves the transition that we should consider for execution by
+   * this actor from the State instance with respect to which this ActorState object
+   * is considered
+   */
+  std::shared_ptr<Transition> get_transition() const
+  {
+    // The rationale for this selection is as follows:
+    //
+    // 1. For transitions with only one possibility of execution,
+    // we always wish to select action `0` even if we've
+    // marked the transition already as considered (which
+    // we'll do if we explore a trace following that transition).
+    //
+    // 2. For transitions that can be considered multiple
+    // times, we want to be sure to select the most up-to-date
+    // action. In general, this means selecting that which is
+    // now being considered at this state. If, however, we've
+    // executed the
+    //
+    // The formula satisfies both of the above conditions:
+    //
+    // > std::clamp(times_considered_, 0u, max_consider_ - 1)
+    return get_transition(std::clamp(times_considered_, 0u, max_consider_ - 1));
+  }
+
+  std::shared_ptr<Transition> get_transition(unsigned times_considered) const
   {
     xbt_assert(times_considered < this->pending_transitions_.size(),
                "Actor %ld does not have a state available transition with `times_considered = %u`,\n"
                "yet one was asked for",
                aid_, times_considered);
-    return this->pending_transitions_[times_considered].get();
+    return this->pending_transitions_[times_considered];
   }
 
-  inline void set_transition(std::unique_ptr<Transition> t, unsigned times_considered)
+  void set_transition(std::shared_ptr<Transition> t, unsigned times_considered)
   {
     xbt_assert(times_considered < this->pending_transitions_.size(),
                "Actor %ld does not have a state available transition with `times_considered = %u`, "
@@ -134,7 +164,8 @@ public:
 
   const std::vector<std::shared_ptr<Transition>>& get_enabled_transitions() const
   {
-    return this->pending_transitions_;
+    static const auto no_enabled_transitions = std::vector<std::shared_ptr<Transition>>();
+    return this->is_enabled() ? this->pending_transitions_ : no_enabled_transitions;
   };
 };
 
diff --git a/src/mc/api/ClockVector.cpp b/src/mc/api/ClockVector.cpp
new file mode 100644 (file)
index 0000000..b411bba
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/mc/api/ClockVector.hpp"
+
+namespace simgrid::mc {
+
+ClockVector ClockVector::max(const ClockVector& cv1, const ClockVector& cv2)
+{
+  auto max_vector = ClockVector();
+
+  for (const auto& [aid, value] : cv1.contents)
+    max_vector[aid] = std::max(value, cv2.get(aid).value_or(0));
+
+  for (const auto& [aid, value] : cv2.contents)
+    max_vector[aid] = std::max(value, cv1.get(aid).value_or(0));
+
+  return max_vector;
+}
+
+} // namespace simgrid::mc
\ No newline at end of file
diff --git a/src/mc/api/ClockVector.hpp b/src/mc/api/ClockVector.hpp
new file mode 100644 (file)
index 0000000..32e395f
--- /dev/null
@@ -0,0 +1,130 @@
+/* Copyright (c) 2016-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_CLOCK_VECTOR_HPP
+#define SIMGRID_MC_CLOCK_VECTOR_HPP
+
+#include "simgrid/forward.h"
+
+#include <cstdint>
+#include <initializer_list>
+#include <optional>
+#include <unordered_map>
+
+namespace simgrid::mc {
+
+/**
+ * @brief A multi-dimensional vector used to keep track of
+ * happens-before relation between dependent events in an
+ * execution of DPOR, SDPOR, or ODPOR
+ *
+ * Clock vectors permit actors in a distributed system
+ * to determine whether two events occurred one after the other
+ * but they may not have); i.e. they permit actors to keep track of "time".
+ * A clever observation made in the original DPOR paper is that a
+ * transition-based "happens-before" relation can be computed for
+ * any particular trace `S` using clock vectors, effectively
+ * treating dependency like the passing of a message (the context
+ * in which vector clocks are typically used).
+ *
+ * Support, however, needs to be added to clock vectors since
+ * SimGrid permits the *creation* of new actors during execution.
+ * Since we don't know this size before-hand, we have to allow
+ * clock vectors to behave as if they were "infinitely" large. To
+ * do so, all newly mapped elements, if not assigned a value, are
+ * defaulted to `0`. This corresponds to the value this actor would
+ * have had regardless had its creation been known to have evnetually
+ * occurred: no actions taken by that actor had occurred prior, so
+ * there's no way the clock vector would have been updated. In other
+ * words, when comparing clock vectors of different sizes, it's equivalent
+ * to imagine both of the same size with elements absent in one or
+ * the other implicitly mapped to zero.
+ */
+struct ClockVector final {
+private:
+  std::unordered_map<aid_t, uint32_t> contents;
+
+public:
+  ClockVector()                              = default;
+  ClockVector(const ClockVector&)            = default;
+  ClockVector& operator=(ClockVector const&) = default;
+  ClockVector(ClockVector&&)                 = default;
+  ClockVector(std::initializer_list<std::pair<const aid_t, uint32_t>> init) : contents(std::move(init)) {}
+
+  /**
+   * @brief The number of components in this
+   * clock vector
+   *
+   * A `ClockVector` implicitly maps the id of an actor
+   * it does not contain to a default value of `0`.
+   * Thus, a `ClockVector` is "lazy" in the sense
+   * that new actors are "automatically" mapped
+   * without needing to be explicitly added the clock
+   * vector when the actor is created. This means that
+   * comparison between clock vectors is possible
+   * even as actors become enabled and disabled
+   *
+   * @return uint32_t the number of elements in
+   * the clock vector
+   */
+  size_t size() const { return this->contents.size(); }
+
+  uint32_t& operator[](aid_t aid)
+  {
+    // NOTE: The `operator[]` overload of
+    // unordered_map will create a new key-value
+    // pair if `tid` does not exist and will use
+    // a _default_ value for the value (0 in this case)
+    // which is precisely what we want here
+    return this->contents[aid];
+  }
+
+  /**
+   * @brief Retrieves the value mapped to the given
+   * actor if it is contained in this clock vector
+   */
+  std::optional<uint32_t> get(aid_t aid) const
+  {
+    if (const auto iter = this->contents.find(aid); iter != this->contents.end())
+      return std::optional<uint32_t>{iter->second};
+    return std::nullopt;
+  }
+
+  /**
+   * @brief Computes a clock vector whose components
+   * are larger than the components of both of
+   * the given clock vectors
+   *
+   * The maximum of two clock vectors is definied to
+   * be the clock vector whose components are the maxmimum
+   * of the corresponding components of the arguments.
+   * Since the `ClockVector` class is "lazy", the two
+   * clock vectors given as arguments may not be of the same size.
+   * The resultant clock vector has components as follows:
+   *
+   * 1. For each actor that each clock vector maps, the
+   * resulting clock vector maps that thread to the maxmimum
+   * of the values mapped for the actor in each clock vector
+   *
+   * 2. For each actor that only a single clock vector maps,
+   * the resulting clock vector maps that thread to the
+   * value mapped by the lone clock vector
+   *
+   * The scheme is equivalent to assuming that an unmapped
+   * thread by any one clock vector is implicitly mapped to zero
+   *
+   * @param cv1 the first clock vector
+   * @param cv2  the second clock vector
+   * @return a clock vector whose components are at
+   * least as large as the corresponding components of each clock
+   * vector and whose size is large enough to contain the union
+   * of components of each clock vector
+   */
+  static ClockVector max(const ClockVector& cv1, const ClockVector& cv2);
+};
+
+} // namespace simgrid::mc
+
+#endif
index fc496ad..dc6c7d0 100644 (file)
@@ -30,52 +30,50 @@ XBT_LOG_EXTERNAL_CATEGORY(mc_global);
 
 namespace simgrid::mc {
 
-static char master_socket_name[65] = {};
-static void cleanup_master_socket()
-{
-  if (master_socket_name[0] != '\0')
-    unlink(master_socket_name);
-  master_socket_name[0] = '\0';
-}
+static std::string master_socket_name;
 
-RemoteApp::RemoteApp(const std::vector<char*>& args, bool need_memory_introspection) : app_args_(args)
+RemoteApp::RemoteApp(const std::vector<char*>& args) : app_args_(args)
 {
-  if (need_memory_introspection) {
-    checker_side_     = std::make_unique<simgrid::mc::CheckerSide>(app_args_, need_memory_introspection);
-    initial_snapshot_ = std::make_shared<simgrid::mc::Snapshot>(0, page_store_, *checker_side_->get_remote_memory());
-  } else {
-    master_socket_ = socket(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+  master_socket_ = socket(AF_UNIX,
+#ifdef __APPLE__
+                          SOCK_STREAM, /* Mac OSX does not have AF_UNIX + SOCK_SEQPACKET, even if that's faster */
+#else
+                          SOCK_SEQPACKET,
+#endif
+                          0);
     xbt_assert(master_socket_ != -1, "Cannot create the master socket: %s", strerror(errno));
 
+    master_socket_name = "/tmp/simgrid-mc-" + std::to_string(getpid());
+    master_socket_name.resize(MC_SOCKET_NAME_LEN); // truncate socket name if it's too long
+    master_socket_name.back() = '\0';              // ensure the data are null-terminated
+#ifdef __linux__
+    master_socket_name[0] = '\0'; // abstract socket, automatically removed after close
+#else
+    unlink(master_socket_name.c_str()); // remove possible stale socket before bind
+    atexit([]() {
+      if (not master_socket_name.empty())
+        unlink(master_socket_name.c_str());
+      master_socket_name.clear();
+    });
+#endif
+
     struct sockaddr_un serv_addr = {};
-    serv_addr.sun_family         = AF_LOCAL;
-    snprintf(serv_addr.sun_path, 64, "/tmp/simgrid-mc-%d", getpid());
-    strcpy(master_socket_name, serv_addr.sun_path);
-    auto addr_size = offsetof(struct sockaddr_un, sun_path) + strlen(serv_addr.sun_path);
+    serv_addr.sun_family         = AF_UNIX;
+    master_socket_name.copy(serv_addr.sun_path, MC_SOCKET_NAME_LEN);
 
-    xbt_assert(bind(master_socket_, (struct sockaddr*)&serv_addr, addr_size) >= 0,
-               "Cannot bind the master socket to %s: %s.", serv_addr.sun_path, strerror(errno));
-    atexit(cleanup_master_socket);
+    xbt_assert(bind(master_socket_, (struct sockaddr*)&serv_addr, sizeof serv_addr) >= 0,
+               "Cannot bind the master socket to %c%s: %s.", (serv_addr.sun_path[0] ? serv_addr.sun_path[0] : '@'),
+               serv_addr.sun_path + 1, strerror(errno));
 
     xbt_assert(listen(master_socket_, SOMAXCONN) >= 0, "Cannot listen to the master socket: %s.", strerror(errno));
 
-    application_factory_ = std::make_unique<simgrid::mc::CheckerSide>(app_args_, need_memory_introspection);
-    checker_side_        = application_factory_->clone(master_socket_);
-  }
-}
-
-RemoteApp::~RemoteApp()
-{
-  initial_snapshot_ = nullptr;
-  checker_side_     = nullptr;
+    application_factory_ = std::make_unique<simgrid::mc::CheckerSide>(app_args_);
+    checker_side_        = application_factory_->clone(master_socket_, master_socket_name);
 }
 
 void RemoteApp::restore_initial_state()
 {
-  if (initial_snapshot_ == nullptr) { // No memory introspection
-    checker_side_ = application_factory_->clone(master_socket_);
-  } else
-    initial_snapshot_->restore(*checker_side_->get_remote_memory());
+    checker_side_ = application_factory_->clone(master_socket_, master_socket_name);
 }
 
 unsigned long RemoteApp::get_maxpid() const
@@ -104,6 +102,10 @@ void RemoteApp::get_actors_status(std::map<aid_t, ActorState>& whereto) const
   //                    <----- send ACTORS_STATUS_REPLY_COUNT
   //                    <----- send `N` ACTORS_STATUS_REPLY_TRANSITION (s_mc_message_actors_status_one_t)
   //                    <----- send `M` ACTORS_STATUS_REPLY_SIMCALL (s_mc_message_simcall_probe_one_t)
+  //
+  // Note that we also receive disabled transitions, because the guiding strategies need them to decide what could
+  // unlock actors.
+
   checker_side_->get_channel().send(MessageType::ACTORS_STATUS);
 
   s_mc_message_actors_status_answer_t answer;
@@ -111,7 +113,7 @@ void RemoteApp::get_actors_status(std::map<aid_t, ActorState>& whereto) const
   xbt_assert(answer_size != -1, "Could not receive message");
   xbt_assert(answer_size == sizeof answer, "Broken message (size=%zd; expected %zu)", answer_size, sizeof answer);
   xbt_assert(answer.type == MessageType::ACTORS_STATUS_REPLY_COUNT,
-             "Received unexpected message %s (%i); expected MessageType::ACTORS_STATUS_REPLY_COUNT (%i)",
+             "%d Received unexpected message %s (%i); expected MessageType::ACTORS_STATUS_REPLY_COUNT (%i)", getpid(),
              to_c_str(answer.type), (int)answer.type, (int)MessageType::ACTORS_STATUS_REPLY_COUNT);
 
   // Message sanity checks
@@ -129,7 +131,7 @@ void RemoteApp::get_actors_status(std::map<aid_t, ActorState>& whereto) const
 
   for (const auto& actor : status) {
     std::vector<std::shared_ptr<Transition>> actor_transitions;
-    int n_transitions = actor.enabled ? actor.max_considered : 0;
+    int n_transitions = actor.max_considered;
     for (int times_considered = 0; times_considered < n_transitions; times_considered++) {
       s_mc_message_simcall_probe_one_t probe;
       ssize_t received = checker_side_->get_channel().receive(probe);
@@ -142,7 +144,8 @@ void RemoteApp::get_actors_status(std::map<aid_t, ActorState>& whereto) const
       actor_transitions.emplace_back(deserialize_transition(actor.aid, times_considered, stream));
     }
 
-    XBT_DEBUG("Received %zu transitions for actor %ld", actor_transitions.size(), actor.aid);
+    XBT_DEBUG("Received %zu transitions for actor %ld. The first one is %s", actor_transitions.size(), actor.aid,
+              (actor_transitions.size() > 0 ? actor_transitions[0]->to_string().c_str() : "null"));
     whereto.try_emplace(actor.aid, actor.aid, actor.enabled, actor.max_considered, std::move(actor_transitions));
   }
 }
@@ -167,7 +170,7 @@ void RemoteApp::check_deadlock() const
              "--cfg=model-check/replay:'%s'",
              explo->get_record_trace().to_string().c_str());
     explo->log_state();
-    throw DeadlockError();
+    throw McError(ExitStatus::DEADLOCK);
   }
 }
 
@@ -184,8 +187,6 @@ Transition* RemoteApp::handle_simcall(aid_t aid, int times_considered, bool new_
   m.times_considered_              = times_considered;
   checker_side_->get_channel().send(m);
 
-  if (auto* memory = get_remote_process_memory(); memory != nullptr)
-    memory->clear_cache();
   if (checker_side_->running())
     checker_side_->dispatch_events(); // The app may send messages while processing the transition
 
index 693a220..6954a98 100644 (file)
@@ -10,7 +10,6 @@
 #include "src/mc/api/ActorState.hpp"
 #include "src/mc/remote/CheckerSide.hpp"
 #include "src/mc/remote/RemotePtr.hpp"
-#include "src/mc/sosp/PageStore.hpp"
 
 #include <functional>
 
@@ -27,8 +26,6 @@ namespace simgrid::mc {
 class XBT_PUBLIC RemoteApp {
 private:
   std::unique_ptr<CheckerSide> checker_side_;
-  PageStore page_store_{500};
-  std::shared_ptr<simgrid::mc::Snapshot> initial_snapshot_;
   std::unique_ptr<CheckerSide> application_factory_; // when no meminfo, create checker_side_ by cloning this one
   int master_socket_ = -1;
 
@@ -46,14 +43,12 @@ public:
    *
    *  The code is expected to `exec` the model-checked application.
    */
-  explicit RemoteApp(const std::vector<char*>& args, bool need_memory_introspection);
-
-  ~RemoteApp();
+  explicit RemoteApp(const std::vector<char*>& args);
 
   void restore_initial_state();
   void wait_for_requests();
 
-  /** Ask to the application to check for a deadlock. If so, do an error message and throw a DeadlockError. */
+  /** Ask to the application to check for a deadlock. If so, do an error message and throw a McError(DEADLOCK). */
   void check_deadlock() const;
 
   /** Ask the application to run post-mortem analysis, and maybe to stop ASAP */
@@ -67,11 +62,6 @@ public:
 
   /** Take a transition. A new Transition is created iff the last parameter is true */
   Transition* handle_simcall(aid_t aid, int times_considered, bool new_transition);
-
-  /* Get the memory of the remote process */
-  RemoteProcessMemory* get_remote_process_memory() { return checker_side_->get_remote_memory(); }
-
-  PageStore& get_page_store() { return page_store_; }
 };
 } // namespace simgrid::mc
 
index ce8daed..f537a48 100644 (file)
@@ -4,10 +4,15 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/mc/api/State.hpp"
-#include "src/mc/api/guide/BasicGuide.hpp"
+#include "src/mc/api/strategy/BasicStrategy.hpp"
+#include "src/mc/api/strategy/MaxMatchComm.hpp"
+#include "src/mc/api/strategy/MinMatchComm.hpp"
+#include "src/mc/api/strategy/UniformStrategy.hpp"
 #include "src/mc/explo/Exploration.hpp"
 #include "src/mc/mc_config.hpp"
+#include "xbt/random.hpp"
 
+#include <algorithm>
 #include <boost/range/algorithm.hpp>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_state, mc, "Logging specific to MC states");
@@ -16,60 +21,78 @@ namespace simgrid::mc {
 
 long State::expended_states_ = 0;
 
-State::State(RemoteApp& remote_app) : num_(++expended_states_), guide(std::make_unique<BasicGuide>())
+State::State(RemoteApp& remote_app) : num_(++expended_states_)
 {
-  remote_app.get_actors_status(guide->actors_to_run_);
+  XBT_VERB("Creating a guide for the state");
 
-  /* Stateful model checking */
-  if ((_sg_mc_checkpoint > 0 && (num_ % _sg_mc_checkpoint == 0)) || _sg_mc_termination)
-    system_state_ = std::make_shared<simgrid::mc::Snapshot>(num_, remote_app.get_page_store(),
-                                                            *remote_app.get_remote_process_memory());
+  if (_sg_mc_strategy == "none")
+    strategy_ = std::make_shared<BasicStrategy>();
+  else if (_sg_mc_strategy == "max_match_comm")
+    strategy_ = std::make_shared<MaxMatchComm>();
+  else if (_sg_mc_strategy == "min_match_comm")
+    strategy_ = std::make_shared<MinMatchComm>();
+  else if (_sg_mc_strategy == "uniform") {
+    xbt::random::set_mersenne_seed(_sg_mc_random_seed);
+    strategy_ = std::make_shared<UniformStrategy>();
+  } else
+    THROW_IMPOSSIBLE;
+
+  remote_app.get_actors_status(strategy_->actors_to_run_);
 }
 
-State::State(RemoteApp& remote_app, const State* parent_state)
-    : num_(++expended_states_), parent_state_(parent_state), guide(std::make_unique<BasicGuide>())
+State::State(RemoteApp& remote_app, std::shared_ptr<State> parent_state)
+    : incoming_transition_(parent_state->get_transition_out()), num_(++expended_states_), parent_state_(parent_state)
 {
-  remote_app.get_actors_status(guide->actors_to_run_);
-
-  /* Stateful model checking */
-  if ((_sg_mc_checkpoint > 0 && (num_ % _sg_mc_checkpoint == 0)) || _sg_mc_termination)
-    system_state_ = std::make_shared<simgrid::mc::Snapshot>(num_, remote_app.get_page_store(),
-                                                            *remote_app.get_remote_process_memory());
+  if (_sg_mc_strategy == "none")
+    strategy_ = std::make_shared<BasicStrategy>();
+  else if (_sg_mc_strategy == "max_match_comm")
+    strategy_ = std::make_shared<MaxMatchComm>();
+  else if (_sg_mc_strategy == "min_match_comm")
+    strategy_ = std::make_shared<MinMatchComm>();
+  else if (_sg_mc_strategy == "uniform")
+    strategy_ = std::make_shared<UniformStrategy>();
+  else
+    THROW_IMPOSSIBLE;
+  strategy_->copy_from(parent_state_->strategy_.get());
 
-  /* If we want sleep set reduction, copy the sleep set and eventually removes things from it */
-  if (_sg_mc_sleep_set) {
-    /* For each actor in the previous sleep set, keep it if it is not dependent with current transition.
-     * And if we kept it and the actor is enabled in this state, mark the actor as already done, so that
-     * it is not explored*/
-    for (auto& [aid, transition] : parent_state_->get_sleep_set()) {
-      if (not parent_state_->get_transition()->depends(&transition)) {
-        sleep_set_.try_emplace(aid, transition);
-        if (guide->actors_to_run_.count(aid) != 0) {
-          XBT_DEBUG("Actor %ld will not be explored, for it is in the sleep set", aid);
+  remote_app.get_actors_status(strategy_->actors_to_run_);
 
-          guide->actors_to_run_.at(aid).mark_done();
-        }
-      } else
-        XBT_DEBUG("Transition >>%s<< removed from the sleep set because it was dependent with >>%s<<",
-                  transition.to_string().c_str(), parent_state_->get_transition()->to_string().c_str());
-    }
+  /* Copy the sleep set and eventually removes things from it: */
+  /* For each actor in the previous sleep set, keep it if it is not dependent with current transition.
+   * And if we kept it and the actor is enabled in this state, mark the actor as already done, so that
+   * it is not explored*/
+  for (const auto& [aid, transition] : parent_state_->get_sleep_set()) {
+    if (not incoming_transition_->depends(transition.get())) {
+      sleep_set_.try_emplace(aid, transition);
+      if (strategy_->actors_to_run_.count(aid) != 0) {
+        XBT_DEBUG("Actor %ld will not be explored, for it is in the sleep set", aid);
+        strategy_->actors_to_run_.at(aid).mark_done();
+      }
+    } else
+      XBT_DEBUG("Transition >>%s<< removed from the sleep set because it was dependent with incoming >>%s<<",
+                transition->to_string().c_str(), incoming_transition_->to_string().c_str());
   }
 }
 
 std::size_t State::count_todo() const
 {
-  return boost::range::count_if(this->guide->actors_to_run_, [](auto& pair) { return pair.second.is_todo(); });
+  return boost::range::count_if(this->strategy_->actors_to_run_, [](auto& pair) { return pair.second.is_todo(); });
 }
 
-Transition* State::get_transition() const
+std::size_t State::count_todo_multiples() const
 {
-  return transition_;
+  size_t count = 0;
+  for (auto const& [_, actor] : strategy_->actors_to_run_)
+    if (actor.is_todo())
+      count += actor.get_times_not_considered();
+
+  return count;
 }
 
 aid_t State::next_transition() const
 {
-  XBT_DEBUG("Search for an actor to run. %zu actors to consider", guide->actors_to_run_.size());
-  for (auto const& [aid, actor] : guide->actors_to_run_) {
+  XBT_DEBUG("Search for an actor to run. %zu actors to consider", strategy_->actors_to_run_.size());
+  for (auto const& [aid, actor] : strategy_->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() || actor.is_done()) {
       if (not actor.is_todo())
@@ -89,21 +112,29 @@ aid_t State::next_transition() const
   return -1;
 }
 
-std::pair<aid_t, double> State::next_transition_guided() const
+std::pair<aid_t, int> State::next_transition_guided() const
+{
+  return strategy_->next_transition();
+}
+
+aid_t State::next_odpor_transition() const
 {
-  return guide->next_transition();
+  return wakeup_tree_.get_min_single_process_actor().value_or(-1);
 }
 
 // This should be done in GuidedState, or at least interact with it
-void State::execute_next(aid_t next, RemoteApp& app)
+std::shared_ptr<Transition> State::execute_next(aid_t next, RemoteApp& app)
 {
+  // First, warn the guide, so it knows how to build a proper child state
+  strategy_->execute_next(next, app);
+
   // This actor is ready to be executed. Execution involves three phases:
 
   // 1. Identify the appropriate ActorState to prepare for execution
   // when simcall_handle will be called on it
-  auto& actor_state                        = guide->actors_to_run_.at(next);
+  auto& actor_state                        = strategy_->actors_to_run_.at(next);
   const unsigned times_considered          = actor_state.do_consider();
-  const auto* expected_executed_transition = actor_state.get_transition(times_considered);
+  const auto* expected_executed_transition = actor_state.get_transition(times_considered).get();
   xbt_assert(expected_executed_transition != nullptr,
              "Expected a transition with %u times considered to be noted in actor %ld", times_considered, next);
 
@@ -125,11 +156,144 @@ void State::execute_next(aid_t next, RemoteApp& app)
   //  2. what action actor `next` was able to take given `times_considered`
   // The latter update is important as *more* information is potentially available
   // about a transition AFTER it has executed.
-  transition_ = just_executed;
-
-  auto executed_transition = std::unique_ptr<Transition>(just_executed);
-  actor_state.set_transition(std::move(executed_transition), times_considered);
+  outgoing_transition_ = std::shared_ptr<Transition>(just_executed);
 
+  actor_state.set_transition(outgoing_transition_, times_considered);
   app.wait_for_requests();
+
+  return outgoing_transition_;
+}
+
+std::unordered_set<aid_t> State::get_backtrack_set() const
+{
+  std::unordered_set<aid_t> actors;
+  for (const auto& [aid, state] : get_actors_list()) {
+    if (state.is_todo() || state.is_done()) {
+      actors.insert(aid);
+    }
+  }
+  return actors;
+}
+
+std::unordered_set<aid_t> State::get_sleeping_actors() const
+{
+  std::unordered_set<aid_t> actors;
+  for (const auto& [aid, _] : get_sleep_set()) {
+    actors.insert(aid);
+  }
+  return actors;
+}
+
+std::unordered_set<aid_t> State::get_enabled_actors() const
+{
+  std::unordered_set<aid_t> actors;
+  for (const auto& [aid, state] : get_actors_list()) {
+    if (state.is_enabled()) {
+      actors.insert(aid);
+    }
+  }
+  return actors;
+}
+
+void State::seed_wakeup_tree_if_needed(const odpor::Execution& prior)
+{
+  // TODO: It would be better not to have such a flag.
+  if (has_initialized_wakeup_tree) {
+    XBT_DEBUG("Reached a node with the following initialized WuT:");
+    XBT_DEBUG("\n%s", wakeup_tree_.string_of_whole_tree().c_str());
+
+    return;
+  }
+  // TODO: Note that the next action taken by the actor may be updated
+  // after it executes. But we will have already inserted it into the
+  // tree and decided upon "happens-before" at that point for different
+  // executions :(
+  if (wakeup_tree_.empty()) {
+    // Find an enabled transition to pick
+    for (const auto& [_, actor] : get_actors_list()) {
+      if (actor.is_enabled()) {
+        // For each variant of the transition that is enabled, we want to insert the action into the tree.
+        // This ensures that all variants are searched
+        for (unsigned times = 0; times < actor.get_max_considered(); ++times) {
+          wakeup_tree_.insert(prior, odpor::PartialExecution{actor.get_transition(times)});
+        }
+        break; // Only one actor gets inserted (see pseudocode)
+      }
+    }
+  }
+  has_initialized_wakeup_tree = true;
+}
+
+void State::sprout_tree_from_parent_state()
+{
+
+  XBT_DEBUG("Initializing Wut with parent one:");
+  XBT_DEBUG("\n%s", parent_state_->wakeup_tree_.string_of_whole_tree().c_str());
+
+  xbt_assert(parent_state_ != nullptr, "Attempting to construct a wakeup tree for the root state "
+                                       "(or what appears to be, rather for state without a parent defined)");
+  const auto min_process_node = parent_state_->wakeup_tree_.get_min_single_process_node();
+  xbt_assert(min_process_node.has_value(), "Attempting to construct a subtree for a substate from a "
+                                           "parent with an empty wakeup tree. This indicates either that ODPOR "
+                                           "actor selection in State.cpp is incorrect, or that the code "
+                                           "deciding when to make subtrees in ODPOR is incorrect");
+  if (not(get_transition_in()->aid_ == min_process_node.value()->get_actor() &&
+          get_transition_in()->type_ == min_process_node.value()->get_action()->type_)) {
+    XBT_ERROR("We tried to make a subtree from a parent state who claimed to have executed `%s` on actor %ld "
+              "but whose wakeup tree indicates it should have executed `%s` on actor %ld. This indicates "
+              "that exploration is not following ODPOR. Are you sure you're choosing actors "
+              "to schedule from the wakeup tree? Trace so far:",
+              get_transition_in()->to_string(false).c_str(), get_transition_in()->aid_,
+              min_process_node.value()->get_action()->to_string(false).c_str(), min_process_node.value()->get_actor());
+    for (auto const& elm : Exploration::get_instance()->get_textual_trace())
+      XBT_ERROR("%s", elm.c_str());
+    xbt_abort();
+  }
+  this->wakeup_tree_ = odpor::WakeupTree::make_subtree_rooted_at(min_process_node.value());
+}
+
+void State::remove_subtree_using_current_out_transition()
+{
+  if (auto out_transition = get_transition_out(); out_transition != nullptr) {
+    if (const auto min_process_node = wakeup_tree_.get_min_single_process_node(); min_process_node.has_value()) {
+      xbt_assert((out_transition->aid_ == min_process_node.value()->get_actor()) &&
+                     (out_transition->type_ == min_process_node.value()->get_action()->type_),
+                 "We tried to make a subtree from a parent state who claimed to have executed `%s` "
+                 "but whose wakeup tree indicates it should have executed `%s`. This indicates "
+                 "that exploration is not following ODPOR. Are you sure you're choosing actors "
+                 "to schedule from the wakeup tree?",
+                 out_transition->to_string(false).c_str(),
+                 min_process_node.value()->get_action()->to_string(false).c_str());
+    }
+  }
+  wakeup_tree_.remove_min_single_process_subtree();
+}
+
+void State::remove_subtree_at_aid(const aid_t proc)
+{
+  wakeup_tree_.remove_subtree_at_aid(proc);
+}
+
+odpor::WakeupTree::InsertionResult State::insert_into_wakeup_tree(const odpor::PartialExecution& pe,
+                                                                  const odpor::Execution& E)
+{
+  return this->wakeup_tree_.insert(E, pe);
 }
+
+void State::do_odpor_unwind()
+{
+  if (auto out_transition = get_transition_out(); out_transition != nullptr) {
+    remove_subtree_using_current_out_transition();
+
+    // Only when we've exhausted all variants of the transition which
+    // can be chosen from this state do we finally add the actor to the
+    // sleep set. This ensures that the current logic handling sleep sets
+    // works with ODPOR in the way we intend it to work. There is not a
+    // good way to perform transition equality in SimGrid; instead, we
+    // effectively simply check for the presence of an actor in the sleep set.
+    if (not get_actors_list().at(out_transition->aid_).has_more_to_consider())
+      add_sleep_set(std::move(out_transition));
+  }
+}
+
 } // namespace simgrid::mc
index 1dd6ecc..6603ff0 100644 (file)
@@ -7,9 +7,10 @@
 #define SIMGRID_MC_STATE_HPP
 
 #include "src/mc/api/ActorState.hpp"
+#include "src/mc/api/ClockVector.hpp"
 #include "src/mc/api/RemoteApp.hpp"
-#include "src/mc/api/guide/GuidedState.hpp"
-#include "src/mc/sosp/Snapshot.hpp"
+#include "src/mc/api/strategy/Strategy.hpp"
+#include "src/mc/explo/odpor/WakeupTree.hpp"
 #include "src/mc/transition/Transition.hpp"
 
 namespace simgrid::mc {
@@ -18,76 +19,150 @@ namespace simgrid::mc {
 class XBT_PRIVATE State : public xbt::Extendable<State> {
   static long expended_states_; /* Count total amount of states, for stats */
 
-  /**
-   * @brief An empty transition that leads to this state by default
-   */
-  const std::unique_ptr<Transition> default_transition_ = std::make_unique<Transition>();
+  /** @brief The outgoing transition is the last transition that we took to leave this state.  */
+  std::shared_ptr<Transition> outgoing_transition_ = nullptr;
 
-  /**
-   * @brief The outgoing transition: what was the last transition that
-   * we took to leave this state?
-   *
-   * The owner of the transition is the `ActorState` instance which exists in this state,
-   * or a reference to the internal default transition `Transition()` if no transition has been
-   * set
-   */
-  Transition* transition_ = default_transition_.get();
+  /** @brief The incoming transition is what led to this state, coming from its parent  */
+  std::shared_ptr<Transition> incoming_transition_ = nullptr;
 
   /** Sequential state ID (used for debugging) */
   long num_ = 0;
 
-  /** Snapshot of system state (if needed) */
-  std::shared_ptr<Snapshot> system_state_;
-
   /** Unique parent of this state. Required both for sleep set computation
       and for guided model-checking */
-  const State* parent_state_;
+  std::shared_ptr<State> parent_state_ = nullptr;
 
-  std::unique_ptr<GuidedState> guide;
+  std::shared_ptr<Strategy> strategy_;
 
   /* Sleep sets are composed of the actor and the corresponding transition that made it being added to the sleep
    * set. With this information, it is check whether it should be removed from it or not when exploring a new
    * transition */
-  std::map<aid_t, Transition> sleep_set_;
+  std::map<aid_t, std::shared_ptr<Transition>> sleep_set_;
+
+  /**
+   * The wakeup tree with respect to the execution represented
+   * by the totality of all states before and including this one
+   * and with respect to this state's sleep set
+   */
+  odpor::WakeupTree wakeup_tree_;
+  bool has_initialized_wakeup_tree = false;
 
 public:
   explicit State(RemoteApp& remote_app);
-  explicit State(RemoteApp& remote_app, const State* parent_state);
+  explicit State(RemoteApp& remote_app, std::shared_ptr<State> parent_state);
   /* Returns a positive number if there is another transition to pick, or -1 if not */
   aid_t next_transition() const; // this function should disapear as it is redundant with the next one
 
-  /* Same as next_transition, but choice is now guided, and a double corresponding to the
+  /* Same as next_transition(), but choice is now guided, and an integer corresponding to the
    internal cost of the transition is returned */
-  std::pair<aid_t, double> next_transition_guided() const;
+  std::pair<aid_t, int> next_transition_guided() const;
 
-  /* Explore a new path on the remote app; the parameter 'next' must be the result of a previous call to
-   * next_transition() */
-  void execute_next(aid_t next, RemoteApp& app);
+  /**
+   * Same as next_transition(), but the choice is not based off the ODPOR
+   * wakeup tree associated with this state
+   */
+  aid_t next_odpor_transition() const;
+
+  /**
+   * @brief Explore a new path on the remote app; the parameter 'next' must be the result of a previous call to
+   * next_transition()
+   */
+  std::shared_ptr<Transition> execute_next(aid_t next, RemoteApp& app);
 
   long get_num() const { return num_; }
   std::size_t count_todo() const;
+  std::size_t count_todo_multiples() const;
 
-  void consider_one(aid_t aid) { guide->consider_one(aid); }
-  void consider_best() { guide->consider_best(); }
-  void consider_all() { guide->consider_all(); }
+  /* Marking as TODO some actor in this state:
+   *  + consider_one mark aid actor (and assert it is possible)
+   *  + consider_best ensure one actor is marked by eventually marking the best regarding its guiding method
+   *  + consider_all mark all enabled actor that are not done yet */
+  void consider_one(aid_t aid) const { strategy_->consider_one(aid); }
+  void consider_best() const { strategy_->consider_best(); }
+  unsigned long consider_all() const { return strategy_->consider_all(); }
 
-  bool is_actor_done(aid_t actor) const { return guide->actors_to_run_.at(actor).is_done(); }
-  Transition* get_transition() const;
-  void set_transition(Transition* t) { transition_ = t; }
-  std::map<aid_t, ActorState> const& get_actors_list() const { return guide->actors_to_run_; }
+  bool is_actor_done(aid_t actor) const { return strategy_->actors_to_run_.at(actor).is_done(); }
+  std::shared_ptr<Transition> get_transition_out() const { return outgoing_transition_; }
+  std::shared_ptr<Transition> get_transition_in() const { return incoming_transition_; }
+  std::shared_ptr<State> get_parent_state() const { return parent_state_; }
 
-  unsigned long get_actor_count() const { return guide->actors_to_run_.size(); }
-  bool is_actor_enabled(aid_t actor) { return guide->actors_to_run_.at(actor).is_enabled(); }
+  std::map<aid_t, ActorState> const& get_actors_list() const { return strategy_->actors_to_run_; }
 
-  Snapshot* get_system_state() const { return system_state_.get(); }
-  void set_system_state(std::shared_ptr<Snapshot> state) { system_state_ = std::move(state); }
+  unsigned long get_actor_count() const { return strategy_->actors_to_run_.size(); }
+  bool is_actor_enabled(aid_t actor) const { return strategy_->actors_to_run_.at(actor).is_enabled(); }
 
-  std::map<aid_t, Transition> const& get_sleep_set() const { return sleep_set_; }
-  void add_sleep_set(const Transition* t)
+  /**
+   * @brief Computes the backtrack set for this state
+   * according to its definition in SimGrid.
+   *
+   * The backtrack set as it appears in DPOR, SDPOR, and ODPOR
+   * in SimGrid consists of those actors marked as `todo`
+   * (i.e. those that have yet to be explored) as well as those
+   * marked `done` (i.e. those that have already been explored)
+   * since the pseudocode in none of the above algorithms explicitly
+   * removes elements from the backtrack set. DPOR makes use
+   * explicitly of the `done` set, but we again note that the
+   * backtrack set still contains processes added to the done set.
+   */
+  std::unordered_set<aid_t> get_backtrack_set() const;
+  std::unordered_set<aid_t> get_sleeping_actors() const;
+  std::unordered_set<aid_t> get_enabled_actors() const;
+  std::map<aid_t, std::shared_ptr<Transition>> const& get_sleep_set() const { return sleep_set_; }
+  void add_sleep_set(std::shared_ptr<Transition> t) { sleep_set_.insert_or_assign(t->aid_, std::move(t)); }
+  bool is_actor_sleeping(aid_t actor) const
   {
-    sleep_set_.insert_or_assign(t->aid_, Transition(t->type_, t->aid_, t->times_considered_));
+    return std::find_if(sleep_set_.begin(), sleep_set_.end(), [=](const auto& pair) { return pair.first == actor; }) !=
+           sleep_set_.end();
   }
 
+  /**
+   * @brief Inserts an arbitrary enabled actor into the wakeup tree
+   * associated with this state, if such an actor exists and if
+   * the wakeup tree is already not empty
+   *
+   * @param prior The sequence of steps leading up to this state
+   * with respec to which the tree associated with this state should be
+   * a wakeup tree (wakeup trees are defined relative to an execution)
+   *
+   * @invariant: You should not manipulate a wakeup tree with respect
+   * to more than one execution; doing so will almost certainly lead to
+   * unexpected results as wakeup trees are defined relative to a single
+   * execution
+   */
+  void seed_wakeup_tree_if_needed(const odpor::Execution& prior);
+
+  /**
+   * @brief Initializes the wakeup_tree_ instance by taking the subtree rooted at the
+   * single-process node `N` running actor `p := "actor taken by parent to form this state"`
+   * of the *parent's* wakeup tree
+   */
+  void sprout_tree_from_parent_state();
+
+  /**
+   * @brief Removes the subtree rooted at the single-process node
+   * `N` running actor `p` of this state's wakeup tree
+   */
+  void remove_subtree_using_current_out_transition();
+  void remove_subtree_at_aid(aid_t proc);
+  bool has_empty_tree() const { return this->wakeup_tree_.empty(); }
+  std::string string_of_wut() const { return this->wakeup_tree_.string_of_whole_tree(); }
+
+  /**
+   * @brief
+   */
+  odpor::WakeupTree::InsertionResult insert_into_wakeup_tree(const odpor::PartialExecution&, const odpor::Execution&);
+
+  /** @brief Prepares the state for re-exploration following
+   * another after having followed ODPOR from this state with
+   * the current out transition
+   *
+   * After ODPOR has completed searching a maximal trace, it
+   * finds the first point in the execution with a nonempty wakeup
+   * tree. This method corresponds to lines 20 and 21 in the ODPOR
+   * pseudocode
+   */
+  void do_odpor_unwind();
+
   /* Returns the total amount of states created so far (for statistics) */
   static long get_expanded_states() { return expended_states_; }
 };
diff --git a/src/mc/api/guide/BasicGuide.hpp b/src/mc/api/guide/BasicGuide.hpp
deleted file mode 100644 (file)
index c550675..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_BASICGUIDE_HPP
-#define SIMGRID_MC_BASICGUIDE_HPP
-
-namespace simgrid::mc {
-
-/** Basic MC guiding class which corresponds to no guide at all (random choice) */
-// Not Yet fully implemented
-class BasicGuide : public GuidedState {
-public:
-  std::pair<aid_t, double> next_transition() const override
-  {
-    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() || actor.is_done()) {
-        continue;
-      }
-
-      return std::make_pair(aid, 1.0);
-    }
-    return std::make_pair(-1, 0.0);
-  }
-  void execute_next(aid_t aid, RemoteApp& app) override { return; }
-
-  void consider_best() override
-  {
-    for (auto& [_, actor] : actors_to_run_) {
-      if (actor.is_todo())
-        return;
-      if (actor.is_enabled() and not actor.is_done()) {
-        actor.mark_todo();
-        return;
-      }
-    }
-  }
-};
-
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/api/guide/GuidedState.hpp b/src/mc/api/guide/GuidedState.hpp
deleted file mode 100644 (file)
index 82ee915..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "xbt/asserts.h"
-
-#ifndef SIMGRID_MC_GUIDEDSTATE_HPP
-#define SIMGRID_MC_GUIDEDSTATE_HPP
-
-namespace simgrid::mc {
-
-class GuidedState {
-protected:
-  /** 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_;
-
-public:
-  virtual ~GuidedState()                                   = default;
-  virtual std::pair<aid_t, double> next_transition() const = 0;
-  virtual void execute_next(aid_t aid, RemoteApp& app)     = 0;
-  virtual void consider_best()                             = 0;
-
-  // Mark the first enabled and not yet done transition as todo
-  // If there's already a transition marked as todo, does nothing
-  void consider_one(aid_t aid)
-  {
-    xbt_assert(actors_to_run_.at(aid).is_enabled() and not actors_to_run_.at(aid).is_done(),
-               "Tried to mark as TODO actor %ld but it is either not enabled or already done", aid);
-    actors_to_run_.at(aid).mark_todo();
-  }
-  // Matk as todo all actors enabled that are not done yet
-  void consider_all()
-  {
-    for (auto& [_, actor] : actors_to_run_)
-      if (actor.is_enabled() and not actor.is_done())
-        actor.mark_todo();
-  }
-
-  friend class State;
-};
-
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/api/strategy/BasicStrategy.hpp b/src/mc/api/strategy/BasicStrategy.hpp
new file mode 100644 (file)
index 0000000..ca44509
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_BASICSTRATEGY_HPP
+#define SIMGRID_MC_BASICSTRATEGY_HPP
+
+#include "Strategy.hpp"
+#include "src/mc/explo/Exploration.hpp"
+
+XBT_LOG_EXTERNAL_CATEGORY(mc_dfs);
+
+namespace simgrid::mc {
+
+/** Basic MC guiding class which corresponds to no guide. When asked for different states
+ *  it will follow a depth first search politics to minize the number of opened states. */
+class BasicStrategy : public Strategy {
+  int depth_ = _sg_mc_max_depth; // Arbitrary starting point. next_transition must return a positive value to work with
+                                 // threshold in DFSExplorer
+
+public:
+  void copy_from(const Strategy* strategy) override
+  {
+    const auto* cast_strategy = dynamic_cast<BasicStrategy const*>(strategy);
+    xbt_assert(cast_strategy != nullptr);
+    depth_ = cast_strategy->depth_ - 1;
+    if (depth_ <= 0) {
+      XBT_CERROR(mc_dfs,
+                 "The exploration reached a depth greater than %d. Change the depth limit with "
+                 "--cfg=model-check/max-depth. Here are the 100 first trace elements",
+                 _sg_mc_max_depth.get());
+      auto trace = Exploration::get_instance()->get_textual_trace(100);
+      for (auto const& elm : trace)
+        XBT_CERROR(mc_dfs, "  %s", elm.c_str());
+      xbt_die("Aborting now.");
+    }
+  }
+  BasicStrategy()                     = default;
+  ~BasicStrategy() override           = default;
+
+  std::pair<aid_t, int> best_transition(bool must_be_todo) const override {
+    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() && must_be_todo) || not actor.is_enabled() || actor.is_done())
+        continue;
+
+      return std::make_pair(aid, depth_);
+    }
+    return std::make_pair(-1, depth_);
+  }
+
+  void execute_next(aid_t aid, RemoteApp& app) override { return; }
+};
+
+} // namespace simgrid::mc
+
+#endif
diff --git a/src/mc/api/strategy/MaxMatchComm.hpp b/src/mc/api/strategy/MaxMatchComm.hpp
new file mode 100644 (file)
index 0000000..77dadd1
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_WAITSTRATEGY_HPP
+#define SIMGRID_MC_WAITSTRATEGY_HPP
+
+#include "src/mc/transition/TransitionComm.hpp"
+
+namespace simgrid::mc {
+
+/** Wait MC guiding class that aims at minimizing the number of in-fly communication.
+ *  When possible, it will try to match corresponding in-fly communications. */
+class MaxMatchComm : public Strategy {
+  /** Stores for each mailbox what kind of transition is waiting on it.
+   *  Negative number means that much recv are waiting on that mailbox, while
+   *  a positiv number means that much send are waiting there. */
+  std::map<unsigned, int> mailbox_;
+    int value_of_state_ = 0; // used to valuate the state. Corresponds to the number of in-fly communications
+    // The two next values are used to save the operation we execute so the next strategy can update its field accordingly
+  Transition::Type last_transition_; 
+  unsigned last_mailbox_ = 0;
+
+public:
+  void copy_from(const Strategy* strategy) override
+  {
+    const auto* cast_strategy = dynamic_cast<MaxMatchComm const*>(strategy);
+    xbt_assert(cast_strategy != nullptr);
+    for (auto& [id, val] : cast_strategy->mailbox_)
+      mailbox_[id] = val;
+    if (cast_strategy->last_transition_ == Transition::Type::COMM_ASYNC_RECV)
+      mailbox_[cast_strategy->last_mailbox_]--;
+    if (cast_strategy->last_transition_ == Transition::Type::COMM_ASYNC_SEND)
+      mailbox_[cast_strategy->last_mailbox_]++;
+
+    for (auto const& [_, val] : mailbox_)
+       value_of_state_ += std::abs(val);
+  }
+  MaxMatchComm()                     = default;
+  ~MaxMatchComm() override           = default;
+
+  std::pair<aid_t, int> best_transition(bool must_be_todo) const override
+  {
+    std::pair<aid_t, int> min_found = std::make_pair(-1, value_of_state_ + 2);
+    for (auto const& [aid, actor] : actors_to_run_) {
+       if ((not actor.is_todo() && must_be_todo) || not actor.is_enabled() || actor.is_done())
+           continue;
+
+      int aid_value = value_of_state_;
+      const Transition* transition = actor.get_transition(actor.get_times_considered()).get();
+
+      if (auto const* cast_recv = dynamic_cast<CommRecvTransition const*>(transition)) {
+            if (mailbox_.count(cast_recv->get_mailbox()) > 0 && mailbox_.at(cast_recv->get_mailbox()) > 0) {
+              aid_value--; // This means we have waiting recv corresponding to this recv
+            } else {
+              aid_value++;
+            }
+      }
+
+      if (auto const* cast_send = dynamic_cast<CommSendTransition const*>(transition)) {
+            if (mailbox_.count(cast_send->get_mailbox()) > 0 && mailbox_.at(cast_send->get_mailbox()) < 0) {
+              aid_value--; // This means we have waiting recv corresponding to this send
+            } else {
+              aid_value++;
+            }
+      }
+
+      if (aid_value < min_found.second)
+         min_found = std::make_pair(aid, aid_value);
+    }
+    return min_found;
+  }
+
+  void execute_next(aid_t aid, RemoteApp& app) override
+  {
+    const Transition* transition = actors_to_run_.at(aid).get_transition(actors_to_run_.at(aid).get_times_considered()).get();
+    last_transition_             = transition->type_;
+
+    if (auto const* cast_recv = dynamic_cast<CommRecvTransition const*>(transition))
+      last_mailbox_ = cast_recv->get_mailbox();
+
+    if (auto const* cast_send = dynamic_cast<CommSendTransition const*>(transition))
+      last_mailbox_ = cast_send->get_mailbox();
+  }
+};
+
+} // namespace simgrid::mc
+
+#endif
diff --git a/src/mc/api/strategy/MinMatchComm.hpp b/src/mc/api/strategy/MinMatchComm.hpp
new file mode 100644 (file)
index 0000000..7d06c9d
--- /dev/null
@@ -0,0 +1,94 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_MINWAITTAKEN_HPP
+#define SIMGRID_MC_MINWAITTAKEN_HPP
+
+#include "src/mc/transition/TransitionComm.hpp"
+
+namespace simgrid::mc {
+
+/** Wait MC guiding class that aims at maximizing the number of in-fly communication.
+ *  When possible, it will try not to match communications. */
+class MinMatchComm : public Strategy {
+  /** Stores for each mailbox what kind of transition is waiting on it.
+   *  Negative number means that much recv are waiting on that mailbox, while
+   *  a positiv number means that much send are waiting there. */
+  std::map<unsigned, int> mailbox_;
+  /**  Used to valuate the state. Corresponds to a maximum minus the number of in-fly communications.
+   *   Maximum should be set in order not to reach 0.*/
+  int value_of_state_ = _sg_mc_max_depth;
+    
+    // The two next values are used to save the operation we execute so the next strategy can update its field accordingly
+  Transition::Type last_transition_;
+  unsigned last_mailbox_ = 0;
+
+public:
+  void copy_from(const Strategy* strategy) override
+  {
+    const auto* cast_strategy = dynamic_cast<MinMatchComm const*>(strategy);
+    xbt_assert(cast_strategy != nullptr);
+    for (auto& [id, val] : cast_strategy->mailbox_)
+      mailbox_[id] = val;
+    if (cast_strategy->last_transition_ == Transition::Type::COMM_ASYNC_RECV)
+      mailbox_[cast_strategy->last_mailbox_]--;
+    if (cast_strategy->last_transition_ == Transition::Type::COMM_ASYNC_SEND)
+      mailbox_[cast_strategy->last_mailbox_]++;
+
+    for (auto const& [_, val] : mailbox_)
+      value_of_state_ -= std::abs(val);
+    xbt_assert(value_of_state_ > 0, "MinMatchComm value shouldn't reach 0");
+  }
+    MinMatchComm()                     = default;
+  ~MinMatchComm() override           = default;
+
+ std::pair<aid_t, int> best_transition(bool must_be_todo) const override
+  {
+    std::pair<aid_t, int> min_found = std::make_pair(-1, value_of_state_ + 2);
+    for (auto const& [aid, actor] : actors_to_run_) {
+       if ((not actor.is_todo() && must_be_todo) || not actor.is_enabled() || actor.is_done())
+           continue;
+
+      int aid_value = value_of_state_;
+      const Transition* transition = actor.get_transition(actor.get_times_considered()).get();
+
+      if (auto const* cast_recv = dynamic_cast<CommRecvTransition const*>(transition)) {
+            if ((mailbox_.count(cast_recv->get_mailbox()) > 0 && mailbox_.at(cast_recv->get_mailbox()) <= 0) ||
+                mailbox_.count(cast_recv->get_mailbox()) == 0)
+              aid_value--; // This means we don't have waiting recv corresponding to this recv
+            else
+              aid_value++;
+      }
+      if (auto const* cast_send = dynamic_cast<CommSendTransition const*>(transition)) {
+            if ((mailbox_.count(cast_send->get_mailbox()) > 0 && mailbox_.at(cast_send->get_mailbox()) >= 0) ||
+                mailbox_.count(cast_send->get_mailbox()) == 0)
+              aid_value--;
+            else
+              aid_value++;
+      }
+
+      if (aid_value < min_found.second)
+         min_found = std::make_pair(aid, aid_value);
+    }
+    return min_found;
+  }
+
+    
+  void execute_next(aid_t aid, RemoteApp& app) override
+  {
+      const Transition* transition = actors_to_run_.at(aid).get_transition(actors_to_run_.at(aid).get_times_considered()).get();
+    last_transition_             = transition->type_;
+
+    if (auto const* cast_recv = dynamic_cast<CommRecvTransition const*>(transition))
+      last_mailbox_ = cast_recv->get_mailbox();
+
+    if (auto const* cast_send = dynamic_cast<CommSendTransition const*>(transition))
+      last_mailbox_ = cast_send->get_mailbox();
+  }
+};
+
+} // namespace simgrid::mc
+
+#endif
diff --git a/src/mc/api/strategy/Strategy.hpp b/src/mc/api/strategy/Strategy.hpp
new file mode 100644 (file)
index 0000000..60e21f5
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_STRATEGY_HPP
+#define SIMGRID_MC_STRATEGY_HPP
+
+#include "simgrid/forward.h"
+#include "src/mc/api/RemoteApp.hpp"
+#include "src/mc/mc_config.hpp"
+#include "xbt/asserts.h"
+#include <map>
+#include <utility>
+
+namespace simgrid::mc {
+
+class Strategy {
+protected:
+  /** State's exploration status by actor. All actors should be present, eventually disabled for now. */
+  std::map<aid_t, ActorState> actors_to_run_;
+
+public:
+  /** Strategies can have values shared from parent to children state.
+   *  This method should copy all value the strategy needs from its parent. */
+  virtual void copy_from(const Strategy*) = 0;
+    
+  Strategy()                              = default;
+  virtual ~Strategy()                     = default;
+
+  /** Returns the best transition among according to the strategy for this state.
+   *  The strategy should consider only enabled transition not already done.
+   *  Furthermore, if must_be_todo is set to true, only transitions marked as todo
+   *  should be considered. */
+  virtual std::pair<aid_t, int> best_transition(bool must_be_todo) const = 0;
+
+  /** Returns the best transition among those that should be interleaved. */
+  std::pair<aid_t, int> next_transition() const { return best_transition(true); }
+
+  /** Allows for the strategy to update its fields knowing that the actor aid will
+   *  be executed and a children strategy will then be created. */  
+  virtual void execute_next(aid_t aid, RemoteApp& app)  = 0;
+
+  /** Ensure at least one transition is marked as todo among the enabled ones not done.
+   *  If required, it marks as todo the best transition according to the strategy. */
+  void consider_best() {
+    if (std::any_of(begin(actors_to_run_), end(actors_to_run_),
+                    [](const auto& actor) { return actor.second.is_todo(); }))
+      return;
+    aid_t best_aid = best_transition(false).first;
+    if (best_aid != -1)
+       actors_to_run_.at(best_aid).mark_todo();
+  }
+
+  // Mark aid as todo. If it makes no sense, ie. if it is already done or not enabled,
+  // else raise an error
+  void consider_one(aid_t aid)
+  {
+    xbt_assert(actors_to_run_.at(aid).is_enabled() && not actors_to_run_.at(aid).is_done(),
+               "Tried to mark as TODO actor %ld but it is either not enabled or already done", aid);
+    actors_to_run_.at(aid).mark_todo();
+  }
+  // Mark as todo all actors enabled that are not done yet and return the number
+  // of marked actors
+  unsigned long consider_all()
+  {
+    unsigned long count = 0;
+    for (auto& [_, actor] : actors_to_run_)
+        if (actor.is_enabled() && not actor.is_done()) {
+          actor.mark_todo();
+          count++;
+        }
+    return count;
+  }
+
+  friend class State;
+};
+
+} // namespace simgrid::mc
+
+#endif
diff --git a/src/mc/api/strategy/UniformStrategy.hpp b/src/mc/api/strategy/UniformStrategy.hpp
new file mode 100644 (file)
index 0000000..472c571
--- /dev/null
@@ -0,0 +1,67 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_UNIFORMSTRATEGY_HPP
+#define SIMGRID_MC_UNIFORMSTRATEGY_HPP
+
+#include "src/mc/transition/Transition.hpp"
+#include "xbt/random.hpp"
+
+namespace simgrid::mc {
+
+/** Guiding strategy that valuate states randomly */
+class UniformStrategy : public Strategy {
+  static constexpr int MAX_RAND = 100000;
+
+  std::map<aid_t, int> valuation;
+
+public:
+  UniformStrategy()
+  {
+    for (long aid = 0; aid < 10; aid++)
+      valuation[aid] = xbt::random::uniform_int(0, MAX_RAND);
+  }
+  void copy_from(const Strategy* strategy) override
+  {
+    for (auto const& [aid, _] : actors_to_run_)
+      valuation[aid] = xbt::random::uniform_int(0, MAX_RAND);
+  }
+
+  std::pair<aid_t, int> best_transition(bool must_be_todo) const override
+  {
+    int possibilities = 0;
+
+    // Consider only valid actors
+    for (auto const& [aid, actor] : actors_to_run_) {
+      if ((actor.is_todo() || not must_be_todo) && (not actor.is_done()) && actor.is_enabled())
+        possibilities++;
+    }
+
+    int chosen;
+    if (possibilities == 0)
+      return std::make_pair(-1, 0);
+    if (possibilities == 1)
+      chosen = 0;
+    else
+       chosen = xbt::random::uniform_int(0, possibilities-1);
+
+    for (auto const& [aid, actor] : actors_to_run_) {
+      if (((not actor.is_todo()) && must_be_todo) || actor.is_done() || (not actor.is_enabled()))
+        continue;
+      if (chosen == 0) {
+        return std::make_pair(aid, valuation.at(aid));
+      }
+      chosen--;
+    }
+
+    return std::make_pair(-1, 0);
+  }
+
+  void execute_next(aid_t aid, RemoteApp& app) override {}
+};
+
+} // namespace simgrid::mc
+
+#endif
diff --git a/src/mc/compare.cpp b/src/mc/compare.cpp
deleted file mode 100644 (file)
index 9fe8072..0000000
+++ /dev/null
@@ -1,1300 +0,0 @@
-/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/** \file compare.cpp Memory snapshotting and comparison                    */
-
-#include "src/mc/mc_config.hpp"
-#include "src/mc/mc_private.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-#include "src/mc/sosp/Snapshot.hpp"
-#include "xbt/ex.h"
-
-#include <algorithm>
-
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_compare, mc, "Logging specific to mc_compare in mc");
-
-namespace simgrid::mc {
-
-/*********************************** Heap comparison ***********************************/
-/***************************************************************************************/
-
-class HeapLocation {
-public:
-  int block_    = 0;
-  int fragment_ = 0;
-
-  HeapLocation() = default;
-  explicit HeapLocation(int block, int fragment = 0) : block_(block), fragment_(fragment) {}
-
-  bool operator==(HeapLocation const& that) const
-  {
-    return block_ == that.block_ && fragment_ == that.fragment_;
-  }
-  bool operator<(HeapLocation const& that) const
-  {
-    return std::make_pair(block_, fragment_) < std::make_pair(that.block_, that.fragment_);
-  }
-};
-
-using HeapLocationPair  = std::array<HeapLocation, 2>;
-using HeapLocationPairs = std::set<HeapLocationPair>;
-
-class HeapArea : public HeapLocation {
-public:
-  bool valid_ = false;
-  HeapArea() = default;
-  explicit HeapArea(int block) : valid_(true) { block_ = block; }
-  HeapArea(int block, int fragment) : valid_(true)
-  {
-    block_    = block;
-    fragment_ = fragment;
-  }
-};
-
-class ProcessComparisonState {
-public:
-  const std::vector<IgnoredHeapRegion>* to_ignore = nullptr;
-  std::vector<HeapArea> equals_to;
-  std::vector<Type*> types;
-  std::size_t heapsize = 0;
-
-  void initHeapInformation(const s_xbt_mheap_t* heap, const std::vector<IgnoredHeapRegion>& i);
-};
-
-class StateComparator {
-public:
-  s_xbt_mheap_t std_heap_copy;
-  std::size_t heaplimit;
-  std::array<ProcessComparisonState, 2> processStates;
-
-  std::unordered_set<std::pair<const void*, const void*>, simgrid::xbt::hash<std::pair<const void*, const void*>>>
-      compared_pointers;
-
-  void clear()
-  {
-    compared_pointers.clear();
-  }
-
-  int initHeapInformation(RemoteProcessMemory& appli, const s_xbt_mheap_t* heap1, const s_xbt_mheap_t* heap2,
-                          const std::vector<IgnoredHeapRegion>& i1, const std::vector<IgnoredHeapRegion>& i2);
-
-  template <int rank> HeapArea& equals_to_(std::size_t i, std::size_t j)
-  {
-    return processStates[rank - 1].equals_to[MAX_FRAGMENT_PER_BLOCK * i + j];
-  }
-  template <int rank> Type*& types_(std::size_t i, std::size_t j)
-  {
-    return processStates[rank - 1].types[MAX_FRAGMENT_PER_BLOCK * i + j];
-  }
-
-  template <int rank> HeapArea const& equals_to_(std::size_t i, std::size_t j) const
-  {
-    return processStates[rank - 1].equals_to[MAX_FRAGMENT_PER_BLOCK * i + j];
-  }
-  template <int rank> Type* const& types_(std::size_t i, std::size_t j) const
-  {
-    return processStates[rank - 1].types[MAX_FRAGMENT_PER_BLOCK * i + j];
-  }
-
-  /** Check whether two blocks are known to be matching
-   *
-   *  @param b1     Block of state 1
-   *  @param b2     Block of state 2
-   *  @return       if the blocks are known to be matching
-   */
-  bool blocksEqual(int b1, int b2) const
-  {
-    return this->equals_to_<1>(b1, 0).block_ == b2 && this->equals_to_<2>(b2, 0).block_ == b1;
-  }
-
-  /** Check whether two fragments are known to be matching
-   *
-   *  @param b1     Block of state 1
-   *  @param f1     Fragment of state 1
-   *  @param b2     Block of state 2
-   *  @param f2     Fragment of state 2
-   *  @return       if the fragments are known to be matching
-   */
-  int fragmentsEqual(int b1, int f1, int b2, int f2) const
-  {
-    return this->equals_to_<1>(b1, f1).block_ == b2 && this->equals_to_<1>(b1, f1).fragment_ == f2 &&
-           this->equals_to_<2>(b2, f2).block_ == b1 && this->equals_to_<2>(b2, f2).fragment_ == f1;
-  }
-
-  void match_equals(const HeapLocationPairs* list);
-};
-
-} // namespace simgrid::mc
-
-/************************************************************************************/
-
-static ssize_t heap_comparison_ignore_size(const std::vector<simgrid::mc::IgnoredHeapRegion>* ignore_list,
-                                           const void* address)
-{
-  auto pos = std::lower_bound(ignore_list->begin(), ignore_list->end(), address,
-                              [](auto const& reg, auto const* addr) { return reg.address < addr; });
-  return (pos != ignore_list->end() && pos->address == address) ? pos->size : -1;
-}
-
-static bool is_stack(const simgrid::mc::RemoteProcessMemory& process, const void* address)
-{
-  auto const& stack_areas = process.stack_areas();
-  return std::any_of(stack_areas.begin(), stack_areas.end(),
-                     [address](auto const& stack) { return stack.address == address; });
-}
-
-// TODO, this should depend on the snapshot?
-static bool is_block_stack(const simgrid::mc::RemoteProcessMemory& process, int block)
-{
-  auto const& stack_areas = process.stack_areas();
-  return std::any_of(stack_areas.begin(), stack_areas.end(),
-                     [block](auto const& stack) { return stack.block == block; });
-}
-
-namespace simgrid::mc {
-
-void StateComparator::match_equals(const HeapLocationPairs* list)
-{
-  for (auto const& pair : *list) {
-    if (pair[0].fragment_ != -1) {
-      this->equals_to_<1>(pair[0].block_, pair[0].fragment_) = HeapArea(pair[1].block_, pair[1].fragment_);
-      this->equals_to_<2>(pair[1].block_, pair[1].fragment_) = HeapArea(pair[0].block_, pair[0].fragment_);
-    } else {
-      this->equals_to_<1>(pair[0].block_, 0) = HeapArea(pair[1].block_, pair[1].fragment_);
-      this->equals_to_<2>(pair[1].block_, 0) = HeapArea(pair[0].block_, pair[0].fragment_);
-    }
-  }
-}
-
-void ProcessComparisonState::initHeapInformation(const s_xbt_mheap_t* heap, const std::vector<IgnoredHeapRegion>& i)
-{
-  auto heaplimit  = heap->heaplimit;
-  this->heapsize  = heap->heapsize;
-  this->to_ignore = &i;
-  this->equals_to.assign(heaplimit * MAX_FRAGMENT_PER_BLOCK, HeapArea());
-  this->types.assign(heaplimit * MAX_FRAGMENT_PER_BLOCK, nullptr);
-}
-
-int StateComparator::initHeapInformation(simgrid::mc::RemoteProcessMemory& memory, const s_xbt_mheap_t* heap1,
-                                         const s_xbt_mheap_t* heap2, const std::vector<IgnoredHeapRegion>& i1,
-                                         const std::vector<IgnoredHeapRegion>& i2)
-{
-  if ((heap1->heaplimit != heap2->heaplimit) || (heap1->heapsize != heap2->heapsize))
-    return -1;
-  this->heaplimit     = heap1->heaplimit;
-  this->std_heap_copy = *memory.get_heap();
-  this->processStates[0].initHeapInformation(heap1, i1);
-  this->processStates[1].initHeapInformation(heap2, i2);
-  return 0;
-}
-
-// TODO, have a robust way to find it in O(1)
-static inline Region* MC_get_heap_region(const Snapshot& snapshot)
-{
-  for (auto const& region : snapshot.snapshot_regions_)
-    if (region->region_type() == RegionType::Heap)
-      return region.get();
-  xbt_die("No heap region");
-}
-
-static bool heap_area_differ(const RemoteProcessMemory& process, StateComparator& state, const void* area1,
-                             const void* area2, const Snapshot& snapshot1, const Snapshot& snapshot2,
-                             HeapLocationPairs* previous, Type* type, int pointer_level);
-
-/* Compares the content of each heap fragment between the two states, at the bit level.
- *
- * This operation is costly (about 5 seconds per snapshots' pair to compare on a small program),
- * but hard to optimize because our algorithm is too hackish.
- *
- * Going at bit level can trigger syntaxtic differences on states that are semantically equivalent.
- *
- * Padding bytes constitute the first source of such syntaxtic difference: Any malloced memory contains spaces that
- * are not used to enforce the memory alignment constraints of the CPU. So, cruft of irrelevant changes could get
- * added on these bits. But this case is handled properly, as any memory block is zeroed by mmalloc before being handled
- * back, not only for calloc but also for malloc. So the memory interstices due to padding bytes are properly zeroed.
- *
- * Another source of such change comes from the order of mallocs, that may well change from one execution path to
- * another. This will change the malloc fragment in which the data is stored and the pointer values (syntaxtic
- * difference) while the semantic of the state remains the same.
- *
- * To fix this, this code relies on a hugly hack. When we see a difference during the bit-level comparison,
- * we first check if it could be explained by a pointer-to-block difference. Ie, if when interpreting the memory
- * area containing that difference as a pointer, I get the pointer to a valid fragment in the heap (in both snapshots).
- *
- * This is why we cannot pre-compute a bit-level hash of the heap content: we discover the pointers to other memory
- * fragment when a difference is found during the bit-level exploration. Fixing this would require to save typing
- * information about the memory fragments, which is something that could be done with https://github.com/tudasc/TypeART
- * This would give us all pointers in the mallocated memory, allowing the graph traversal needed to precompute the hash.
- *
- * Using a hash without paying attention to malloc fragment reordering would lead to false negatives:
- * semantically equivalent states would be detected as [syntaxically] different. It's of no importance for the
- * state-equality reduction (we would re-explore semantically equivalent states), but it would endanger the soundness
- * of the liveness model-checker, as state-equality is used to detect the loops that constitute the accepting states of
- * the verified property. So we could miss counter-examples to the verified property. Not good. Not good at all.
- */
-static bool mmalloc_heap_differ(const RemoteProcessMemory& process, StateComparator& state, const Snapshot& snapshot1,
-                                const Snapshot& snapshot2)
-{
-  /* Check busy blocks */
-  size_t i1 = 1;
-
-  malloc_info heapinfo_temp1;
-  malloc_info heapinfo_temp2;
-  malloc_info heapinfo_temp2b;
-
-  const Region* heap_region1 = MC_get_heap_region(snapshot1);
-  const Region* heap_region2 = MC_get_heap_region(snapshot2);
-
-  // This is the address of std_heap->heapinfo in the application process:
-  uint64_t heapinfo_address = process.heap_address.address() + offsetof(s_xbt_mheap_t, heapinfo);
-
-  // This is in snapshot do not use them directly:
-  const malloc_info* heapinfos1 = snapshot1.read(remote<malloc_info*>(heapinfo_address));
-  const malloc_info* heapinfos2 = snapshot2.read(remote<malloc_info*>(heapinfo_address));
-
-  while (i1 < state.heaplimit) {
-    const auto* heapinfo1 =
-        static_cast<malloc_info*>(heap_region1->read(&heapinfo_temp1, &heapinfos1[i1], sizeof(malloc_info)));
-    const auto* heapinfo2 =
-        static_cast<malloc_info*>(heap_region2->read(&heapinfo_temp2, &heapinfos2[i1], sizeof(malloc_info)));
-
-    if (heapinfo1->type == MMALLOC_TYPE_FREE || heapinfo1->type == MMALLOC_TYPE_HEAPINFO) {      /* Free block */
-      i1 ++;
-      continue;
-    }
-
-    xbt_assert(heapinfo1->type >= 0, "Unknown mmalloc block type: %d", heapinfo1->type);
-
-    void* addr_block1 = (ADDR2UINT(i1) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase;
-
-    if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED) { /* Large block */
-      if (is_stack(process, addr_block1)) {
-        for (size_t k = 0; k < heapinfo1->busy_block.size; k++)
-          state.equals_to_<1>(i1 + k, 0) = HeapArea(i1, -1);
-        for (size_t k = 0; k < heapinfo2->busy_block.size; k++)
-          state.equals_to_<2>(i1 + k, 0) = HeapArea(i1, -1);
-        i1 += heapinfo1->busy_block.size;
-        continue;
-      }
-
-      if (state.equals_to_<1>(i1, 0).valid_) {
-        i1++;
-        continue;
-      }
-
-      size_t i2 = 1;
-      bool equal = false;
-
-      /* Try first to associate to same block in the other heap */
-      if (heapinfo2->type == heapinfo1->type && state.equals_to_<2>(i1, 0).valid_ == 0) {
-        const void* addr_block2 = (ADDR2UINT(i1) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase;
-        if (not heap_area_differ(process, state, addr_block1, addr_block2, snapshot1, snapshot2, nullptr, nullptr, 0)) {
-          for (size_t k = 1; k < heapinfo2->busy_block.size; k++)
-            state.equals_to_<2>(i1 + k, 0) = HeapArea(i1, -1);
-          for (size_t k = 1; k < heapinfo1->busy_block.size; k++)
-            state.equals_to_<1>(i1 + k, 0) = HeapArea(i1, -1);
-          equal = true;
-          i1 += heapinfo1->busy_block.size;
-        }
-      }
-
-      while (i2 < state.heaplimit && not equal) {
-        const void* addr_block2 = (ADDR2UINT(i2) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase;
-
-        if (i2 == i1) {
-          i2++;
-          continue;
-        }
-
-        const auto* heapinfo2b =
-            static_cast<malloc_info*>(heap_region2->read(&heapinfo_temp2b, &heapinfos2[i2], sizeof(malloc_info)));
-
-        if (heapinfo2b->type != MMALLOC_TYPE_UNFRAGMENTED) {
-          i2++;
-          continue;
-        }
-
-        if (state.equals_to_<2>(i2, 0).valid_) {
-          i2++;
-          continue;
-        }
-
-        if (not heap_area_differ(process, state, addr_block1, addr_block2, snapshot1, snapshot2, nullptr, nullptr, 0)) {
-          for (size_t k = 1; k < heapinfo2b->busy_block.size; k++)
-            state.equals_to_<2>(i2 + k, 0) = HeapArea(i1, -1);
-          for (size_t k = 1; k < heapinfo1->busy_block.size; k++)
-            state.equals_to_<1>(i1 + k, 0) = HeapArea(i2, -1);
-          equal = true;
-          i1 += heapinfo1->busy_block.size;
-        }
-        i2++;
-      }
-
-      if (not equal) {
-        XBT_DEBUG("Block %zu not found (size_used = %zu, addr = %p)", i1, heapinfo1->busy_block.busy_size, addr_block1);
-        return true;
-      }
-    } else { /* Fragmented block */
-      for (size_t j1 = 0; j1 < (size_t)(BLOCKSIZE >> heapinfo1->type); j1++) {
-        if (heapinfo1->busy_frag.frag_size[j1] == -1) /* Free fragment_ */
-          continue;
-
-        if (state.equals_to_<1>(i1, j1).valid_)
-          continue;
-
-        void* addr_frag1 = (char*)addr_block1 + (j1 << heapinfo1->type);
-
-        size_t i2 = 1;
-        bool equal = false;
-
-        /* Try first to associate to same fragment_ in the other heap */
-        if (heapinfo2->type == heapinfo1->type && not state.equals_to_<2>(i1, j1).valid_) {
-          const void* addr_block2 = (ADDR2UINT(i1) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase;
-          const void* addr_frag2  = (const char*)addr_block2 + (j1 << heapinfo2->type);
-          if (not heap_area_differ(process, state, addr_frag1, addr_frag2, snapshot1, snapshot2, nullptr, nullptr, 0))
-            equal = true;
-        }
-
-        while (i2 < state.heaplimit && not equal) {
-          const auto* heapinfo2b =
-              static_cast<malloc_info*>(heap_region2->read(&heapinfo_temp2b, &heapinfos2[i2], sizeof(malloc_info)));
-
-          if (heapinfo2b->type == MMALLOC_TYPE_FREE || heapinfo2b->type == MMALLOC_TYPE_HEAPINFO) {
-            i2 ++;
-            continue;
-          }
-
-          // We currently do not match fragments with unfragmented blocks (maybe we should).
-          if (heapinfo2b->type == MMALLOC_TYPE_UNFRAGMENTED) {
-            i2++;
-            continue;
-          }
-
-          xbt_assert(heapinfo2b->type >= 0, "Unknown mmalloc block type: %d", heapinfo2b->type);
-
-          for (size_t j2 = 0; j2 < (size_t)(BLOCKSIZE >> heapinfo2b->type); j2++) {
-            if (i2 == i1 && j2 == j1)
-              continue;
-
-            if (state.equals_to_<2>(i2, j2).valid_)
-              continue;
-
-            const void* addr_block2 = (ADDR2UINT(i2) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase;
-            const void* addr_frag2  = (const char*)addr_block2 + (j2 << heapinfo2b->type);
-
-            if (not heap_area_differ(process, state, addr_frag1, addr_frag2, snapshot1, snapshot2, nullptr, nullptr,
-                                     0)) {
-              equal = true;
-              break;
-            }
-          }
-          i2++;
-        }
-
-        if (not equal) {
-          XBT_DEBUG("Block %zu, fragment_ %zu not found (size_used = %zd, address = %p)\n", i1, j1,
-                    heapinfo1->busy_frag.frag_size[j1], addr_frag1);
-          return true;
-        }
-      }
-      i1++;
-    }
-  }
-
-  /* All blocks/fragments are equal to another block/fragment_ ? */
-  for (size_t i = 1; i < state.heaplimit; i++) {
-    const auto* heapinfo1 =
-        static_cast<malloc_info*>(heap_region1->read(&heapinfo_temp1, &heapinfos1[i], sizeof(malloc_info)));
-
-    if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED && i1 == state.heaplimit && heapinfo1->busy_block.busy_size > 0 &&
-        not state.equals_to_<1>(i, 0).valid_) {
-      XBT_DEBUG("Block %zu not found (size used = %zu)", i, heapinfo1->busy_block.busy_size);
-      return true;
-    }
-
-    if (heapinfo1->type <= 0)
-      continue;
-    for (size_t j = 0; j < (size_t)(BLOCKSIZE >> heapinfo1->type); j++)
-      if (i1 == state.heaplimit && heapinfo1->busy_frag.frag_size[j] > 0 && not state.equals_to_<1>(i, j).valid_) {
-        XBT_DEBUG("Block %zu, Fragment %zu not found (size used = %zd)", i, j, heapinfo1->busy_frag.frag_size[j]);
-        return true;
-      }
-  }
-
-  for (size_t i = 1; i < state.heaplimit; i++) {
-    const auto* heapinfo2 =
-        static_cast<malloc_info*>(heap_region2->read(&heapinfo_temp2, &heapinfos2[i], sizeof(malloc_info)));
-    if (heapinfo2->type == MMALLOC_TYPE_UNFRAGMENTED && i1 == state.heaplimit && heapinfo2->busy_block.busy_size > 0 &&
-        not state.equals_to_<2>(i, 0).valid_) {
-      XBT_DEBUG("Block %zu not found (size used = %zu)", i,
-                heapinfo2->busy_block.busy_size);
-      return true;
-    }
-
-    if (heapinfo2->type <= 0)
-      continue;
-
-    for (size_t j = 0; j < (size_t)(BLOCKSIZE >> heapinfo2->type); j++)
-      if (i1 == state.heaplimit && heapinfo2->busy_frag.frag_size[j] > 0 && not state.equals_to_<2>(i, j).valid_) {
-        XBT_DEBUG("Block %zu, Fragment %zu not found (size used = %zd)",
-          i, j, heapinfo2->busy_frag.frag_size[j]);
-        return true;
-      }
-  }
-  return false;
-}
-
-/**
- *
- * @param state
- * @param real_area1     Process address for state 1
- * @param real_area2     Process address for state 2
- * @param snapshot1      Snapshot of state 1
- * @param snapshot2      Snapshot of state 2
- * @param previous
- * @param size
- * @param check_ignore
- * @return true when different, false otherwise (same or unknown)
- */
-static bool heap_area_differ_without_type(const RemoteProcessMemory& process, StateComparator& state,
-                                          const void* real_area1, const void* real_area2, const Snapshot& snapshot1,
-                                          const Snapshot& snapshot2, HeapLocationPairs* previous, int size,
-                                          int check_ignore)
-{
-  const Region* heap_region1  = MC_get_heap_region(snapshot1);
-  const Region* heap_region2  = MC_get_heap_region(snapshot2);
-
-  for (int i = 0; i < size; ) {
-    if (check_ignore > 0) {
-      ssize_t ignore1 = heap_comparison_ignore_size(state.processStates[0].to_ignore, (const char*)real_area1 + i);
-      if (ignore1 != -1) {
-        ssize_t ignore2 = heap_comparison_ignore_size(state.processStates[1].to_ignore, (const char*)real_area2 + i);
-        if (ignore2 == ignore1) {
-          if (ignore1 == 0) {
-            return false;
-          } else {
-            i = i + ignore2;
-            check_ignore--;
-            continue;
-          }
-        }
-      }
-    }
-
-    if (MC_snapshot_region_memcmp((const char*)real_area1 + i, heap_region1, (const char*)real_area2 + i, heap_region2,
-                                  1) != 0) {
-      int pointer_align = (i / sizeof(void *)) * sizeof(void *);
-      const void* addr_pointed1 = snapshot1.read(remote((void* const*)((const char*)real_area1 + pointer_align)));
-      const void* addr_pointed2 = snapshot2.read(remote((void* const*)((const char*)real_area2 + pointer_align)));
-
-      if (process.in_maestro_stack(remote(addr_pointed1)) && process.in_maestro_stack(remote(addr_pointed2))) {
-        i = pointer_align + sizeof(void *);
-        continue;
-      }
-
-      if (snapshot1.on_heap(addr_pointed1) && snapshot2.on_heap(addr_pointed2)) {
-        // Both addresses are in the heap:
-        if (heap_area_differ(process, state, addr_pointed1, addr_pointed2, snapshot1, snapshot2, previous, nullptr, 0))
-          return true;
-        i = pointer_align + sizeof(void *);
-        continue;
-      }
-      return true;
-    }
-    i++;
-  }
-  return false;
-}
-
-/**
- *
- * @param state
- * @param real_area1     Process address for state 1
- * @param real_area2     Process address for state 2
- * @param snapshot1      Snapshot of state 1
- * @param snapshot2      Snapshot of state 2
- * @param previous
- * @param type
- * @param area_size      either a byte_size or an elements_count (?)
- * @param check_ignore
- * @param pointer_level
- * @return               true when different, false otherwise (same or unknown)
- */
-static bool heap_area_differ_with_type(const simgrid::mc::RemoteProcessMemory& process, StateComparator& state,
-                                       const void* real_area1, const void* real_area2, const Snapshot& snapshot1,
-                                       const Snapshot& snapshot2, HeapLocationPairs* previous, const Type* type,
-                                       int area_size, int check_ignore, int pointer_level)
-{
-  // HACK: This should not happen but in practice, there are some
-  // DW_TAG_typedef without an associated DW_AT_type:
-  //<1><538832>: Abbrev Number: 111 (DW_TAG_typedef)
-  //    <538833>   DW_AT_name        : (indirect string, offset: 0x2292f3): gregset_t
-  //    <538837>   DW_AT_decl_file   : 98
-  //    <538838>   DW_AT_decl_line   : 37
-  if (type == nullptr)
-    return false;
-
-  if (is_stack(process, real_area1) && is_stack(process, real_area2))
-    return false;
-
-  if (check_ignore > 0) {
-    ssize_t ignore1 = heap_comparison_ignore_size(state.processStates[0].to_ignore, real_area1);
-    if (ignore1 > 0 && heap_comparison_ignore_size(state.processStates[1].to_ignore, real_area2) == ignore1)
-      return false;
-  }
-
-  const Type* subtype;
-  const Type* subsubtype;
-  int elm_size;
-  const void* addr_pointed1;
-  const void* addr_pointed2;
-
-  const Region* heap_region1 = MC_get_heap_region(snapshot1);
-  const Region* heap_region2 = MC_get_heap_region(snapshot2);
-
-  switch (type->type) {
-    case DW_TAG_unspecified_type:
-      return true;
-
-    case DW_TAG_base_type:
-      if (not type->name.empty() && type->name == "char") { /* String, hence random (arbitrary ?) size */
-        if (real_area1 == real_area2)
-          return false;
-        else
-          return MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, area_size) != 0;
-      } else {
-        if (area_size != -1 && type->byte_size != area_size)
-          return false;
-        else
-          return MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0;
-      }
-
-    case DW_TAG_enumeration_type:
-      if (area_size != -1 && type->byte_size != area_size)
-        return false;
-      return MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0;
-
-    case DW_TAG_typedef:
-    case DW_TAG_const_type:
-    case DW_TAG_volatile_type:
-      return heap_area_differ_with_type(process, state, real_area1, real_area2, snapshot1, snapshot2, previous,
-                                        type->subtype, area_size, check_ignore, pointer_level);
-
-    case DW_TAG_array_type:
-      subtype = type->subtype;
-      switch (subtype->type) {
-        case DW_TAG_unspecified_type:
-          return true;
-
-        case DW_TAG_base_type:
-        case DW_TAG_enumeration_type:
-        case DW_TAG_pointer_type:
-        case DW_TAG_reference_type:
-        case DW_TAG_rvalue_reference_type:
-        case DW_TAG_structure_type:
-        case DW_TAG_class_type:
-        case DW_TAG_union_type:
-          if (subtype->full_type)
-            subtype = subtype->full_type;
-          elm_size  = subtype->byte_size;
-          break;
-        // TODO, just remove the type indirection?
-        case DW_TAG_const_type:
-        case DW_TAG_typedef:
-        case DW_TAG_volatile_type:
-          subsubtype = subtype->subtype;
-          if (subsubtype->full_type)
-            subsubtype = subsubtype->full_type;
-          elm_size     = subsubtype->byte_size;
-          break;
-        default:
-          return false;
-      }
-      for (int i = 0; i < type->element_count; i++) {
-        // TODO, add support for variable stride (DW_AT_byte_stride)
-        if (heap_area_differ_with_type(process, state, (const char*)real_area1 + (i * elm_size),
-                                       (const char*)real_area2 + (i * elm_size), snapshot1, snapshot2, previous,
-                                       type->subtype, subtype->byte_size, check_ignore, pointer_level))
-          return true;
-      }
-      return false;
-
-    case DW_TAG_reference_type:
-    case DW_TAG_rvalue_reference_type:
-    case DW_TAG_pointer_type:
-      if (type->subtype && type->subtype->type == DW_TAG_subroutine_type) {
-        addr_pointed1 = snapshot1.read(remote((void* const*)real_area1));
-        addr_pointed2 = snapshot2.read(remote((void* const*)real_area2));
-        return (addr_pointed1 != addr_pointed2);
-      }
-      pointer_level++;
-      if (pointer_level <= 1) {
-        addr_pointed1 = snapshot1.read(remote((void* const*)real_area1));
-        addr_pointed2 = snapshot2.read(remote((void* const*)real_area2));
-        if (snapshot1.on_heap(addr_pointed1) && snapshot2.on_heap(addr_pointed2))
-          return heap_area_differ(process, state, addr_pointed1, addr_pointed2, snapshot1, snapshot2, previous,
-                                  type->subtype, pointer_level);
-        else
-          return (addr_pointed1 != addr_pointed2);
-      }
-      for (size_t i = 0; i < (area_size / sizeof(void*)); i++) {
-        addr_pointed1 = snapshot1.read(remote((void* const*)((const char*)real_area1 + i * sizeof(void*))));
-        addr_pointed2 = snapshot2.read(remote((void* const*)((const char*)real_area2 + i * sizeof(void*))));
-        bool differ   = snapshot1.on_heap(addr_pointed1) && snapshot2.on_heap(addr_pointed2)
-                            ? heap_area_differ(process, state, addr_pointed1, addr_pointed2, snapshot1, snapshot2,
-                                             previous, type->subtype, pointer_level)
-                            : addr_pointed1 != addr_pointed2;
-        if (differ)
-          return true;
-      }
-      return false;
-
-    case DW_TAG_structure_type:
-    case DW_TAG_class_type:
-      if (type->full_type)
-        type = type->full_type;
-      if (type->byte_size == 0)
-        return false;
-      if (area_size != -1 && type->byte_size != area_size) {
-        if (area_size <= type->byte_size || area_size % type->byte_size != 0)
-          return false;
-        for (size_t i = 0; i < (size_t)(area_size / type->byte_size); i++) {
-          if (heap_area_differ_with_type(process, state, (const char*)real_area1 + i * type->byte_size,
-                                         (const char*)real_area2 + i * type->byte_size, snapshot1, snapshot2, previous,
-                                         type, -1, check_ignore, 0))
-            return true;
-        }
-        } else {
-          for (const simgrid::mc::Member& member : type->members) {
-            // TODO, optimize this? (for the offset case)
-            const void* real_member1 = dwarf::resolve_member(real_area1, type, &member, &snapshot1);
-            const void* real_member2 = dwarf::resolve_member(real_area2, type, &member, &snapshot2);
-            if (heap_area_differ_with_type(process, state, real_member1, real_member2, snapshot1, snapshot2, previous,
-                                           member.type, -1, check_ignore, 0))
-              return true;
-          }
-        }
-        return false;
-
-    case DW_TAG_union_type:
-      return heap_area_differ_without_type(process, state, real_area1, real_area2, snapshot1, snapshot2, previous,
-                                           type->byte_size, check_ignore);
-
-    default:
-      THROW_IMPOSSIBLE;
-  }
-}
-
-/** Infer the type of a part of the block from the type of the block
- *
- * TODO, handle DW_TAG_array_type as well as arrays of the object ((*p)[5], p[5])
- *
- * TODO, handle subfields ((*p).bar.foo, (*p)[5].bar…)
- *
- * @param  type               DWARF type ID of the root address
- * @param  area_size
- * @return                    DWARF type ID for given offset
- */
-static Type* get_offset_type(void* real_base_address, Type* type, int offset, int area_size, const Snapshot& snapshot)
-{
-  // Beginning of the block, the inferred variable type if the type of the block:
-  if (offset == 0)
-    return type;
-
-  switch (type->type) {
-  case DW_TAG_structure_type:
-  case DW_TAG_class_type:
-    if (type->full_type)
-      type = type->full_type;
-    if (area_size != -1 && type->byte_size != area_size) {
-      if (area_size > type->byte_size && area_size % type->byte_size == 0)
-        return type;
-      else
-        return nullptr;
-    }
-
-    for (const simgrid::mc::Member& member : type->members) {
-      if (member.has_offset_location()) {
-        // We have the offset, use it directly (shortcut):
-        if (member.offset() == offset)
-          return member.type;
-      } else {
-        void* real_member = dwarf::resolve_member(real_base_address, type, &member, &snapshot);
-        if ((char*)real_member - (char*)real_base_address == offset)
-          return member.type;
-      }
-    }
-    return nullptr;
-
-  default:
-    /* FIXME: other cases ? */
-    return nullptr;
-  }
-}
-
-/**
- *
- * @param area1          Process address for state 1
- * @param area2          Process address for state 2
- * @param snapshot1      Snapshot of state 1
- * @param snapshot2      Snapshot of state 2
- * @param previous       Pairs of blocks already compared on the current path (or nullptr)
- * @param type_id        Type of variable
- * @param pointer_level
- * @return true when different, false otherwise (same or unknown)
- */
-static bool heap_area_differ(const RemoteProcessMemory& process, StateComparator& state, const void* area1,
-                             const void* area2, const Snapshot& snapshot1, const Snapshot& snapshot2,
-                             HeapLocationPairs* previous, Type* type, int pointer_level)
-{
-  ssize_t block1;
-  ssize_t block2;
-  ssize_t size;
-  int check_ignore = 0;
-
-  int type_size = -1;
-  int offset1   = 0;
-  int offset2   = 0;
-  int new_size1 = -1;
-  int new_size2 = -1;
-
-  Type* new_type1 = nullptr;
-
-  bool match_pairs = false;
-
-  // This is the address of std_heap->heapinfo in the application process:
-  uint64_t heapinfo_address = process.heap_address.address() + offsetof(s_xbt_mheap_t, heapinfo);
-
-  const malloc_info* heapinfos1 = snapshot1.read(remote<malloc_info*>(heapinfo_address));
-  const malloc_info* heapinfos2 = snapshot2.read(remote<malloc_info*>(heapinfo_address));
-
-  malloc_info heapinfo_temp1;
-  malloc_info heapinfo_temp2;
-
-  simgrid::mc::HeapLocationPairs current;
-  if (previous == nullptr) {
-    previous = &current;
-    match_pairs = true;
-  }
-
-  // Get block number:
-  block1 = ((const char*)area1 - (const char*)state.std_heap_copy.heapbase) / BLOCKSIZE + 1;
-  block2 = ((const char*)area2 - (const char*)state.std_heap_copy.heapbase) / BLOCKSIZE + 1;
-
-  // If either block is a stack block:
-  if (is_block_stack(process, (int)block1) && is_block_stack(process, (int)block2)) {
-    previous->insert(HeapLocationPair{{HeapLocation(block1, -1), HeapLocation(block2, -1)}});
-    if (match_pairs)
-      state.match_equals(previous);
-    return false;
-  }
-
-  // If either block is not in the expected area of memory:
-  if (((const char*)area1 < (const char*)state.std_heap_copy.heapbase) ||
-      (block1 > (ssize_t)state.processStates[0].heapsize) ||
-      ((const char*)area2 < (const char*)state.std_heap_copy.heapbase) ||
-      (block2 > (ssize_t)state.processStates[1].heapsize)) {
-    return true;
-  }
-
-  // Process address of the block:
-  void* real_addr_block1 = (ADDR2UINT(block1) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase;
-  void* real_addr_block2 = (ADDR2UINT(block2) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase;
-
-  if (type) {
-    if (type->full_type)
-      type = type->full_type;
-
-    // This assume that for "boring" types (volatile ...) byte_size is absent:
-    while (type->byte_size == 0 && type->subtype != nullptr)
-      type = type->subtype;
-
-    // Find type_size:
-    if (type->type == DW_TAG_pointer_type ||
-        (type->type == DW_TAG_base_type && not type->name.empty() && type->name == "char"))
-      type_size = -1;
-    else
-      type_size = type->byte_size;
-  }
-
-  const Region* heap_region1 = MC_get_heap_region(snapshot1);
-  const Region* heap_region2 = MC_get_heap_region(snapshot2);
-
-  const auto* heapinfo1 =
-      static_cast<malloc_info*>(heap_region1->read(&heapinfo_temp1, &heapinfos1[block1], sizeof(malloc_info)));
-  const auto* heapinfo2 =
-      static_cast<malloc_info*>(heap_region2->read(&heapinfo_temp2, &heapinfos2[block2], sizeof(malloc_info)));
-
-  if ((heapinfo1->type == MMALLOC_TYPE_FREE || heapinfo1->type==MMALLOC_TYPE_HEAPINFO)
-    && (heapinfo2->type == MMALLOC_TYPE_FREE || heapinfo2->type ==MMALLOC_TYPE_HEAPINFO)) {
-    /* Free block */
-    if (match_pairs)
-      state.match_equals(previous);
-    return false;
-  }
-
-  if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED && heapinfo2->type == MMALLOC_TYPE_UNFRAGMENTED) {
-    /* Complete block */
-
-    // TODO, lookup variable type from block type as done for fragmented blocks
-
-    if (state.equals_to_<1>(block1, 0).valid_ && state.equals_to_<2>(block2, 0).valid_ &&
-        state.blocksEqual(block1, block2)) {
-      if (match_pairs)
-        state.match_equals(previous);
-      return false;
-    }
-
-    if (type_size != -1 && type_size != (ssize_t)heapinfo1->busy_block.busy_size &&
-        type_size != (ssize_t)heapinfo2->busy_block.busy_size && type->name.empty()) {
-      if (match_pairs)
-        state.match_equals(previous);
-      return false;
-    }
-
-    if (heapinfo1->busy_block.size != heapinfo2->busy_block.size ||
-        heapinfo1->busy_block.busy_size != heapinfo2->busy_block.busy_size)
-      return true;
-
-    if (not previous->insert(HeapLocationPair{{HeapLocation(block1, -1), HeapLocation(block2, -1)}}).second) {
-      if (match_pairs)
-        state.match_equals(previous);
-      return false;
-    }
-
-    size = heapinfo1->busy_block.busy_size;
-
-    // Remember (basic) type inference.
-    // The current data structure only allows us to do this for the whole block.
-    if (type != nullptr && area1 == real_addr_block1)
-      state.types_<1>(block1, 0) = type;
-    if (type != nullptr && area2 == real_addr_block2)
-      state.types_<2>(block2, 0) = type;
-
-    if (size <= 0) {
-      if (match_pairs)
-        state.match_equals(previous);
-      return false;
-    }
-
-    if (heapinfo1->busy_block.ignore > 0 && heapinfo2->busy_block.ignore == heapinfo1->busy_block.ignore)
-      check_ignore = heapinfo1->busy_block.ignore;
-
-  } else if ((heapinfo1->type > 0) && (heapinfo2->type > 0)) {      /* Fragmented block */
-    // Fragment number:
-    ssize_t frag1 = (ADDR2UINT(area1) % BLOCKSIZE) >> heapinfo1->type;
-    ssize_t frag2 = (ADDR2UINT(area2) % BLOCKSIZE) >> heapinfo2->type;
-
-    // Process address of the fragment_:
-    void* real_addr_frag1 = (char*)real_addr_block1 + (frag1 << heapinfo1->type);
-    void* real_addr_frag2 = (char*)real_addr_block2 + (frag2 << heapinfo2->type);
-
-    // Check the size of the fragments against the size of the type:
-    if (type_size != -1) {
-      if (heapinfo1->busy_frag.frag_size[frag1] == -1 || heapinfo2->busy_frag.frag_size[frag2] == -1) {
-        if (match_pairs)
-          state.match_equals(previous);
-        return false;
-      }
-      // ?
-      if (type_size != heapinfo1->busy_frag.frag_size[frag1]
-          || type_size != heapinfo2->busy_frag.frag_size[frag2]) {
-        if (match_pairs)
-          state.match_equals(previous);
-        return false;
-      }
-    }
-
-    // Check if the blocks are already matched together:
-    if (state.equals_to_<1>(block1, frag1).valid_ && state.equals_to_<2>(block2, frag2).valid_ &&
-        state.fragmentsEqual(block1, frag1, block2, frag2)) {
-      if (match_pairs)
-        state.match_equals(previous);
-      return false;
-    }
-    // Compare the size of both fragments:
-    if (heapinfo1->busy_frag.frag_size[frag1] != heapinfo2->busy_frag.frag_size[frag2]) {
-      if (type_size == -1) {
-        if (match_pairs)
-          state.match_equals(previous);
-        return false;
-      } else
-        return true;
-    }
-
-    // Size of the fragment_:
-    size = heapinfo1->busy_frag.frag_size[frag1];
-
-    // Remember (basic) type inference.
-    // The current data structure only allows us to do this for the whole fragment_.
-    if (type != nullptr && area1 == real_addr_frag1)
-      state.types_<1>(block1, frag1) = type;
-    if (type != nullptr && area2 == real_addr_frag2)
-      state.types_<2>(block2, frag2) = type;
-
-    // The type of the variable is already known:
-    if (type) {
-      new_type1 = type;
-    }
-    // Type inference from the block type.
-    else if (state.types_<1>(block1, frag1) != nullptr || state.types_<2>(block2, frag2) != nullptr) {
-      Type* new_type2 = nullptr;
-
-      offset1 = (const char*)area1 - (const char*)real_addr_frag1;
-      offset2 = (const char*)area2 - (const char*)real_addr_frag2;
-
-      if (state.types_<1>(block1, frag1) != nullptr && state.types_<2>(block2, frag2) != nullptr) {
-        new_type1 = get_offset_type(real_addr_frag1, state.types_<1>(block1, frag1), offset1, size, snapshot1);
-        new_type2 = get_offset_type(real_addr_frag2, state.types_<2>(block2, frag2), offset1, size, snapshot2);
-      } else if (state.types_<1>(block1, frag1) != nullptr) {
-        new_type1 = get_offset_type(real_addr_frag1, state.types_<1>(block1, frag1), offset1, size, snapshot1);
-        new_type2 = get_offset_type(real_addr_frag2, state.types_<1>(block1, frag1), offset2, size, snapshot2);
-      } else if (state.types_<2>(block2, frag2) != nullptr) {
-        new_type1 = get_offset_type(real_addr_frag1, state.types_<2>(block2, frag2), offset1, size, snapshot1);
-        new_type2 = get_offset_type(real_addr_frag2, state.types_<2>(block2, frag2), offset2, size, snapshot2);
-      } else {
-        if (match_pairs)
-          state.match_equals(previous);
-        return false;
-      }
-
-      if (new_type1 != nullptr && new_type2 != nullptr && new_type1 != new_type2) {
-        type = new_type1;
-        while (type->byte_size == 0 && type->subtype != nullptr)
-          type = type->subtype;
-        new_size1 = type->byte_size;
-
-        type = new_type2;
-        while (type->byte_size == 0 && type->subtype != nullptr)
-          type = type->subtype;
-        new_size2 = type->byte_size;
-
-      } else {
-        if (match_pairs)
-          state.match_equals(previous);
-        return false;
-      }
-    }
-
-    if (new_size1 > 0 && new_size1 == new_size2) {
-      type = new_type1;
-      size = new_size1;
-    }
-
-    if (offset1 == 0 && offset2 == 0 &&
-        not previous->insert(HeapLocationPair{{HeapLocation(block1, frag1), HeapLocation(block2, frag2)}}).second) {
-      if (match_pairs)
-        state.match_equals(previous);
-      return false;
-    }
-
-    if (size <= 0) {
-      if (match_pairs)
-        state.match_equals(previous);
-      return false;
-    }
-
-    if ((heapinfo1->busy_frag.ignore[frag1] > 0) &&
-        (heapinfo2->busy_frag.ignore[frag2] == heapinfo1->busy_frag.ignore[frag1]))
-      check_ignore = heapinfo1->busy_frag.ignore[frag1];
-  } else
-    return true;
-
-  /* Start comparison */
-  if (type ? heap_area_differ_with_type(process, state, area1, area2, snapshot1, snapshot2, previous, type, size,
-                                        check_ignore, pointer_level)
-           : heap_area_differ_without_type(process, state, area1, area2, snapshot1, snapshot2, previous, size,
-                                           check_ignore))
-    return true;
-
-  if (match_pairs)
-    state.match_equals(previous);
-  return false;
-}
-} // namespace simgrid::mc
-
-/************************** Snapshot comparison *******************************/
-/******************************************************************************/
-
-static bool areas_differ_with_type(const simgrid::mc::RemoteProcessMemory& process, simgrid::mc::StateComparator& state,
-                                   const void* real_area1, const simgrid::mc::Snapshot& snapshot1,
-                                   simgrid::mc::Region* region1, const void* real_area2,
-                                   const simgrid::mc::Snapshot& snapshot2, simgrid::mc::Region* region2,
-                                   const simgrid::mc::Type* type, int pointer_level)
-{
-  const simgrid::mc::Type* subtype;
-  const simgrid::mc::Type* subsubtype;
-  int elm_size;
-
-  xbt_assert(type != nullptr);
-  switch (type->type) {
-    case DW_TAG_unspecified_type:
-      return true;
-
-    case DW_TAG_base_type:
-    case DW_TAG_enumeration_type:
-    case DW_TAG_union_type:
-      return MC_snapshot_region_memcmp(real_area1, region1, real_area2, region2, type->byte_size) != 0;
-    case DW_TAG_typedef:
-    case DW_TAG_volatile_type:
-    case DW_TAG_const_type:
-      return areas_differ_with_type(process, state, real_area1, snapshot1, region1, real_area2, snapshot2, region2,
-                                    type->subtype, pointer_level);
-    case DW_TAG_array_type:
-      subtype = type->subtype;
-      switch (subtype->type) {
-        case DW_TAG_unspecified_type:
-          return true;
-
-        case DW_TAG_base_type:
-        case DW_TAG_enumeration_type:
-        case DW_TAG_pointer_type:
-        case DW_TAG_reference_type:
-        case DW_TAG_rvalue_reference_type:
-        case DW_TAG_structure_type:
-        case DW_TAG_class_type:
-        case DW_TAG_union_type:
-          if (subtype->full_type)
-            subtype = subtype->full_type;
-          elm_size  = subtype->byte_size;
-          break;
-        case DW_TAG_const_type:
-        case DW_TAG_typedef:
-        case DW_TAG_volatile_type:
-          subsubtype = subtype->subtype;
-          if (subsubtype->full_type)
-            subsubtype = subsubtype->full_type;
-          elm_size     = subsubtype->byte_size;
-          break;
-        default:
-          return false;
-      }
-      for (int i = 0; i < type->element_count; i++) {
-        size_t off = i * elm_size;
-        if (areas_differ_with_type(process, state, (const char*)real_area1 + off, snapshot1, region1,
-                                   (const char*)real_area2 + off, snapshot2, region2, type->subtype, pointer_level))
-          return true;
-      }
-      break;
-    case DW_TAG_pointer_type:
-    case DW_TAG_reference_type:
-    case DW_TAG_rvalue_reference_type: {
-      const void* addr_pointed1 = MC_region_read_pointer(region1, real_area1);
-      const void* addr_pointed2 = MC_region_read_pointer(region2, real_area2);
-
-      if (type->subtype && type->subtype->type == DW_TAG_subroutine_type)
-        return (addr_pointed1 != addr_pointed2);
-      if (addr_pointed1 == nullptr && addr_pointed2 == nullptr)
-        return false;
-      if (addr_pointed1 == nullptr || addr_pointed2 == nullptr)
-        return true;
-      if (not state.compared_pointers.insert(std::make_pair(addr_pointed1, addr_pointed2)).second)
-        return false;
-
-      pointer_level++;
-
-      // Some cases are not handled here:
-      // * the pointers lead to different areas (one to the heap, the other to the RW segment ...)
-      // * a pointer leads to the read-only segment of the current object
-      // * a pointer lead to a different ELF object
-
-      if (snapshot1.on_heap(addr_pointed1)) {
-        if (not snapshot2.on_heap(addr_pointed2))
-          return true;
-        // The pointers are both in the heap:
-        return simgrid::mc::heap_area_differ(process, state, addr_pointed1, addr_pointed2, snapshot1, snapshot2,
-                                             nullptr, type->subtype, pointer_level);
-
-      } else if (region1->contain(simgrid::mc::remote(addr_pointed1))) {
-        // The pointers are both in the current object R/W segment:
-        if (not region2->contain(simgrid::mc::remote(addr_pointed2)))
-          return true;
-        if (not type->type_id)
-          return (addr_pointed1 != addr_pointed2);
-        else
-          return areas_differ_with_type(process, state, addr_pointed1, snapshot1, region1, addr_pointed2, snapshot2,
-                                        region2, type->subtype, pointer_level);
-      } else {
-        // TODO, We do not handle very well the case where
-        // it belongs to a different (non-heap) region from the current one.
-
-        return (addr_pointed1 != addr_pointed2);
-      }
-    }
-    case DW_TAG_structure_type:
-    case DW_TAG_class_type:
-      for (const simgrid::mc::Member& member : type->members) {
-        const void* member1             = simgrid::dwarf::resolve_member(real_area1, type, &member, &snapshot1);
-        const void* member2             = simgrid::dwarf::resolve_member(real_area2, type, &member, &snapshot2);
-        simgrid::mc::Region* subregion1 = snapshot1.get_region(member1, region1); // region1 is hinted
-        simgrid::mc::Region* subregion2 = snapshot2.get_region(member2, region2); // region2 is hinted
-        if (areas_differ_with_type(process, state, member1, snapshot1, subregion1, member2, snapshot2, subregion2,
-                                   member.type, pointer_level))
-          return true;
-      }
-      break;
-    case DW_TAG_subroutine_type:
-      return false;
-    default:
-      XBT_VERB("Unknown case: %d", type->type);
-      break;
-  }
-
-  return false;
-}
-
-static bool global_variables_differ(const simgrid::mc::RemoteProcessMemory& process,
-                                    simgrid::mc::StateComparator& state,
-                                    const simgrid::mc::ObjectInformation* object_info, simgrid::mc::Region* r1,
-                                    simgrid::mc::Region* r2, const simgrid::mc::Snapshot& snapshot1,
-                                    const simgrid::mc::Snapshot& snapshot2)
-{
-  xbt_assert(r1 && r2, "Missing region.");
-
-  const std::vector<simgrid::mc::Variable>& variables = object_info->global_variables;
-
-  for (simgrid::mc::Variable const& current_var : variables) {
-    // If the variable is not in this object, skip it:
-    // We do not expect to find a pointer to something which is not reachable
-    // by the global variables.
-    if ((char*)current_var.address < object_info->start_rw || (char*)current_var.address > object_info->end_rw)
-      continue;
-
-    const simgrid::mc::Type* bvariable_type = current_var.type;
-    if (areas_differ_with_type(process, state, current_var.address, snapshot1, r1, current_var.address, snapshot2, r2,
-                               bvariable_type, 0)) {
-      XBT_VERB("Global variable %s (%p) is different between snapshots", current_var.name.c_str(), current_var.address);
-      return true;
-    }
-  }
-
-  return false;
-}
-
-static bool local_variables_differ(const simgrid::mc::RemoteProcessMemory& process, simgrid::mc::StateComparator& state,
-                                   const simgrid::mc::Snapshot& snapshot1, const simgrid::mc::Snapshot& snapshot2,
-                                   const_mc_snapshot_stack_t stack1, const_mc_snapshot_stack_t stack2)
-{
-  if (stack1->local_variables.size() != stack2->local_variables.size()) {
-    XBT_VERB("Different number of local variables");
-    return true;
-  }
-
-  for (unsigned int cursor = 0; cursor < stack1->local_variables.size(); cursor++) {
-    const_local_variable_t current_var1 = &stack1->local_variables[cursor];
-    const_local_variable_t current_var2 = &stack2->local_variables[cursor];
-    if (current_var1->name != current_var2->name || current_var1->subprogram != current_var2->subprogram ||
-        current_var1->ip != current_var2->ip) {
-      // TODO, fix current_varX->subprogram->name to include name if DW_TAG_inlined_subprogram
-      XBT_VERB("Different name of variable (%s - %s) or frame (%s - %s) or ip (%lu - %lu)", current_var1->name.c_str(),
-               current_var2->name.c_str(), current_var1->subprogram->name.c_str(),
-               current_var2->subprogram->name.c_str(), current_var1->ip, current_var2->ip);
-      return true;
-    }
-
-    if (areas_differ_with_type(process, state, current_var1->address, snapshot1,
-                               snapshot1.get_region(current_var1->address), current_var2->address, snapshot2,
-                               snapshot2.get_region(current_var2->address), current_var1->type, 0)) {
-      XBT_VERB("Local variable %s (%p - %p) in frame %s is different between snapshots", current_var1->name.c_str(),
-               current_var1->address, current_var2->address, current_var1->subprogram->name.c_str());
-      return true;
-    }
-  }
-  return false;
-}
-
-namespace simgrid::mc {
-bool Snapshot::equals_to(const Snapshot& other, RemoteProcessMemory& memory)
-{
-  /* TODO: the memory parameter should be eventually removed. It seems to be there because each snapshot lacks some sort
-    of metadata. That's OK for now (letting appart the fact that we cannot have a nice operator== because we need that
-    extra parameter), but it will fall short when we want to have parallel explorations, with more than one
-    RemoteProcess. At the very least, snapshots will need to know the remote process they are corresponding to, and more
-    probably they will need to embeed all their metadata to let the remoteprocesses die before the end of the
-    exploration. */
-
-  /* TODO: This method should moved to Snapshot.cpp, but it needs the StateComparator that is declared locally to this
-   * file only. */
-
-  static StateComparator state_comparator; // TODO, make this a field of a persistant state object
-
-  if (hash_ != other.hash_) {
-    XBT_VERB("(%ld - %ld) Different hash: 0x%" PRIx64 "--0x%" PRIx64, this->num_state_, other.num_state_, this->hash_,
-             other.hash_);
-    return false;
-  }
-  XBT_VERB("(%ld - %ld) Same hash: 0x%" PRIx64, this->num_state_, other.num_state_, this->hash_);
-
-  /* TODO: re-enable the quick filter of counting enabled processes in each snapshots */
-
-  /* Compare size of stacks */
-  for (unsigned long i = 0; i < this->stacks_.size(); i++) {
-    size_t size_used1 = this->stack_sizes_[i];
-    size_t size_used2 = other.stack_sizes_[i];
-    if (size_used1 != size_used2) {
-      XBT_VERB("(%ld - %ld) Different size used in stacks: %zu - %zu", num_state_, other.num_state_, size_used1,
-               size_used2);
-      return false;
-    }
-  }
-
-  /* Init heap information used in heap comparison algorithm */
-  const s_xbt_mheap_t* heap1 = static_cast<xbt_mheap_t>(
-      this->read_bytes(alloca(sizeof(s_xbt_mheap_t)), sizeof(s_xbt_mheap_t), memory.heap_address, ReadOptions::lazy()));
-  const s_xbt_mheap_t* heap2 = static_cast<xbt_mheap_t>(
-      other.read_bytes(alloca(sizeof(s_xbt_mheap_t)), sizeof(s_xbt_mheap_t), memory.heap_address, ReadOptions::lazy()));
-  if (state_comparator.initHeapInformation(memory, heap1, heap2, this->to_ignore_, other.to_ignore_) == -1) {
-    XBT_VERB("(%ld - %ld) Different heap information", this->num_state_, other.num_state_);
-    return false;
-  }
-
-  /* Stacks comparison */
-  for (unsigned int cursor = 0; cursor < this->stacks_.size(); cursor++) {
-    const_mc_snapshot_stack_t stack1 = &this->stacks_[cursor];
-    const_mc_snapshot_stack_t stack2 = &other.stacks_[cursor];
-
-    if (local_variables_differ(memory, state_comparator, *this, other, stack1, stack2)) {
-      XBT_VERB("(%ld - %ld) Different local variables between stacks %u", this->num_state_, other.num_state_,
-               cursor + 1);
-      return false;
-    }
-  }
-
-  size_t regions_count = this->snapshot_regions_.size();
-  if (regions_count != other.snapshot_regions_.size())
-    return false;
-
-  for (size_t k = 0; k != regions_count; ++k) {
-    Region* region1 = this->snapshot_regions_[k].get();
-    Region* region2 = other.snapshot_regions_[k].get();
-
-    // Preconditions:
-    if (region1->region_type() != RegionType::Data)
-      continue;
-
-    xbt_assert(region1->region_type() == region2->region_type());
-    xbt_assert(region1->object_info() == region2->object_info());
-    xbt_assert(region1->object_info());
-
-    /* Compare global variables */
-    if (global_variables_differ(memory, state_comparator, region1->object_info(), region1, region2, *this, other)) {
-      std::string const& name = region1->object_info()->file_name;
-      XBT_VERB("(%ld - %ld) Different global variables in %s", this->num_state_, other.num_state_, name.c_str());
-      return false;
-    }
-  }
-
-  XBT_VERB("   Compare heap...");
-  /* Compare heap */
-  if (mmalloc_heap_differ(memory, state_comparator, *this, other)) {
-    XBT_VERB("(%ld - %ld) Different heap (mmalloc_heap_differ)", this->num_state_, other.num_state_);
-    return false;
-  }
-
-  XBT_VERB("(%ld - %ld) No difference found", this->num_state_, other.num_state_);
-
-  return true;
-}
-} // namespace simgrid::mc
index a1a51ce..639b28c 100644 (file)
@@ -14,6 +14,7 @@
 #include "xbt/string.hpp"
 
 #include <cstdint>
+#include <inttypes.h>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_comm_determinism, mc, "Logging specific to MC communication determinism detection");
 
@@ -100,7 +101,7 @@ public:
   std::vector<unsigned> communication_indices_;
 
   static simgrid::xbt::Extension<simgrid::mc::State, StateCommDet> EXTENSION_ID;
-  explicit StateCommDet(CommDetExtension& checker, RemoteApp const& remote_app)
+  explicit StateCommDet(CommDetExtension const& checker, RemoteApp const& remote_app)
   {
     const unsigned long maxpid = remote_app.get_maxpid();
     for (unsigned long i = 0; i < maxpid; i++) {
@@ -209,7 +210,7 @@ void CommDetExtension::enforce_deterministic_pattern(aid_t actor, const PatternC
       XBT_INFO("*********************************************************");
       XBT_INFO("%s", send_diff.c_str());
       exploration_.log_state();
-      exploration_.system_exit(SIMGRID_MC_EXIT_NON_DETERMINISM);
+      throw McError(ExitStatus::NON_DETERMINISM);
     } else if (_sg_mc_comms_determinism && (not send_deterministic && not recv_deterministic)) {
       XBT_INFO("****************************************************");
       XBT_INFO("***** Non-deterministic communications pattern *****");
@@ -219,7 +220,7 @@ void CommDetExtension::enforce_deterministic_pattern(aid_t actor, const PatternC
       if (not recv_diff.empty())
         XBT_INFO("%s", recv_diff.c_str());
       exploration_.log_state();
-      exploration_.system_exit(SIMGRID_MC_EXIT_NON_DETERMINISM);
+      throw McError(ExitStatus::NON_DETERMINISM);
     }
   }
 }
@@ -235,7 +236,7 @@ void CommDetExtension::get_comm_pattern(const Transition* transition)
   pattern->index = initial_pattern.index_comm + incomplete_pattern.size();
 
   if (transition->type_ == Transition::Type::COMM_ASYNC_SEND) {
-    auto* send = static_cast<const CommSendTransition*>(transition);
+    const auto* send = static_cast<const CommSendTransition*>(transition);
 
     pattern->type      = PatternCommunicationType::send;
     pattern->comm_addr = send->get_comm();
@@ -244,7 +245,7 @@ void CommDetExtension::get_comm_pattern(const Transition* transition)
     // FIXME: Detached sends should be enforced when the receive is waited
 
   } else if (transition->type_ == Transition::Type::COMM_ASYNC_RECV) {
-    auto* recv = static_cast<const CommRecvTransition*>(transition);
+    const auto* recv = static_cast<const CommRecvTransition*>(transition);
 
     pattern->type      = PatternCommunicationType::receive;
     pattern->comm_addr = recv->get_comm();
@@ -320,15 +321,15 @@ void CommDetExtension::handle_comm_pattern(const Transition* transition)
       }
  */
 
-Exploration* create_communication_determinism_checker(const std::vector<char*>& args, bool with_dpor)
+Exploration* create_communication_determinism_checker(const std::vector<char*>& args, ReductionMode mode)
 {
   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 base      = new DFSExplorer(args, with_dpor, true);
-  auto extension = new CommDetExtension(*base);
+  auto* base      = new DFSExplorer(args, mode);
+  auto* extension = new CommDetExtension(*base);
 
   DFSExplorer::on_exploration_start([extension](RemoteApp const&) {
     XBT_INFO("Check communication determinism");
index 2446342..b328d15 100644 (file)
@@ -4,14 +4,14 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/mc/explo/DFSExplorer.hpp"
-#include "src/mc/VisitedState.hpp"
 #include "src/mc/mc_config.hpp"
 #include "src/mc/mc_exit.hpp"
 #include "src/mc/mc_private.hpp"
 #include "src/mc/mc_record.hpp"
+#include "src/mc/remote/mc_protocol.h"
 #include "src/mc/transition/Transition.hpp"
 
-#include "src/xbt/mmalloc/mmprivate.h"
+#include "xbt/asserts.h"
 #include "xbt/log.h"
 #include "xbt/string.hpp"
 #include "xbt/sysdep.h"
 #include <cassert>
 #include <cstdio>
 
+#include <algorithm>
 #include <memory>
 #include <string>
+#include <unordered_set>
 #include <vector>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dfs, mc, "DFS exploration algorithm of the model-checker");
@@ -39,44 +41,40 @@ xbt::signal<void(Transition*, RemoteApp&)> DFSExplorer::on_transition_execute_si
 
 xbt::signal<void(RemoteApp&)> DFSExplorer::on_log_state_signal;
 
-void DFSExplorer::check_non_termination(const State* current_state)
-{
-  for (auto const& state : stack_) {
-    if (state->get_system_state()->equals_to(*current_state->get_system_state(),
-                                             *get_remote_app().get_remote_process_memory())) {
-      XBT_INFO("Non-progressive cycle: state %ld -> state %ld", state->get_num(), current_state->get_num());
-      XBT_INFO("******************************************");
-      XBT_INFO("*** NON-PROGRESSIVE CYCLE DETECTED ***");
-      XBT_INFO("******************************************");
-      XBT_INFO("Counter-example execution trace:");
-      for (auto const& s : get_textual_trace())
-        XBT_INFO("  %s", s.c_str());
-      XBT_INFO("You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with "
-               "--cfg=model-check/replay:'%s'",
-               get_record_trace().to_string().c_str());
-      log_state();
-
-      throw TerminationError();
-    }
-  }
-}
-
 RecordTrace DFSExplorer::get_record_trace() // override
 {
   RecordTrace res;
-  for (auto const& state : stack_)
-    res.push_back(state->get_transition());
+
+  if (const auto trans = stack_.back()->get_transition_out(); trans != nullptr)
+    res.push_back(trans.get());
+  for (const auto* state = stack_.back().get(); state != nullptr; state = state->get_parent_state().get())
+    if (state->get_transition_in() != nullptr)
+      res.push_front(state->get_transition_in().get());
+
   return res;
 }
 
-std::vector<std::string> DFSExplorer::get_textual_trace() // override
+void DFSExplorer::restore_stack(std::shared_ptr<State> state)
 {
-  std::vector<std::string> trace;
-  for (auto const& state : stack_) {
-    const auto* t = state->get_transition();
-    trace.push_back(xbt::string_printf("%ld: %s", t->aid_, t->to_string().c_str()));
+  stack_.clear();
+  execution_seq_     = odpor::Execution();
+  auto current_state = state;
+  stack_.emplace_front(current_state);
+  // condition corresponds to reaching initial state
+  while (current_state->get_parent_state() != nullptr) {
+    current_state = current_state->get_parent_state();
+    stack_.emplace_front(current_state);
+  }
+  XBT_DEBUG("Replaced stack by %s", get_record_trace().to_string().c_str());
+  if (reduction_mode_ == ReductionMode::sdpor || reduction_mode_ == ReductionMode::odpor) {
+    // NOTE: The outgoing transition for the top-most state of the  stack refers to that which was taken
+    // as part of the last trace explored by the algorithm. Thus, only the sequence of transitions leading up to,
+    // but not including, the last state must be included when reconstructing the Exploration for SDPOR.
+    for (auto iter = std::next(stack_.begin()); iter != stack_.end(); ++iter) {
+      execution_seq_.push_transition((*iter)->get_transition_in());
+    }
+    XBT_DEBUG("Replaced SDPOR/ODPOR execution to reflect the new stack");
   }
-  return trace;
 }
 
 void DFSExplorer::log_state() // override
@@ -84,8 +82,8 @@ void DFSExplorer::log_state() // override
   on_log_state_signal(get_remote_app());
   XBT_INFO("DFS exploration ended. %ld unique states visited; %lu backtracks (%lu transition replays, %lu states "
            "visited overall)",
-           State::get_expanded_states(), backtrack_count_, visited_states_count_,
-           Transition::get_replayed_transitions());
+           State::get_expanded_states(), backtrack_count_, Transition::get_replayed_transitions(),
+           visited_states_count_);
   Exploration::log_state();
 }
 
@@ -98,7 +96,7 @@ void DFSExplorer::run()
 
   while (not stack_.empty()) {
     /* Get current state */
-    State* state = stack_.back().get();
+    auto state = stack_.back();
 
     XBT_DEBUG("**************************************************");
     XBT_DEBUG("Exploration depth=%zu (state:#%ld; %zu interleaves todo)", stack_.size(), state->get_num(),
@@ -112,29 +110,51 @@ void DFSExplorer::run()
         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 /!\\");
-      } else
+      } else if (reduction_mode_ == ReductionMode::sdpor || reduction_mode_ == ReductionMode::odpor) {
+        XBT_ERROR("/!\\ Max depth of %d reached! THIS **WILL** BREAK the reduction, which is not sound "
+                  "when stopping at a fixed depth /!\\",
+                  _sg_mc_max_depth.get());
+        XBT_ERROR("/!\\ If bad things happen, disable the reduction with --cfg=model-check/reduction:none /!\\");
+      } else {
         XBT_WARN("/!\\ Max depth reached ! /!\\ ");
+      }
       this->backtrack();
       continue;
     }
 
-    // Backtrack if we are revisiting a state we saw previously while applying state-equality reduction
-    if (visited_state_ != nullptr) {
-      XBT_DEBUG("State already visited (equal to state %ld), exploration stopped on this path.",
-                visited_state_->original_num_ == -1 ? visited_state_->num_ : visited_state_->original_num_);
-
-      visited_state_ = nullptr;
-      this->backtrack();
-      continue;
+    if (reduction_mode_ == ReductionMode::odpor) {
+      // In the case of ODPOR, the wakeup tree for this state may be empty if we're exploring new territory
+      // (rather than following the partial execution of a wakeup tree). This corresponds to lines 9 to 13 of
+      // the ODPOR pseudocode
+      //
+      // INVARIANT: The execution sequence should be consistent with the state when seeding the tree. If the sequence
+      // gets out of sync with the state, selection will not work as we intend
+      state->seed_wakeup_tree_if_needed(execution_seq_);
     }
 
     // Search for the next transition
-    // next_transition returns a pair<aid_t, double> in case we want to consider multiple state
-    auto [next, _] = state->next_transition_guided();
-
-    if (next < 0) { // If there is no more transition in the current state, backtrack.
-      XBT_DEBUG("There remains %lu actors, but none to interleave (depth %zu).", state->get_actor_count(),
-                stack_.size() + 1);
+    // next_transition returns a pair<aid_t, int>
+    // in case we want to consider multiple states (eg. during backtrack)
+    const aid_t next = reduction_mode_ == ReductionMode::odpor ? state->next_odpor_transition()
+                                                               : std::get<0>(state->next_transition_guided());
+
+    if (next < 0 || not state->is_actor_enabled(next)) {
+      if (next >= 0) { // Actor is not enabled, then
+        XBT_DEBUG(
+            "Reduction %s wants to execute a disabled transition %s. If it's ODPOR, ReversibleRace is suboptimal.",
+            to_c_str(reduction_mode_), state->get_actors_list().at(next).get_transition()->to_string(true).c_str());
+        if (reduction_mode_ == ReductionMode::odpor) {
+          // Remove the disabled transition from the wakeup tree so that ODPOR doesn't try it again
+          state->remove_subtree_at_aid(next);
+          state->add_sleep_set(state->get_actors_list().at(next).get_transition());
+        } else {
+          xbt_assert(false, "Only ODPOR should be confident enought in itself to try executing a disabled transition");
+        }
+      }
+      // If there is no more transition in the current state (or if ODPOR picked an actor that is not enabled --
+      // ReversibleRace is an overapproximation), backtrace
+      XBT_VERB("%lu actors remain, but none of them need to be interleaved (depth %zu).", state->get_actor_count(),
+               stack_.size() + 1);
 
       if (state->get_actor_count() == 0) {
         get_remote_app().finalize_app();
@@ -146,192 +166,316 @@ void DFSExplorer::run()
       continue;
     }
 
-    if (_sg_mc_sleep_set && XBT_LOG_ISENABLED(mc_dfs, xbt_log_priority_verbose)) {
+    if (XBT_LOG_ISENABLED(mc_dfs, xbt_log_priority_verbose)) {
       XBT_VERB("Sleep set actually containing:");
-      for (auto& [aid, transition] : state->get_sleep_set())
-        XBT_VERB("  <%ld,%s>", aid, transition.to_string().c_str());
+      for (const auto& [aid, transition] : state->get_sleep_set())
+        XBT_VERB("  <%ld,%s>", aid, transition->to_string().c_str());
     }
 
+    auto todo = state->get_actors_list().at(next).get_transition();
+    XBT_DEBUG("wanna execute %ld: %.60s", next, todo->to_string().c_str());
+
     /* Actually answer the request: let's execute the selected request (MCed does one step) */
-    state->execute_next(next, get_remote_app());
-    on_transition_execute_signal(state->get_transition(), get_remote_app());
+    auto executed_transition = state->execute_next(next, get_remote_app());
+    on_transition_execute_signal(state->get_transition_out().get(), 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());
+    XBT_VERB("Executed %ld: %.60s (stack depth: %zu, state: %ld, %zu interleaves)", state->get_transition_out()->aid_,
+             state->get_transition_out()->to_string().c_str(), stack_.size(), state->get_num(), state->count_todo());
 
     /* Create the new expanded state (copy the state of MCed into our MCer data) */
-    std::unique_ptr<State> next_state;
-
-    next_state = std::make_unique<State>(get_remote_app(), state);
+    auto next_state = std::make_shared<State>(get_remote_app(), state);
     on_state_creation_signal(next_state.get(), get_remote_app());
 
-    /* Sleep set procedure:
-     * adding the taken transition to the sleep set of the original state.
-     * <!> Since the parent sleep set is used to compute the child sleep set, this need to be
-     * done after next_state creation */
-    XBT_DEBUG("Marking Transition >>%s<< of process %ld done and adding it to the sleep set",
-              state->get_transition()->to_string().c_str(), state->get_transition()->aid_);
-    state->add_sleep_set(state->get_transition()); // Actors are marked done when they are considerd in ActorState
-    
+    if (reduction_mode_ == ReductionMode::odpor) {
+      // With ODPOR, after taking a step forward, we must assign a copy of that subtree to the next state.
+      //
+      // NOTE: We only add actions to the sleep set AFTER we've regenerated states. We must perform the search
+      // fully down a single path before we consider adding any elements to the sleep set according to the pseudocode
+      next_state->sprout_tree_from_parent_state();
+    } else {
+      /* Sleep set procedure:
+       * adding the taken transition to the sleep set of the original state.
+       * <!> Since the parent sleep set is used to compute the child sleep set, this need to be
+       * done after next_state creation */
+      XBT_DEBUG("Marking Transition >>%s<< of process %ld done and adding it to the sleep set",
+                state->get_transition_out()->to_string().c_str(), state->get_transition_out()->aid_);
+      state->add_sleep_set(
+          state->get_transition_out()); // Actors are marked done when they are considered in ActorState
+    }
+
     /* DPOR persistent set procedure:
      * for each new transition considered, check if it depends on any other previous transition executed before it
      * on another process. If there exists one, find the more recent, and add its process to the interleave set.
      * If the process is not enabled at this  point, then add every enabled process to the interleave */
     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();
-        if (state->get_transition()->aid_ == prev_state->get_transition()->aid_) {
-          XBT_DEBUG("Simcall >>%s<< and >>%s<< with same issuer %ld", state->get_transition()->to_string().c_str(),
-                    prev_state->get_transition()->to_string().c_str(), issuer_id);
+      aid_t issuer_id   = state->get_transition_out()->aid_;
+      stack_t tmp_stack = stack_;
+      while (not tmp_stack.empty()) {
+        if (const State* prev_state = tmp_stack.back().get();
+            state->get_transition_out()->aid_ == prev_state->get_transition_out()->aid_) {
+          XBT_DEBUG("Simcall >>%s<< and >>%s<< with same issuer %ld", state->get_transition_out()->to_string().c_str(),
+                    prev_state->get_transition_out()->to_string().c_str(), issuer_id);
+          tmp_stack.pop_back();
           continue;
-        } else if (prev_state->get_transition()->depends(state->get_transition())) {
+        } else if (prev_state->get_transition_out()->depends(state->get_transition_out().get())) {
           XBT_VERB("Dependent Transitions:");
-          XBT_VERB("  %s (state=%ld)", prev_state->get_transition()->to_string().c_str(), prev_state->get_num());
-          XBT_VERB("  %s (state=%ld)", state->get_transition()->to_string().c_str(), state->get_num());
+          XBT_VERB(" #%ld %s (state=%ld)", prev_state->get_transition_out()->aid_,
+                   prev_state->get_transition_out()->to_string().c_str(), prev_state->get_num());
+          XBT_VERB(" #%ld %s (state=%ld)", state->get_transition_out()->aid_,
+                   state->get_transition_out()->to_string().c_str(), state->get_num());
 
           if (prev_state->is_actor_enabled(issuer_id)) {
-            if (not prev_state->is_actor_done(issuer_id))
+            if (not prev_state->is_actor_done(issuer_id)) {
               prev_state->consider_one(issuer_id);
-            else
+              opened_states_.emplace_back(tmp_stack.back());
+            } else
               XBT_DEBUG("Actor %ld is already in done set: no need to explore it again", issuer_id);
           } else {
             XBT_DEBUG("Actor %ld is not enabled: DPOR may be failing. To stay sound, we are marking every enabled "
                       "transition as todo",
                       issuer_id);
-            prev_state->consider_all();
+            // If we ended up marking at least a transition, explore it at some point
+            if (prev_state->consider_all() > 0)
+              opened_states_.emplace_back(tmp_stack.back());
           }
           break;
         } else {
           XBT_VERB("INDEPENDENT Transitions:");
-          XBT_VERB("  %s (state=%ld)", prev_state->get_transition()->to_string().c_str(), prev_state->get_num());
-          XBT_VERB("  %s (state=%ld)", state->get_transition()->to_string().c_str(), state->get_num());
+          XBT_VERB(" #%ld %s (state=%ld)", prev_state->get_transition_out()->aid_,
+                   prev_state->get_transition_out()->to_string().c_str(), prev_state->get_num());
+          XBT_VERB(" #%ld %s (state=%ld)", state->get_transition_out()->aid_,
+                   state->get_transition_out()->to_string().c_str(), state->get_num());
+        }
+        tmp_stack.pop_back();
+      }
+    } else if (reduction_mode_ == ReductionMode::sdpor) {
+      /**
+       * SDPOR Source Set Procedure:
+       *
+       * Find "reversible races" in the current execution `E` with respect to the latest action `p`. For each such race,
+       * determine one thread not contained in the backtrack set at the "race point" `r` which "represents" the trace
+       * formed by first executing everything after `r` that doesn't depend on it (`v := notdep(r, E)`) and then `p` to
+       * flip the race.
+       *
+       * The intuition is that some subsequence of `v` may enable `p`, so we want to be sure that search "in that
+       * direction"
+       */
+      execution_seq_.push_transition(std::move(executed_transition));
+      xbt_assert(execution_seq_.get_latest_event_handle().has_value(), "No events are contained in the SDPOR execution "
+                                                                       "even though one was just added");
+
+      const auto next_E_p = execution_seq_.get_latest_event_handle().value();
+      for (const auto e_race : execution_seq_.get_reversible_races_of(next_E_p)) {
+        State* prev_state  = stack_[e_race].get();
+        const auto choices = execution_seq_.get_missing_source_set_actors_from(e_race, prev_state->get_backtrack_set());
+        if (not choices.empty()) {
+          // NOTE: To incorporate the idea of attempting to select the "best" backtrack point into SDPOR, instead of
+          // selecting the `first` initial, we should instead compute all choices and decide which is best
+          //
+          // Here, we choose the actor with the lowest ID to ensure we get deterministic results
+          const auto q =
+              std::min_element(choices.begin(), choices.end(), [](const aid_t a1, const aid_t a2) { return a1 < a2; });
+          prev_state->consider_one(*q);
+          opened_states_.emplace_back(std::move(prev_state));
         }
       }
+    } else if (reduction_mode_ == ReductionMode::odpor) {
+      // In the case of ODPOR, we simply observe the transition that was executed until we've reached a maximal trace
+      execution_seq_.push_transition(std::move(executed_transition));
     }
 
-    if (_sg_mc_termination)
-      this->check_non_termination(next_state.get());
+    // Before leaving that state, if the transition we just took can be taken multiple times, we
+    // need to give it to the opened states
+    if (stack_.back()->count_todo_multiples() > 0)
+      opened_states_.emplace_back(stack_.back());
 
-    /* Check whether we already explored next_state in the past (but only if interested in state-equality reduction) */
-    if (_sg_mc_max_visited_states > 0)
-      visited_state_ = visited_states_.addVisitedState(next_state->get_num(), next_state.get(), get_remote_app());
+    stack_.emplace_back(std::move(next_state));
 
     /* If this is a new state (or if we don't care about state-equality reduction) */
-    if (visited_state_ == nullptr) {
-      /* Get an enabled process and insert it in the interleave set of the next state */
-      if (reduction_mode_ == ReductionMode::dpor)
-        next_state->consider_best(); // Take only one transition if DPOR: others may be considered later if required
-      else
-        next_state->consider_all();
-
-      dot_output("\"%ld\" -> \"%ld\" [%s];\n", state->get_num(), next_state->get_num(),
-                 state->get_transition()->dot_string().c_str());
-    } else
-      dot_output("\"%ld\" -> \"%ld\" [%s];\n", state->get_num(),
-                 visited_state_->original_num_ == -1 ? visited_state_->num_ : visited_state_->original_num_,
-                 state->get_transition()->dot_string().c_str());
-
-    stack_.push_back(std::move(next_state));
-  }
+    /* Get an enabled process and insert it in the interleave set of the next state */
+    if (reduction_mode_ == ReductionMode::dpor)
+      stack_.back()->consider_best(); // Take only one transition if DPOR: others may be considered later if required
+    else {
+      stack_.back()->consider_all();
+    }
 
+    dot_output("\"%ld\" -> \"%ld\" [%s];\n", state->get_num(), stack_.back()->get_num(),
+               state->get_transition_out()->dot_string().c_str());
+  }
   log_state();
 }
 
+std::shared_ptr<State> DFSExplorer::best_opened_state()
+{
+  int best_prio = 0; // cache the value for the best priority found so far (initialized to silence gcc)
+  auto best     = end(opened_states_);   // iterator to the state to explore having the best priority
+  auto valid    = begin(opened_states_); // iterator marking the limit between states still to explore, and already
+                                         // explored ones
+
+  // Keep only still non-explored states (aid != -1), and record the one with the best (greater) priority.
+  for (auto current = begin(opened_states_); current != end(opened_states_); ++current) {
+    auto [aid, prio] = (*current)->next_transition_guided();
+    if (aid == -1)
+      continue;
+    if (valid != current)
+      *valid = std::move(*current);
+    if (best == end(opened_states_) || prio < best_prio) {
+      best_prio = prio;
+      best      = valid;
+    }
+    ++valid;
+  }
+
+  std::shared_ptr<State> best_state;
+  if (best < valid) {
+    // There are non-explored states, and one of them has the best priority.  Remove it from opened_states_ before
+    // returning.
+    best_state = std::move(*best);
+    --valid;
+    if (best != valid)
+      *best = std::move(*valid);
+  }
+  opened_states_.erase(valid, end(opened_states_));
+
+  return best_state;
+}
+
+std::shared_ptr<State> DFSExplorer::next_odpor_state()
+{
+  for (auto iter = stack_.rbegin(); iter != stack_.rend(); ++iter) {
+    const auto& state = *iter;
+    state->do_odpor_unwind();
+    XBT_DEBUG("\tPerformed ODPOR 'clean-up'. Sleep set has:");
+    for (const auto& [aid, transition] : state->get_sleep_set())
+      XBT_DEBUG("\t  <%ld,%s>", aid, transition->to_string().c_str());
+    if (not state->has_empty_tree()) {
+      return state;
+    }
+  }
+  return nullptr;
+}
+
 void DFSExplorer::backtrack()
 {
-  backtrack_count_++;
+  if (const auto last_event = execution_seq_.get_latest_event_handle();
+      reduction_mode_ == ReductionMode::odpor and last_event.has_value()) {
+    /**
+     * ODPOR Race Detection Procedure:
+     *
+     * For each reversible race in the current execution, we note if there are any continuations `C` equivalent to that
+     * which would reverse the race that have already either a) been searched by ODPOR or b) been *noted* to be searched
+     * by the wakeup tree at the appropriate reversal point, either as `C` directly or an as equivalent to `C`
+     * ("eventually looks like C", viz. the `~_E` relation)
+     */
+    for (auto e_prime = static_cast<odpor::Execution::EventHandle>(0); e_prime <= last_event.value(); ++e_prime) {
+      XBT_DEBUG("ODPOR: Now considering all possible race with `%u`", e_prime);
+      for (const auto e : execution_seq_.get_reversible_races_of(e_prime)) {
+        XBT_DEBUG("ODPOR: Reversible race detected between events `%u` and `%u`", e, e_prime);
+        State& prev_state = *stack_[e];
+        if (const auto v = execution_seq_.get_odpor_extension_from(e, e_prime, prev_state); v.has_value()) {
+          switch (prev_state.insert_into_wakeup_tree(v.value(), execution_seq_.get_prefix_before(e))) {
+            case odpor::WakeupTree::InsertionResult::root: {
+              XBT_DEBUG("ODPOR: Reversible race with `%u`(%ld: %.20s) unaccounted for in the wakeup tree for "
+                        "the execution prior to event `%u`(%ld: %.20s):",
+                        e_prime, stack_[e_prime]->get_transition_out()->aid_,
+                        stack_[e_prime]->get_transition_out()->to_string(true).c_str(), e,
+                        prev_state.get_transition_out()->aid_,
+                        prev_state.get_transition_out()->to_string(true).c_str());
+              break;
+            }
+            case odpor::WakeupTree::InsertionResult::interior_node: {
+              XBT_DEBUG("ODPOR: Reversible race with `%u` partially accounted for in the wakeup tree for "
+                        "the execution prior to event `%u`:",
+                        e_prime, e);
+              break;
+            }
+            case odpor::WakeupTree::InsertionResult::leaf: {
+              XBT_DEBUG("ODPOR: Reversible race with `%u` accounted for in the wakeup tree for "
+                        "the execution prior to event `%u`:",
+                        e_prime, e);
+              break;
+            }
+          }
+          for (const auto& seq : simgrid::mc::odpor::get_textual_trace(v.value())) {
+            XBT_DEBUG(" %s", seq.c_str());
+          }
+        } else {
+          XBT_DEBUG("ODPOR: Ignoring race: `sleep(E')` intersects `WI_[E'](v := notdep(%u, E))`", e);
+          XBT_DEBUG("Sleep set contains:");
+          for (const auto& [aid, transition] : prev_state.get_sleep_set())
+            XBT_DEBUG("  <%ld,%s>", aid, transition->to_string().c_str());
+        }
+      }
+    }
+  }
+
   XBT_VERB("Backtracking from %s", get_record_trace().to_string().c_str());
+  XBT_DEBUG("%lu alternatives are yet to be explored:", opened_states_.size());
+
   on_backtracking_signal(get_remote_app());
   get_remote_app().check_deadlock();
 
-  /* We may backtrack from somewhere either because it's leaf, or because every enabled process are in done/sleep set.
-   * In the first case, we need to remove the last transition corresponding to the Finalize */
-  if (stack_.back()->get_transition()->aid_ == 0)
-    stack_.pop_back();
-
-  /* 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. */
-  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();
+  // Take the point with smallest distance
+  auto backtracking_point = reduction_mode_ == ReductionMode::odpor ? next_odpor_state() : best_opened_state();
 
+  // if no backtracking point, then set the stack_ to empty so we can end the exploration
+  if (not backtracking_point) {
+    XBT_DEBUG("No more opened point of exploration, the search will end");
+    stack_.clear();
+    return;
+  }
 
-    if (state->count_todo() == 0) { // Empty interleaving set: exploration at this level is over
-      XBT_DEBUG("Delete state %ld at depth %zu", state->get_num(), stack_.size() + 1);
+  // We found a backtracking point, let's go to it
+  backtrack_count_++;
+  XBT_DEBUG("Backtracking to state#%ld", backtracking_point->get_num());
 
-    } else {
-      XBT_DEBUG("Back-tracking to state %ld at depth %zu: %lu transitions left to be explored", state->get_num(),
-                stack_.size() + 1, state->count_todo());
-      stack_.push_back(
-          std::move(state)); // Put it back on the stack so we can explore the next transition of the interleave
-      found_backtracking_point = true;
-    }
+  // Search how to restore the backtracking point
+  std::deque<Transition*> replay_recipe;
+  for (const auto* s = backtracking_point.get(); s != nullptr; s = s->get_parent_state().get()) {
+    if (s->get_transition_in() != nullptr) // The root has no transition_in
+      replay_recipe.push_front(s->get_transition_in().get());
   }
 
-  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_memory());
-      on_restore_system_state_signal(last_state, get_remote_app());
-      return;
-    }
+  // Restore the initial state if no intermediate state was found
+  get_remote_app().restore_initial_state();
+  on_restore_initial_state_signal(get_remote_app());
 
-    /* if no snapshot, we need to restore the initial state and replay the transitions */
-    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(get_remote_app());
-      on_transition_replay_signal(state->get_transition(), get_remote_app());
-      visited_states_count_++;
-    }
-  } // If no backtracing point, then the stack is empty and the exploration is over
+  /* if no snapshot, we need to restore the initial state and replay the transitions */
+  /* Traverse the stack from the state at position start and re-execute the transitions */
+  for (auto& transition : replay_recipe) {
+    transition->replay(get_remote_app());
+    on_transition_replay_signal(transition, get_remote_app());
+    visited_states_count_++;
+  }
+  this->restore_stack(backtracking_point);
 }
 
-DFSExplorer::DFSExplorer(const std::vector<char*>& args, bool with_dpor, bool need_memory_info)
-    : Exploration(args, need_memory_info || _sg_mc_termination)
+DFSExplorer::DFSExplorer(const std::vector<char*>& args, ReductionMode mode) : Exploration(args), reduction_mode_(mode)
 {
-  if (with_dpor)
-    reduction_mode_ = ReductionMode::dpor;
-  else
-    reduction_mode_ = ReductionMode::none;
-
-  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_));
+  XBT_INFO("Start a DFS exploration. Reduction is: %s.", to_c_str(reduction_mode_));
 
-  auto initial_state = std::make_unique<State>(get_remote_app());
+  auto initial_state = std::make_shared<State>(get_remote_app());
 
   XBT_DEBUG("**************************************************");
 
+  stack_.emplace_back(std::move(initial_state));
+
   /* Get an enabled actor and insert it in the interleave set of the initial state */
-  XBT_DEBUG("Initial state. %lu actors to consider", initial_state->get_actor_count());
+  XBT_DEBUG("Initial state. %lu actors to consider", stack_.back()->get_actor_count());
   if (reduction_mode_ == ReductionMode::dpor)
-    initial_state->consider_best();
-  else
-    initial_state->consider_all();
-
-  stack_.push_back(std::move(initial_state));
+    stack_.back()->consider_best();
+  else {
+    stack_.back()->consider_all();
+  }
+  if (stack_.back()->count_todo_multiples() > 1)
+    opened_states_.emplace_back(stack_.back());
 }
 
-Exploration* create_dfs_exploration(const std::vector<char*>& args, bool with_dpor)
+Exploration* create_dfs_exploration(const std::vector<char*>& args, ReductionMode mode)
 {
-  return new DFSExplorer(args, with_dpor);
+  return new DFSExplorer(args, mode);
 }
 
 } // namespace simgrid::mc
index 353e00c..bb80b08 100644 (file)
@@ -6,19 +6,26 @@
 #ifndef SIMGRID_MC_SAFETY_CHECKER_HPP
 #define SIMGRID_MC_SAFETY_CHECKER_HPP
 
-#include "src/mc/VisitedState.hpp"
+#include "src/mc/api/ClockVector.hpp"
+#include "src/mc/api/State.hpp"
 #include "src/mc/explo/Exploration.hpp"
+#include "src/mc/explo/odpor/Execution.hpp"
+#include "src/mc/mc_config.hpp"
 
+#include <deque>
 #include <list>
 #include <memory>
+#include <set>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 namespace simgrid::mc {
 
-class XBT_PRIVATE DFSExplorer : public Exploration {
-  XBT_DECLARE_ENUM_CLASS(ReductionMode, none, dpor);
+using stack_t = std::deque<std::shared_ptr<State>>;
 
+class XBT_PRIVATE DFSExplorer : public Exploration {
+private:
   ReductionMode reduction_mode_;
   unsigned long backtrack_count_      = 0; // for statistics
   unsigned long visited_states_count_ = 0; // for statistics
@@ -36,10 +43,9 @@ class XBT_PRIVATE DFSExplorer : public Exploration {
   static xbt::signal<void(RemoteApp&)> on_log_state_signal;
 
 public:
-  explicit DFSExplorer(const std::vector<char*>& args, bool with_dpor, bool need_memory_info = false);
+  explicit DFSExplorer(const std::vector<char*>& args, ReductionMode mode);
   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 */
@@ -82,13 +88,36 @@ public:
   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();
 
   /** Stack representing the position in the exploration graph */
-  std::list<std::unique_ptr<State>> stack_;
-  VisitedStates visited_states_;
-  std::unique_ptr<VisitedState> visited_state_;
+  stack_t stack_;
+
+  /**
+   * Provides additional metadata about the position in the exploration graph
+   * which is used by SDPOR and ODPOR
+   */
+  odpor::Execution execution_seq_;
+
+  /** Per-actor clock vectors used to compute the "happens-before" relation */
+  std::unordered_map<aid_t, ClockVector> per_actor_clocks_;
+
+  /** Opened states are states that still contains todo actors.
+   *  When backtracking, we pick a state from it*/
+  std::vector<std::shared_ptr<State>> opened_states_;
+  std::shared_ptr<State> best_opened_state();
+
+  /** If we're running ODPOR, picks the corresponding state in the stack
+   * (opened_states_ are ignored)
+   */
+  std::shared_ptr<State> next_odpor_state();
+
+  /** Change current stack_ value to correspond to the one we would have
+   *  had if we executed transition to get to state. This is required when
+   *  backtracking, and achieved thanks to the fact states save their parent.*/
+  void restore_stack(std::shared_ptr<State> state);
+
+  RecordTrace get_record_trace_of_stack(stack_t stack);
 };
 
 } // namespace simgrid::mc
index 061a9b4..58bc34d 100644 (file)
@@ -5,9 +5,10 @@
 
 #include "src/mc/explo/Exploration.hpp"
 #include "src/mc/mc_config.hpp"
+#include "src/mc/mc_environ.h"
 #include "src/mc/mc_exit.hpp"
 #include "src/mc/mc_private.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
+#include "xbt/string.hpp"
 
 #include <sys/wait.h>
 
@@ -20,8 +21,7 @@ static simgrid::config::Flag<std::string> cfg_dot_output_file{
 
 Exploration* Exploration::instance_ = nullptr; // singleton instance
 
-Exploration::Exploration(const std::vector<char*>& args, bool need_memory_introspection)
-    : remote_app_(std::make_unique<RemoteApp>(args, need_memory_introspection))
+Exploration::Exploration(const std::vector<char*>& args) : remote_app_(std::make_unique<RemoteApp>(args))
 {
   xbt_assert(instance_ == nullptr, "Cannot have more than one exploration instance");
   instance_ = this;
@@ -59,20 +59,49 @@ void Exploration::log_state()
     dot_output("}\n");
     fclose(dot_output_);
   }
-  if (getenv("SIMGRID_MC_SYSTEM_STATISTICS")) {
+  if (getenv(MC_ENV_SYSTEM_STATISTICS)) {
     int ret = system("free");
     if (ret != 0)
       XBT_WARN("Call to system(free) did not return 0, but %d", ret);
   }
 }
+// Make our tests fully reproducible despite the subtle differences of strsignal() across archs
+static const char* signal_name(int status)
+{
+  switch (WTERMSIG(status)) {
+    case SIGABRT: // FreeBSD uses "Abort trap" as a strsignal for SIGABRT
+      return "Aborted";
+    case SIGSEGV: // MacOSX uses "Segmentation fault: 11" for SIGKILL
+      return "Segmentation fault";
+    default:
+      return strsignal(WTERMSIG(status));
+  }
+}
+
+std::vector<std::string> Exploration::get_textual_trace(int max_elements)
+{
+  std::vector<std::string> trace;
+  for (auto const& transition : get_record_trace()) {
+    auto const& call_location = transition->get_call_location();
+    if (not call_location.empty())
+      trace.push_back(xbt::string_printf("Actor %ld in %s ==> simcall: %s", transition->aid_, call_location.c_str(),
+                                         transition->to_string().c_str()));
+    else
+      trace.push_back(xbt::string_printf("Actor %ld in simcall %s", transition->aid_, transition->to_string().c_str()));
+    max_elements--;
+    if (max_elements == 0)
+      break;
+  }
+  return trace;
+}
 
 XBT_ATTRIB_NORETURN void Exploration::report_crash(int status)
 {
   XBT_INFO("**************************");
   XBT_INFO("** CRASH IN THE PROGRAM **");
   XBT_INFO("**************************");
-  if (WIFSIGNALED(status)) // FreeBSD use "Abort trap" as a strsignal for SIGABRT that is part of our tests
-    XBT_INFO("From signal: %s", WTERMSIG(status) == SIGABRT ? "Aborted" : strsignal(WTERMSIG(status)));
+  if (WIFSIGNALED(status))
+    XBT_INFO("From signal: %s", signal_name(status));
   else if (WIFEXITED(status))
     XBT_INFO("From exit: %i", WEXITSTATUS(status));
   if (not xbt_log_no_loc)
@@ -85,19 +114,8 @@ XBT_ATTRIB_NORETURN void Exploration::report_crash(int status)
            "--cfg=model-check/replay:'%s'",
            get_record_trace().to_string().c_str());
   log_state();
-  if (xbt_log_no_loc) {
-    XBT_INFO("Stack trace not displayed because you passed --log=no_loc");
-  } else {
-    const auto* memory = get_remote_app().get_remote_process_memory();
-    if (memory) {
-      XBT_INFO("Stack trace:");
-      memory->dump_stack();
-    } else {
-      XBT_INFO("Stack trace not shown because there is no memory introspection.");
-    }
-  }
 
-  system_exit(SIMGRID_MC_EXIT_PROGRAM_CRASH);
+  throw McError(ExitStatus::PROGRAM_CRASH);
 }
 XBT_ATTRIB_NORETURN void Exploration::report_assertion_failure()
 {
@@ -111,12 +129,7 @@ XBT_ATTRIB_NORETURN void Exploration::report_assertion_failure()
            "--cfg=model-check/replay:'%s'",
            get_record_trace().to_string().c_str());
   log_state();
-  system_exit(SIMGRID_MC_EXIT_SAFETY);
-}
-
-void Exploration::system_exit(int status) const
-{
-  ::exit(status);
+  throw McError(ExitStatus::SAFETY);
 }
 
 }; // namespace simgrid::mc
index aa6d420..8ef417c 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "simgrid/forward.h"
 #include "src/mc/api/RemoteApp.hpp"
+#include "src/mc/mc_config.hpp"
+#include "src/mc/mc_exit.hpp"
 #include "src/mc/mc_record.hpp"
 #include <xbt/Extendable.hpp>
 
@@ -34,12 +36,12 @@ class Exploration : public xbt::Extendable<Exploration> {
   FILE* dot_output_ = nullptr;
 
 public:
-  explicit Exploration(const std::vector<char*>& args, bool need_memory_introspection);
+  explicit Exploration(const std::vector<char*>& args);
   virtual ~Exploration();
 
   static Exploration* get_instance() { return instance_; }
   // No copy:
-  Exploration(Exploration const&) = delete;
+  Exploration(Exploration const&)            = delete;
   Exploration& operator=(Exploration const&) = delete;
 
   /** Main function of this algorithm */
@@ -50,20 +52,15 @@ public:
   /** Produce an error message indicating that a property was violated */
   XBT_ATTRIB_NORETURN void report_assertion_failure();
 
-  /** Kill the application and the model-checker (which exits with `status`)*/
-  XBT_ATTRIB_NORETURN void system_exit(int status) const;
-
   /* These methods are callbacks called by the model-checking engine
    * to get and display information about the current state of the
    * model-checking algorithm: */
 
-  /** Show the current trace/stack
-   *
-   *  Could this be handled in the Session/ModelChecker instead? */
+  /** Retrieve the current stack to build an execution trace */
   virtual RecordTrace get_record_trace() = 0;
 
   /** Generate a textual execution trace of the simulated application */
-  virtual std::vector<std::string> get_textual_trace() = 0;
+  std::vector<std::string> get_textual_trace(int max_elements = -1);
 
   /** Log additional information about the state of the model-checker */
   virtual void log_state();
@@ -75,9 +72,8 @@ public:
 };
 
 // External constructors so that the types (and the types of their content) remain hidden
-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_dfs_exploration(const std::vector<char*>& args, ReductionMode mode);
+XBT_PUBLIC Exploration* create_communication_determinism_checker(const std::vector<char*>& args, ReductionMode mode);
 XBT_PUBLIC Exploration* create_udpor_checker(const std::vector<char*>& args);
 
 } // namespace simgrid::mc
diff --git a/src/mc/explo/LivenessChecker.cpp b/src/mc/explo/LivenessChecker.cpp
deleted file mode 100644 (file)
index 3638fd6..0000000
+++ /dev/null
@@ -1,445 +0,0 @@
-/* Copyright (c) 2011-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/explo/LivenessChecker.hpp"
-#include "src/mc/api/RemoteApp.hpp"
-#include "src/mc/mc_config.hpp"
-#include "src/mc/mc_exit.hpp"
-#include "src/mc/mc_private.hpp"
-
-#include <boost/range/algorithm.hpp>
-#include <cstring>
-
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_liveness, mc, "Logging specific to algorithms for liveness properties verification");
-
-/********* Static functions *********/
-
-namespace simgrid::mc {
-
-VisitedPair::VisitedPair(int pair_num, xbt_automaton_state_t prop_state,
-                         std::shared_ptr<const std::vector<int>> atomic_propositions, std::shared_ptr<State> app_state,
-                         RemoteApp& remote_app)
-    : num(pair_num), prop_state_(prop_state)
-{
-  auto* memory     = remote_app.get_remote_process_memory();
-  this->app_state_ = std::move(app_state);
-  if (not this->app_state_->get_system_state())
-    this->app_state_->set_system_state(std::make_shared<Snapshot>(pair_num, remote_app.get_page_store(), *memory));
-  this->heap_bytes_used     = memory->get_remote_heap_bytes();
-  this->actor_count_        = app_state_->get_actor_count();
-  this->other_num           = -1;
-  this->atomic_propositions = std::move(atomic_propositions);
-}
-
-bool LivenessChecker::evaluate_label(const xbt_automaton_exp_label* l, std::vector<int> const& values)
-{
-  switch (l->type) {
-    case xbt_automaton_exp_label::AUT_OR:
-      return evaluate_label(l->u.or_and.left_exp, values) || evaluate_label(l->u.or_and.right_exp, values);
-    case xbt_automaton_exp_label::AUT_AND:
-      return evaluate_label(l->u.or_and.left_exp, values) && evaluate_label(l->u.or_and.right_exp, values);
-    case xbt_automaton_exp_label::AUT_NOT:
-      return not evaluate_label(l->u.exp_not, values);
-    case xbt_automaton_exp_label::AUT_PREDICAT:
-      return values.at(compare_automaton_exp_label(l)) != 0;
-    case xbt_automaton_exp_label::AUT_ONE:
-      return true;
-    default:
-      xbt_die("Unexpected value for automaton");
-  }
-}
-
-Pair::Pair(unsigned long expanded_pairs) : num(expanded_pairs) {}
-
-std::shared_ptr<const std::vector<int>> LivenessChecker::get_proposition_values() const
-{
-  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->prop_state_, pair->atomic_propositions,
-                                                pair->app_state_, get_remote_app());
-
-  auto [res_begin,
-        res_end] = boost::range::equal_range(acceptance_pairs_, new_pair.get(), [](auto const& a, auto const& b) {
-    return std::make_pair(a->actor_count_, a->heap_bytes_used) < std::make_pair(b->actor_count_, b->heap_bytes_used);
-  });
-
-  if (pair->search_cycle)
-    for (auto i = res_begin; i != res_end; ++i) {
-      std::shared_ptr<simgrid::mc::VisitedPair> const& pair_test = *i;
-      if (xbt_automaton_state_compare(pair_test->prop_state_, new_pair->prop_state_) != 0 ||
-          *(pair_test->atomic_propositions) != *(new_pair->atomic_propositions) ||
-          (not pair_test->app_state_->get_system_state()->equals_to(*new_pair->app_state_->get_system_state(),
-                                                                    *get_remote_app().get_remote_process_memory())))
-        continue;
-      XBT_INFO("Pair %d already reached (equal to pair %d) !", new_pair->num, pair_test->num);
-      exploration_stack_.pop_back();
-      dot_output("\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, pair_test->num, this->previous_request_.c_str());
-      return nullptr;
-    }
-
-  acceptance_pairs_.insert(res_begin, new_pair);
-  return new_pair;
-}
-
-void LivenessChecker::remove_acceptance_pair(int pair_num)
-{
-  for (auto i = acceptance_pairs_.begin(); i != acceptance_pairs_.end(); ++i)
-    if ((*i)->num == pair_num) {
-      acceptance_pairs_.erase(i);
-      break;
-    }
-}
-
-void LivenessChecker::replay()
-{
-  XBT_DEBUG("**** Begin Replay ****");
-
-  /* Intermediate backtracking */
-  if (_sg_mc_checkpoint > 0) {
-    const Pair* pair = exploration_stack_.back().get();
-    if (const auto* system_state = pair->app_state_->get_system_state()) {
-      system_state->restore(*get_remote_app().get_remote_process_memory());
-      return;
-    }
-  }
-
-  get_remote_app().restore_initial_state();
-
-  /* Traverse the stack from the initial state and re-execute the transitions */
-  int depth = 1;
-  for (std::shared_ptr<Pair> const& pair : exploration_stack_) {
-    if (pair == exploration_stack_.back())
-      break;
-
-    std::shared_ptr<State> state = pair->app_state_;
-
-    if (pair->exploration_started) {
-      state->get_transition()->replay(get_remote_app());
-      XBT_DEBUG("Replay (depth = %d) : %s (%p)", depth, state->get_transition()->to_string().c_str(), state.get());
-    }
-
-    /* Update statistics */
-    visited_pairs_count_++;
-    depth++;
-  }
-  XBT_DEBUG("**** End Replay ****");
-}
-
-/**
- * @brief Checks whether a given pair has already been visited by the algorithm.
- */
-int LivenessChecker::insert_visited_pair(std::shared_ptr<VisitedPair> visited_pair, simgrid::mc::Pair* pair)
-{
-  if (_sg_mc_max_visited_states == 0)
-    return -1;
-
-  if (visited_pair == nullptr)
-    visited_pair = std::make_shared<VisitedPair>(pair->num, pair->prop_state_, pair->atomic_propositions,
-                                                 pair->app_state_, get_remote_app());
-
-  auto [range_begin,
-        range_end] = boost::range::equal_range(visited_pairs_, visited_pair.get(), [](auto const& a, auto const& b) {
-    return std::make_pair(a->actor_count_, a->heap_bytes_used) < std::make_pair(b->actor_count_, b->heap_bytes_used);
-  });
-
-  for (auto i = range_begin; i != range_end; ++i) {
-    const VisitedPair* pair_test = i->get();
-    if (xbt_automaton_state_compare(pair_test->prop_state_, visited_pair->prop_state_) != 0 ||
-        *(pair_test->atomic_propositions) != *(visited_pair->atomic_propositions) ||
-        (not pair_test->app_state_->get_system_state()->equals_to(*visited_pair->app_state_->get_system_state(),
-                                                                  *get_remote_app().get_remote_process_memory())))
-      continue;
-    if (pair_test->other_num == -1)
-      visited_pair->other_num = pair_test->num;
-    else
-      visited_pair->other_num = pair_test->other_num;
-    XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", visited_pair->num, pair_test->num,
-              visited_pair->other_num);
-    (*i) = std::move(visited_pair);
-    return (*i)->other_num;
-  }
-
-  visited_pairs_.insert(range_begin, std::move(visited_pair));
-  this->purge_visited_pairs();
-  return -1;
-}
-
-void LivenessChecker::purge_visited_pairs()
-{
-  if (_sg_mc_max_visited_states != 0 && visited_pairs_.size() > (std::size_t)_sg_mc_max_visited_states) {
-    // Remove the oldest entry with a linear search:
-    visited_pairs_.erase(
-        boost::min_element(visited_pairs_, [](std::shared_ptr<VisitedPair> const a,
-                                              std::shared_ptr<VisitedPair> const& b) { return a->num < b->num; }));
-  }
-}
-
-LivenessChecker::LivenessChecker(const std::vector<char*>& args) : Exploration(args, true) {}
-LivenessChecker::~LivenessChecker()
-{
-  xbt_automaton_free(property_automaton_);
-}
-
-xbt_automaton_t LivenessChecker::property_automaton_ = nullptr;
-
-void LivenessChecker::automaton_load(const char* file) const
-{
-  if (property_automaton_ == nullptr)
-    property_automaton_ = xbt_automaton_new();
-
-  xbt_automaton_load(property_automaton_, file);
-}
-
-std::vector<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(RemoteProcessMemory 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->app_state_->get_transition());
-  return res;
-}
-
-void LivenessChecker::log_state() // override
-{
-  XBT_INFO("Expanded pairs = %lu", expanded_pairs_count_);
-  XBT_INFO("Visited pairs = %lu", visited_pairs_count_);
-  XBT_INFO("Executed transitions = %lu", Transition::get_executed_transitions());
-  Exploration::log_state();
-}
-
-void LivenessChecker::show_acceptance_cycle(std::size_t depth)
-{
-  XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
-  XBT_INFO("|             ACCEPTANCE CYCLE            |");
-  XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
-  XBT_INFO("Counter-example that violates formula:");
-  for (auto const& s : this->get_textual_trace())
-    XBT_INFO("  %s", s.c_str());
-  XBT_INFO("You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with "
-           "--cfg=model-check/replay:'%s'",
-           get_record_trace().to_string().c_str());
-  log_state();
-  XBT_INFO("Counter-example depth: %zu", depth);
-}
-
-std::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->app_state_->get_transition()->to_string());
-
-  return trace;
-}
-
-std::shared_ptr<Pair> LivenessChecker::create_pair(const Pair* current_pair, xbt_automaton_state_t state,
-                                                   std::shared_ptr<const std::vector<int>> propositions)
-{
-  ++expanded_pairs_count_;
-  auto next_pair                 = std::make_shared<Pair>(expanded_pairs_count_);
-  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 const& [aid, _] : next_pair->app_state_->get_actors_list())
-    if (next_pair->app_state_->is_actor_enabled(aid))
-      next_pair->app_state_->consider_one(aid);
-
-  next_pair->requests = next_pair->app_state_->count_todo();
-  /* FIXME : get search_cycle value for each accepting state */
-  if (next_pair->prop_state_->type == 1 || (current_pair && current_pair->search_cycle))
-    next_pair->search_cycle = true;
-  else
-    next_pair->search_cycle = false;
-  return next_pair;
-}
-
-void LivenessChecker::backtrack()
-{
-  /* Traverse the stack backwards until a pair with a non empty interleave
-     set is found, deleting all the pairs that have it empty in the way. */
-  while (not exploration_stack_.empty()) {
-    std::shared_ptr<simgrid::mc::Pair> current_pair = exploration_stack_.back();
-    exploration_stack_.pop_back();
-    if (current_pair->requests > 0) {
-      /* We found a backtracking point */
-      XBT_DEBUG("Backtracking to depth %d", current_pair->depth);
-      exploration_stack_.push_back(std::move(current_pair));
-      this->replay();
-      XBT_DEBUG("Backtracking done");
-      break;
-    } else {
-      XBT_DEBUG("Delete pair %d at depth %d", current_pair->num, current_pair->depth);
-      if (current_pair->prop_state_->type == 1)
-        this->remove_acceptance_pair(current_pair->num);
-    }
-  }
-}
-
-void LivenessChecker::run()
-{
-  XBT_INFO("Check the liveness property %s", _sg_mc_property_file.get().c_str());
-  automaton_load(_sg_mc_property_file.get().c_str());
-
-  XBT_DEBUG("Starting the liveness algorithm");
-
-  /* Initialize */
-  this->previous_pair_ = 0;
-
-  std::shared_ptr<const std::vector<int>> propos = this->get_proposition_values();
-
-  // For each initial state of the property automaton, push a
-  // (application_state, automaton_state) pair to the exploration stack:
-  auto automaton_stack = get_automaton_state();
-  for (auto* automaton_state : automaton_stack) {
-    if (automaton_state->type == -1)
-      exploration_stack_.push_back(this->create_pair(nullptr, automaton_state, propos));
-  }
-
-  /* Actually run the double DFS search for counter-examples */
-  while (not exploration_stack_.empty()) {
-    std::shared_ptr<Pair> current_pair = exploration_stack_.back();
-
-    /* Update current state in buchi automaton */
-    set_property_automaton(current_pair->prop_state_);
-
-    XBT_DEBUG(
-        "********************* ( Depth = %d, search_cycle = %d, interleave size = %zu, pair_num = %d, requests = %d)",
-        current_pair->depth, current_pair->search_cycle, current_pair->app_state_->count_todo(), current_pair->num,
-        current_pair->requests);
-
-    if (current_pair->requests == 0) {
-      this->backtrack();
-      continue;
-    }
-
-    std::shared_ptr<VisitedPair> reached_pair;
-    if (current_pair->prop_state_->type == 1 && not current_pair->exploration_started) {
-      reached_pair = this->insert_acceptance_pair(current_pair.get());
-      if (reached_pair == nullptr) {
-        this->show_acceptance_cycle(current_pair->depth);
-        throw LivenessError();
-      }
-    }
-
-    /* Pair already visited ? stop the exploration on the current path */
-    if (not current_pair->exploration_started) {
-      int visited_num = this->insert_visited_pair(reached_pair, current_pair.get());
-      if (visited_num != -1) {
-        dot_output("\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, visited_num, this->previous_request_.c_str());
-
-        XBT_DEBUG("Pair already visited (equal to pair %d), exploration on the current path stopped.", visited_num);
-        current_pair->requests = 0;
-        this->backtrack();
-        continue;
-      }
-    }
-
-    current_pair->app_state_->execute_next(current_pair->app_state_->next_transition(), get_remote_app());
-    XBT_DEBUG("Execute: %s", current_pair->app_state_->get_transition()->to_string().c_str());
-
-    /* Update the dot output */
-    if (this->previous_pair_ != 0 && this->previous_pair_ != current_pair->num) {
-      dot_output("\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, current_pair->num, this->previous_request_.c_str());
-      this->previous_request_.clear();
-    }
-    this->previous_pair_    = current_pair->num;
-    this->previous_request_ = current_pair->app_state_->get_transition()->dot_string();
-    if (current_pair->search_cycle)
-      dot_output("%d [shape=doublecircle];\n", current_pair->num);
-
-    if (not current_pair->exploration_started)
-      visited_pairs_count_++;
-
-    current_pair->requests--;
-    current_pair->exploration_started = true;
-
-    /* Get values of atomic propositions (variables used in the property formula) */
-    std::shared_ptr<const std::vector<int>> prop_values = this->get_proposition_values();
-
-    // For each enabled transition in the property automaton, push a
-    // (application_state, automaton_state) pair to the exploration stack:
-    for (int i = xbt_dynar_length(current_pair->prop_state_->out) - 1; i >= 0; i--) {
-      const auto* transition_succ_label = get_automaton_transition_label(current_pair->prop_state_->out, i);
-      auto* transition_succ_dst         = get_automaton_transition_dst(current_pair->prop_state_->out, i);
-      if (evaluate_label(transition_succ_label, *prop_values))
-        exploration_stack_.push_back(this->create_pair(current_pair.get(), transition_succ_dst, prop_values));
-    }
-  }
-
-  XBT_INFO("No property violation found.");
-  log_state();
-}
-
-Exploration* create_liveness_checker(const std::vector<char*>& args)
-{
-  return new LivenessChecker(args);
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/explo/LivenessChecker.hpp b/src/mc/explo/LivenessChecker.hpp
deleted file mode 100644 (file)
index 532f639..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_LIVENESS_CHECKER_HPP
-#define SIMGRID_MC_LIVENESS_CHECKER_HPP
-
-#include "src/mc/api/State.hpp"
-#include "src/mc/explo/Exploration.hpp"
-#include "xbt/automaton.hpp"
-
-#include <list>
-#include <memory>
-#include <vector>
-
-namespace simgrid::mc {
-
-class XBT_PRIVATE Pair {
-public:
-  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;
-  bool exploration_started = false;
-
-  explicit Pair(unsigned long expanded_pairs);
-
-  Pair(Pair const&) = delete;
-  Pair& operator=(Pair const&) = delete;
-};
-
-class XBT_PRIVATE VisitedPair {
-public:
-  int num;
-  int other_num                      = 0;       /* Dot output for */
-  std::shared_ptr<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 actor_count_;
-
-  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,
-              RemoteApp& remote_app);
-};
-
-class XBT_PRIVATE LivenessChecker : public Exploration {
-public:
-  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;
-  void log_state() override;
-
-private:
-  std::shared_ptr<const std::vector<int>> get_proposition_values() const;
-  std::shared_ptr<VisitedPair> insert_acceptance_pair(Pair* pair);
-  int insert_visited_pair(std::shared_ptr<VisitedPair> visited_pair, Pair* pair);
-  void show_acceptance_cycle(std::size_t depth);
-  void replay();
-  void remove_acceptance_pair(int pair_num);
-  void purge_visited_pairs();
-  void backtrack();
-  std::shared_ptr<Pair> create_pair(const Pair* pair, xbt_automaton_state_t state,
-                                    std::shared_ptr<const std::vector<int>> propositions);
-
-  // A stack of (application_state, automaton_state) pairs for DFS exploration:
-  std::list<std::shared_ptr<Pair>> exploration_stack_;
-  std::list<std::shared_ptr<VisitedPair>> acceptance_pairs_;
-  std::list<std::shared_ptr<VisitedPair>> visited_pairs_;
-  unsigned long visited_pairs_count_  = 0;
-  unsigned long expanded_pairs_count_ = 0;
-  int previous_pair_                  = 0;
-  std::string previous_request_;
-
-  /* The property automaton must be a static because it's sometimes used before the explorer is even created.
-   *
-   * This can happen if some symbols are created during the application's initialization process, before the first
-   * decision point for the model-checker. Since the first snapshot is taken at the first decision point and since the
-   * explorer is created after the first snapshot, this may result in some symbols being registered even before the
-   * model-checker notices that this is a LivenessChecker to create.
-   *
-   * This situation is unfortunate, but I guess that it's the best I can achieve given the state of our initialization
-   * code.
-   */
-  static xbt_automaton_t property_automaton_;
-  bool evaluate_label(const xbt_automaton_exp_label* l, std::vector<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(RemoteProcessMemory const& remote_process, const char* name,
-                                        RemotePtr<int> addr);
-};
-
-} // namespace simgrid::mc
-
-#endif
index 98bab5e..f5c512f 100644 (file)
@@ -6,46 +6,44 @@
 #include "src/mc/explo/UdporChecker.hpp"
 #include "src/mc/api/State.hpp"
 #include "src/mc/explo/udpor/Comb.hpp"
+#include "src/mc/explo/udpor/ExtensionSetCalculator.hpp"
 #include "src/mc/explo/udpor/History.hpp"
 #include "src/mc/explo/udpor/maximal_subsets_iterator.hpp"
 
+#include <numeric>
 #include <xbt/asserts.h>
 #include <xbt/log.h>
+#include <xbt/string.hpp>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_udpor, mc, "Logging specific to verification using UDPOR");
 
 namespace simgrid::mc::udpor {
 
-UdporChecker::UdporChecker(const std::vector<char*>& args) : Exploration(args, true)
-{
-  // Initialize the map
-}
+UdporChecker::UdporChecker(const std::vector<char*>& args) : Exploration(args) {}
 
 void UdporChecker::run()
 {
   XBT_INFO("Starting a UDPOR exploration");
-  // NOTE: `A`, `D`, and `C` are derived from the
-  // original UDPOR paper [1], while `prev_exC` arises
-  // from the incremental computation of ex(C) from [3]
-  Configuration C_root;
-
-  // TODO: Move computing the root configuration into a method on the Unfolding
-  auto initial_state      = get_current_state();
-  auto root_event         = std::make_unique<UnfoldingEvent>(EventSet(), std::make_shared<Transition>());
-  auto* root_event_handle = root_event.get();
-  unfolding.insert(std::move(root_event));
-  C_root.add_event(root_event_handle);
-
-  explore(C_root, EventSet(), EventSet(), std::move(initial_state), EventSet());
-
+  state_stack.clear();
+  state_stack.push_back(get_current_state());
+  explore(Configuration(), EventSet(), EventSet(), EventSet());
   XBT_INFO("UDPOR exploration terminated -- model checking completed");
 }
 
-void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A, std::unique_ptr<State> stateC,
-                           EventSet prev_exC)
+void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A, EventSet prev_exC)
 {
-  auto exC       = compute_exC(C, *stateC, prev_exC);
+  auto& stateC   = *state_stack.back();
+  auto exC       = compute_exC(C, stateC, prev_exC);
   const auto enC = compute_enC(C, exC);
+  XBT_DEBUG("explore(C, D, A) with:\n"
+            "C\t := %s \n"
+            "D\t := %s \n"
+            "A\t := %s \n"
+            "ex(C)\t := %s \n"
+            "en(C)\t := %s \n",
+            C.to_string().c_str(), D.to_string().c_str(), A.to_string().c_str(), exC.to_string().c_str(),
+            enC.to_string().c_str());
+  XBT_DEBUG("ex(C) has %zu elements, of which %zu are in en(C)", exC.size(), enC.size());
 
   // If enC is a subset of D, intuitively
   // there aren't any enabled transitions
@@ -53,9 +51,10 @@ void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A, std::
   // exploration would lead to a so-called
   // "sleep-set blocked" trace.
   if (enC.is_subset_of(D)) {
-    if (not C.get_events().empty()) {
-      // Report information...
-    }
+    XBT_DEBUG("en(C) is a subset of the sleep set D (size %zu); if we "
+              "kept exploring, we'd hit a sleep-set blocked trace",
+              D.size());
+    XBT_DEBUG("The current configuration has %zu elements", C.get_events().size());
 
     // When `en(C)` is empty, intuitively this means that there
     // are no enabled transitions that can be executed from the
@@ -65,23 +64,24 @@ void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A, std::
     // possibility is that we've finished running everything, and
     // we wouldn't be in deadlock then)
     if (enC.empty()) {
+      XBT_VERB("**************************");
+      XBT_VERB("*** TRACE INVESTIGATED ***");
+      XBT_VERB("**************************");
+      XBT_VERB("Execution sequence:");
+      for (auto const& s : get_textual_trace())
+        XBT_VERB("  %s", s.c_str());
       get_remote_app().check_deadlock();
     }
 
     return;
   }
-
-  // TODO: Add verbose logging about which event is being explored
-
-  const UnfoldingEvent* e = select_next_unfolding_event(A, enC);
+  UnfoldingEvent* e = select_next_unfolding_event(A, enC);
   xbt_assert(e != nullptr, "\n\n****** INVARIANT VIOLATION ******\n"
                            "UDPOR guarantees that an event will be chosen at each point in\n"
                            "the search, yet no events were actually chosen\n"
                            "*********************************\n\n");
-
-  // Move the application into stateCe and make note of that state
-  move_to_stateCe(*stateC, *e);
-  auto stateCe = record_current_state();
+  XBT_DEBUG("Selected event `%s` (%zu dependencies) to extend the configuration", e->to_string().c_str(),
+            e->get_immediate_causes().size());
 
   // Ce := C + {e}
   Configuration Ce = C;
@@ -91,22 +91,48 @@ void UdporChecker::explore(const Configuration& C, EventSet D, EventSet A, std::
   exC.remove(e);
 
   // Explore(C + {e}, D, A \ {e})
-  explore(Ce, D, std::move(A), std::move(stateCe), std::move(exC));
+
+  // Move the application into stateCe (i.e. `state(C + {e})`) and make note of that state
+  move_to_stateCe(&stateC, e);
+  state_stack.push_back(record_current_state());
+
+  explore(Ce, D, std::move(A), std::move(exC));
+
+  // Prepare to move the application back one state.
+  // We need only remove the state from the stack here: if we perform
+  // another `Explore()` after computing an alternative, at that
+  // point we'll actually create a fresh RemoteProcess
+  state_stack.pop_back();
 
   // D <-- D + {e}
   D.insert(e);
 
-  constexpr unsigned K = 10;
-  if (auto J = C.compute_k_partial_alternative_to(D, this->unfolding, K); J.has_value()) {
+  XBT_DEBUG("Checking for the existence of an alternative...");
+  if (auto J = C.compute_alternative_to(D, this->unfolding); J.has_value()) {
     // Before searching the "right half", we need to make
     // sure the program actually reflects the fact
-    // that we are searching again from `stateC` (the recursive
-    // search moved the program into `stateCe`)
-    restore_program_state_to(*stateC);
+    // that we are searching again from `state(C)`. While the
+    // stack of states is properly adjusted to represent
+    // `state(C)` all together, the RemoteApp is currently sitting
+    // at some *future* state with respect to `state(C)` since the
+    // recursive calls had moved it there.
+    restore_program_state_with_current_stack();
 
     // Explore(C, D + {e}, J \ C)
     auto J_minus_C = J.value().get_events().subtracting(C.get_events());
-    explore(C, D, std::move(J_minus_C), std::move(stateC), std::move(prev_exC));
+
+    XBT_DEBUG("Alternative detected! The alternative is:\n"
+              "J\t := %s \n"
+              "J / C := %s\n"
+              "UDPOR is going to explore it...",
+              J.value().to_string().c_str(), J_minus_C.to_string().c_str());
+    explore(C, D, std::move(J_minus_C), std::move(prev_exC));
+  } else {
+    XBT_DEBUG("No alternative detected with:\n"
+              "C\t := %s \n"
+              "D\t := %s \n"
+              "A\t := %s \n",
+              C.to_string().c_str(), D.to_string().c_str(), A.to_string().c_str());
   }
 
   // D <-- D - {e}
@@ -129,67 +155,41 @@ EventSet UdporChecker::compute_exC(const Configuration& C, const State& stateC,
   EventSet exC                = prev_exC;
   exC.remove(e_cur);
 
+  // IMPORTANT NOTE: In order to have deterministic results, we need to process
+  // the actors in a deterministic manner so that events are discovered by
+  // UDPOR in a deterministic order. The processing done here always processes
+  // actors in a consistent order since `std::map` is by-default ordered using
+  // `std::less<Key>` (see the return type of `State::get_actors_list()`)
   for (const auto& [aid, actor_state] : stateC.get_actors_list()) {
-    for (const auto& transition : actor_state.get_enabled_transitions()) {
-      // First check for a specialized function that can compute the extension
-      // set "quickly" based on its type. Otherwise, fall back to computing
-      // the set "by hand"
-      const auto specialized_extension_function = incremental_extension_functions.find(transition->type_);
-      if (specialized_extension_function != incremental_extension_functions.end()) {
-        exC.form_union((specialized_extension_function->second)(C, transition));
-      } else {
-        exC.form_union(this->compute_exC_by_enumeration(C, transition));
+    const auto& enabled_transitions = actor_state.get_enabled_transitions();
+    if (enabled_transitions.empty()) {
+      XBT_DEBUG("\t Actor `%ld` is disabled: no partial extensions need to be considered", aid);
+    } else {
+      XBT_DEBUG("\t Actor `%ld` is enabled", aid);
+      for (const auto& transition : enabled_transitions) {
+        XBT_DEBUG("\t Considering partial extension for %s", transition->to_string().c_str());
+        EventSet extension = ExtensionSetCalculator::partially_extend(C, &unfolding, transition);
+        exC.form_union(extension);
       }
     }
   }
   return exC;
 }
 
-EventSet UdporChecker::compute_exC_by_enumeration(const Configuration& C, const std::shared_ptr<Transition> action)
-{
-  // Here we're computing the following:
-  //
-  // U{<a, K> : K is maximal, `a` depends on all of K, `a` enabled at config(K) }
-  //
-  // where `a` is the `action` given to us. Note that `a` is presumed to be enabled
-  EventSet incremental_exC;
-
-  for (auto begin =
-           maximal_subsets_iterator(C, {[&](const UnfoldingEvent* e) { return e->is_dependent_with(action.get()); }});
-       begin != maximal_subsets_iterator(); ++begin) {
-    const EventSet& maximal_subset = *begin;
-
-    // Determining if `a` is enabled here might not be possible while looking at `a` opaquely
-    // We leave the implementation as-is to ensure that any addition would be simple
-    // if it were ever added
-    const bool enabled_at_config_k = false;
-
-    if (enabled_at_config_k) {
-      auto candidate_handle = std::make_unique<UnfoldingEvent>(maximal_subset, action);
-      if (auto candidate_event = candidate_handle.get(); not unfolding.contains_event_equivalent_to(candidate_event)) {
-        // This is a new event (i.e. one we haven't yet seen)
-        unfolding.insert(std::move(candidate_handle));
-        incremental_exC.insert(candidate_event);
-      }
-    }
-  }
-  return incremental_exC;
-}
-
 EventSet UdporChecker::compute_enC(const Configuration& C, const EventSet& exC) const
 {
   EventSet enC;
-  for (const auto e : exC) {
-    if (not e->conflicts_with(C)) {
+  for (const auto* e : exC) {
+    if (C.is_compatible_with(e)) {
       enC.insert(e);
     }
   }
   return enC;
 }
 
-void UdporChecker::move_to_stateCe(State& state, const UnfoldingEvent& e)
+void UdporChecker::move_to_stateCe(State* state, UnfoldingEvent* e)
 {
-  const aid_t next_actor = e.get_transition()->aid_;
+  const aid_t next_actor = e->get_transition()->aid_;
 
   // TODO: Add the trace if possible for reporting a bug
   xbt_assert(next_actor >= 0, "\n\n****** INVARIANT VIOLATION ******\n"
@@ -197,15 +197,41 @@ void UdporChecker::move_to_stateCe(State& state, const UnfoldingEvent& e)
                               "one transition of the state of an visited event is enabled, yet no\n"
                               "state was actually enabled. Please report this as a bug.\n"
                               "*********************************\n\n");
-  state.execute_next(next_actor, get_remote_app());
+  auto latest_transition_by_next_actor = state->execute_next(next_actor, get_remote_app());
+
+  // The transition that is associated with the event was just
+  // executed, so it's possible that the new version of the transition
+  // (i.e. the one after execution) has *more* information than
+  // that which existed *prior* to execution.
+  //
+  //
+  // ------- !!!!! UDPOR INVARIANT !!!!! -------
+  //
+  // At this point, we are leveraging the fact that
+  // UDPOR will not contain more than one copy of any
+  // transition executed by any actor for any
+  // particular step taken by that actor. That is,
+  // if transition `i` of the `j`th actor is contained in the
+  // configuration `C` currently under consideration
+  // by UDPOR, then only one and only one copy exists in `C`
+  //
+  // This means that we can referesh the transitions associated
+  // with each event lazily, i.e. only after we have chosen the
+  // event to continue our execution.
+  e->set_transition(std::move(latest_transition_by_next_actor));
 }
 
-void UdporChecker::restore_program_state_to(const State& stateC)
+void UdporChecker::restore_program_state_with_current_stack()
 {
+  XBT_DEBUG("Restoring state using the current stack");
   get_remote_app().restore_initial_state();
-  // TODO: We need to have the stack of past states available at this
-  // point. Since the method is recursive, we'll need to keep track of
-  // this as we progress
+
+  /* Traverse the stack from the state at position start and re-execute the transitions */
+  for (const std::unique_ptr<State>& state : state_stack) {
+    if (state == state_stack.back()) /* If we are arrived on the target state, don't replay the outgoing transition */
+      break;
+    state->get_transition_out()->replay(get_remote_app());
+  }
 }
 
 std::unique_ptr<State> UdporChecker::record_current_state()
@@ -218,53 +244,110 @@ std::unique_ptr<State> UdporChecker::record_current_state()
   return next_state;
 }
 
-const UnfoldingEvent* UdporChecker::select_next_unfolding_event(const EventSet& A, const EventSet& enC)
+UnfoldingEvent* UdporChecker::select_next_unfolding_event(const EventSet& A, const EventSet& enC)
 {
-  if (!enC.empty()) {
-    return *(enC.begin());
+  if (enC.empty()) {
+    throw std::invalid_argument("There are no unfolding events to select. "
+                                "Are you sure that you checked that en(C) was not "
+                                "empty before attempting to select an event from it?");
   }
 
-  for (const auto& event : A) {
-    if (enC.contains(event)) {
-      return event;
-    }
+  // UDPOR's exploration is non-deterministic (as is DPOR's)
+  // in the sense that at any given point there may
+  // be multiple paths that can be followed. The correctness and optimality
+  // of the algorithm remains unaffected by the route taken by UDPOR when
+  // given multiple choices; but to ensure that SimGrid itself has deterministic
+  // behavior on all platforms, we always pick events with lower id's
+  // to ensure we explore the unfolding deterministically.
+  if (A.empty()) {
+    const auto min_event = std::min_element(enC.begin(), enC.end(),
+                                            [](const auto e1, const auto e2) { return e1->get_id() < e2->get_id(); });
+    return const_cast<UnfoldingEvent*>(*min_event);
+  } else {
+    const auto intersection = A.make_intersection(enC);
+    const auto min_event    = std::min_element(intersection.begin(), intersection.end(),
+                                               [](const auto e1, const auto e2) { return e1->get_id() < e2->get_id(); });
+    return const_cast<UnfoldingEvent*>(*min_event);
   }
-  return nullptr;
 }
 
 void UdporChecker::clean_up_explore(const UnfoldingEvent* e, const Configuration& C, const EventSet& D)
 {
-  const EventSet C_union_D              = C.get_events().make_union(D);
-  const EventSet es_immediate_conflicts = this->unfolding.get_immediate_conflicts_of(e);
-  const EventSet Q_CDU                  = C_union_D.make_union(es_immediate_conflicts.get_local_config());
+  // The "clean-up set" conceptually represents
+  // those events which will no longer be considered
+  // by UDPOR during its exploration. The concept is
+  // introduced to avoid modification during iteration
+  // over the current unfolding to determine who needs to
+  // be removed. Since sets are unordered, it's quite possible
+  // that e.g. two events `e` and `e'` such that `e < e'`
+  // which are determined eligible for removal are removed
+  // in the order `e` and then `e'`. Determining that `e'`
+  // needs to be removed requires that its history be in
+  // tact to e.g. compute the conflicts with the event.
+  //
+  // Thus, we compute the set and remove all of the events
+  // at once in lieu of removing events while iterating over them.
+  // We can hypothesize that processing the events in reverse
+  // topological order would prevent any issues concerning
+  // the order in which are processed
+  EventSet clean_up_set;
+
+  // Q_(C, D, U) = C u D u U (complicated expression)
+  // See page 9 of "Unfolding-based Partial Order Reduction"
+
+  // "C u D" portion
+  const EventSet C_union_D = C.get_events().make_union(D);
+
+  // "U (complicated expression)" portion
+  const EventSet conflict_union = std::accumulate(
+      C_union_D.begin(), C_union_D.end(), EventSet(), [&](const EventSet& acc, const UnfoldingEvent* e_prime) {
+        return acc.make_union(unfolding.get_immediate_conflicts_of(e_prime));
+      });
+
+  const EventSet Q_CDU = C_union_D.make_union(conflict_union.get_local_config());
+
+  XBT_DEBUG("Computed Q_CDU as '%s'", Q_CDU.to_string().c_str());
 
   // Move {e} \ Q_CDU from U to G
-  if (Q_CDU.contains(e)) {
-    this->unfolding.remove(e);
+  if (not Q_CDU.contains(e)) {
+    XBT_DEBUG("Moving %s from U to G...", e->to_string().c_str());
+    clean_up_set.insert(e);
   }
 
   // foreach ê in #ⁱ_U(e)
-  for (const auto* e_hat : es_immediate_conflicts) {
+  for (const auto* e_hat : this->unfolding.get_immediate_conflicts_of(e)) {
     // Move [ê] \ Q_CDU from U to G
-    const EventSet to_remove = e_hat->get_history().subtracting(Q_CDU);
-    this->unfolding.remove(to_remove);
+    const EventSet to_remove = e_hat->get_local_config().subtracting(Q_CDU);
+    XBT_DEBUG("Moving {%s} from U to G...", to_remove.to_string().c_str());
+    clean_up_set.form_union(to_remove);
   }
+
+  // TODO: We still perhaps need to
+  // figure out how to deal with the fact that the previous
+  // extension sets computed for past configurations
+  // contain events that may be removed from `U`. Perhaps
+  // it would be best to keep them around forever (they
+  // are moved to `G` after all and can be discarded at will,
+  // which means they may never have to be removed at all).
+  //
+  // Of course, the benefit of moving them into the set `G`
+  // is that the computation for immediate conflicts becomes
+  // more efficient (we have to search all of `U` for such conflicts,
+  // and there would be no reason to search those events
+  // that UDPOR has marked as no longer being important)
+  // For now, there appear to be no "obvious" issues (although
+  // UDPOR's behavior is often far from obvious...)
+  this->unfolding.mark_finished(clean_up_set);
 }
 
 RecordTrace UdporChecker::get_record_trace()
 {
   RecordTrace res;
+  for (auto const& state : state_stack)
+    res.push_back(state->get_transition_out().get());
   return res;
 }
 
-std::vector<std::string> UdporChecker::get_textual_trace()
-{
-  // TODO: Topologically sort the events of the latest configuration
-  // and iterate through that topological sorting
-  std::vector<std::string> trace;
-  return trace;
-}
-
 } // namespace simgrid::mc::udpor
 
 namespace simgrid::mc {
index 6214039..02f2a8e 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef SIMGRID_MC_UDPOR_CHECKER_HPP
 #define SIMGRID_MC_UDPOR_CHECKER_HPP
 
+#include "src/mc/api/State.hpp"
 #include "src/mc/explo/Exploration.hpp"
 #include "src/mc/explo/udpor/Configuration.hpp"
 #include "src/mc/explo/udpor/EventSet.hpp"
@@ -15,6 +16,7 @@
 #include "src/mc/mc_record.hpp"
 
 #include <functional>
+#include <list>
 #include <optional>
 
 namespace simgrid::mc::udpor {
@@ -37,20 +39,14 @@ public:
 
   void run() override;
   RecordTrace get_record_trace() override;
-  std::vector<std::string> get_textual_trace() override;
-
-  inline std::unique_ptr<State> get_current_state() { return std::make_unique<State>(get_remote_app()); }
+  std::unique_ptr<State> get_current_state() { return std::make_unique<State>(get_remote_app()); }
 
 private:
   Unfolding unfolding = Unfolding();
 
-  /**
-   * @brief A collection of specialized functions which can incrementally
-   * compute the extension of a configuration based on the action taken
-   */
-  using ExtensionFunction = std::function<EventSet(const Configuration&, const std::shared_ptr<Transition>)>;
-  std::unordered_map<Transition::Type, ExtensionFunction> incremental_extension_functions =
-      std::unordered_map<Transition::Type, ExtensionFunction>();
+  // The current sequence of states that the checker has
+  // visited in order to reach the current configuration
+  std::list<std::unique_ptr<State>> state_stack;
 
   /**
    * @brief Explores the unfolding of the concurrent system
@@ -67,13 +63,11 @@ private:
    * @param A the set of events to "guide" UDPOR in the correct direction
    * when it returns back to a node in the unfolding and must decide among
    * events to select from `ex(C)`. See [1] for more details
-   * @param stateC the state of the program after having executed `C`,
-   * viz. `state(C)`  using the notation of [1]
    *
    * TODO: Add the optimization where we can check if e == e_prior
    * to prevent repeated work when computing ex(C)
    */
-  void explore(const Configuration& C, EventSet D, EventSet A, std::unique_ptr<State> stateC, EventSet prev_exC);
+  void explore(const Configuration& C, EventSet D, EventSet A, EventSet prev_exC);
 
   /**
    * @brief Identifies the next event from the unfolding of the concurrent system
@@ -87,7 +81,7 @@ private:
    * by the UDPOR algorithm to select new events to search. See the original
    * paper [1] for more details
    */
-  const UnfoldingEvent* select_next_unfolding_event(const EventSet& A, const EventSet& enC);
+  UnfoldingEvent* select_next_unfolding_event(const EventSet& A, const EventSet& enC);
 
   /**
    * @brief Computes the sets `ex(C)` and `en(C)` of the given configuration
@@ -114,38 +108,43 @@ private:
    * @returns the extension set `ex(C)` of `C`
    */
   EventSet compute_exC(const Configuration& C, const State& stateC, const EventSet& prev_exC);
-
-  /**
-   * @brief Computes a portion of the extension set of a configuration given
-   * some action `action` by directly enumerating all maximal subsets of C
-   * (i.e. without specializations based on the action)
-   */
-  EventSet compute_exC_by_enumeration(const Configuration& C, const std::shared_ptr<Transition> action);
-
   EventSet compute_enC(const Configuration& C, const EventSet& exC) const;
 
   /**
    *
    */
-  void move_to_stateCe(State& stateC, const UnfoldingEvent& e);
+  void move_to_stateCe(State* stateC, UnfoldingEvent* e);
 
   /**
-   * @brief Creates a new snapshot of the state of the progam undergoing
-   * model checking
-   *
-   * @returns the handle used to uniquely identify this state later in the
-   * exploration of the unfolding. You provide this handle to an event in the
-   * unfolding to regenerate past states
+   * @brief Creates a new snapshot of the state of the application
+   * as it currently looks
    */
   std::unique_ptr<State> record_current_state();
 
   /**
+   * @brief Move the application side into the state at the top of the
+   * state stack provided
+   *
+   * As UDPOR performs its search, it moves the application-side along with
+   * it so that the application is always providing the checker with
+   * the correct information about what each actor is running (and whether
+   * those actors are enabled) at the state reached by the configuration it
+   * decides to search.
    *
+   * When UDPOR decides to "backtrack" (e.g. after reaching a configuration
+   * whose en(C) is empty), before it attempts to continue the search by taking
+   * a different path from a configuration it visited in the past, it must ensure
+   * that the application-side has moved back into `state(C)`.
+   *
+   * The search may have moved the application arbitrarily deep into its execution,
+   * and the search may backtrack arbitrarily closer to the beginning of the execution.
+   * The UDPOR implementation in SimGrid ensures that the stack is updated appropriately,
+   * but the process must still be regenerated.
    */
-  void restore_program_state_to(const State& stateC);
+  void restore_program_state_with_current_stack();
 
   /**
-   *
+   * @brief Perform the functionality of the `Remove(e, C, D)` function in [1]
    */
   void clean_up_explore(const UnfoldingEvent* e, const Configuration& C, const EventSet& D);
 };
diff --git a/src/mc/explo/odpor/ClockVector_test.cpp b/src/mc/explo/odpor/ClockVector_test.cpp
new file mode 100644 (file)
index 0000000..9d49c60
--- /dev/null
@@ -0,0 +1,366 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.               */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/3rd-party/catch.hpp"
+#include "src/mc/api/ClockVector.hpp"
+
+using namespace simgrid::mc;
+
+TEST_CASE("simgrid::mc::ClockVector: Constructing Vectors")
+{
+  SECTION("Without values")
+  {
+    ClockVector cv;
+    REQUIRE(cv.size() == 0);
+
+    // Verify `cv` doesn't map any values
+    REQUIRE_FALSE(cv.get(0).has_value());
+    REQUIRE_FALSE(cv.get(1).has_value());
+    REQUIRE_FALSE(cv.get(2).has_value());
+    REQUIRE_FALSE(cv.get(3).has_value());
+  }
+
+  SECTION("With initial values")
+  {
+    ClockVector cv{
+        {1, 5}, {3, 1}, {7, 10}, {6, 5}, {8, 1}, {10, 10},
+    };
+    REQUIRE(cv.size() == 6);
+
+    // Verify `cv` maps each value
+    REQUIRE(cv.get(1).has_value());
+    REQUIRE(cv.get(1).value() == 5);
+    REQUIRE(cv[1] == 5);
+    REQUIRE(cv.get(3).has_value());
+    REQUIRE(cv.get(3).value() == 1);
+    REQUIRE(cv[3] == 1);
+    REQUIRE(cv.get(7).has_value());
+    REQUIRE(cv.get(7).value() == 10);
+    REQUIRE(cv[7] == 10);
+    REQUIRE(cv.get(6).has_value());
+    REQUIRE(cv.get(6).value() == 5);
+    REQUIRE(cv[6] == 5);
+    REQUIRE(cv.get(8).has_value());
+    REQUIRE(cv.get(8).value() == 1);
+    REQUIRE(cv[8] == 1);
+    REQUIRE(cv.get(10).has_value());
+    REQUIRE(cv.get(10).value() == 10);
+    REQUIRE(cv[10] == 10);
+  }
+}
+
+TEST_CASE("simgrid::mc::ClockVector: Testing operator[]")
+{
+  ClockVector cv;
+  cv[0] = 1;
+  REQUIRE(cv.size() == 1);
+
+  REQUIRE(cv.get(0).has_value());
+  REQUIRE(cv.get(0).value() == 1);
+
+  // Verify `cv` doesn't map other values
+  REQUIRE_FALSE(cv.get(2).has_value());
+  REQUIRE_FALSE(cv.get(3).has_value());
+
+  cv[10] = 31;
+  REQUIRE(cv.size() == 2);
+
+  // Old values are still mapped
+  REQUIRE(cv.get(0).has_value());
+  REQUIRE(cv.get(0).value() == 1);
+  REQUIRE(cv[0] == 1);
+  REQUIRE(cv.get(10).has_value());
+  REQUIRE(cv.get(10).value() == 31);
+  REQUIRE(cv[10] == 31);
+
+  // Verify `cv` doesn't map other values
+  REQUIRE_FALSE(cv.get(2).has_value());
+  REQUIRE_FALSE(cv.get(3).has_value());
+}
+
+TEST_CASE("simgrid::mc::ClockVector: Testing Maximal Clock Vectors")
+{
+  SECTION("Max with zero clock vector yields self")
+  {
+    ClockVector cv1{
+        {1, 2},
+        {2, 10},
+        {3, 5},
+    };
+    ClockVector cv2;
+    ClockVector maxCV = ClockVector::max(cv1, cv2);
+
+    REQUIRE(maxCV.size() == 3);
+    REQUIRE(maxCV.get(1).has_value());
+    REQUIRE(maxCV.get(1).value() == 2);
+    REQUIRE(maxCV[1] == 2);
+
+    REQUIRE(maxCV.get(2).has_value());
+    REQUIRE(maxCV.get(2).value() == 10);
+    REQUIRE(maxCV[2] == 10);
+
+    REQUIRE(maxCV.get(3).has_value());
+    REQUIRE(maxCV.get(3).value() == 5);
+    REQUIRE(maxCV[3] == 5);
+  }
+
+  SECTION("Max with self clock vector yields self")
+  {
+    ClockVector cv1{
+        {1, 2},
+        {2, 10},
+        {3, 5},
+    };
+    ClockVector maxCV = ClockVector::max(cv1, cv1);
+
+    REQUIRE(maxCV.size() == 3);
+    REQUIRE(maxCV.get(1).has_value());
+    REQUIRE(maxCV.get(1).value() == 2);
+    REQUIRE(maxCV[1] == 2);
+
+    REQUIRE(maxCV.get(2).has_value());
+    REQUIRE(maxCV.get(2).value() == 10);
+    REQUIRE(maxCV[2] == 10);
+
+    REQUIRE(maxCV.get(3).has_value());
+    REQUIRE(maxCV.get(3).value() == 5);
+    REQUIRE(maxCV[3] == 5);
+  }
+
+  SECTION("Testing with partial overlaps")
+  {
+    SECTION("Example 1")
+    {
+      ClockVector cv1{
+          {1, 2},
+          {2, 10},
+          {3, 5},
+      };
+      ClockVector cv2{
+          {1, 5},
+          {3, 1},
+          {7, 10},
+      };
+      ClockVector maxCV = ClockVector::max(cv1, cv2);
+
+      REQUIRE(maxCV.size() == 4);
+      REQUIRE(maxCV.get(1).has_value());
+      REQUIRE(maxCV.get(1).value() == 5);
+      REQUIRE(maxCV[1] == 5);
+
+      REQUIRE(maxCV.get(2).has_value());
+      REQUIRE(maxCV.get(2).value() == 10);
+      REQUIRE(maxCV[2] == 10);
+
+      REQUIRE(maxCV.get(3).has_value());
+      REQUIRE(maxCV.get(3).value() == 5);
+      REQUIRE(maxCV[3] == 5);
+
+      REQUIRE(maxCV.get(7).has_value());
+      REQUIRE(maxCV.get(7).value() == 10);
+      REQUIRE(maxCV[7] == 10);
+    }
+
+    SECTION("Example 2")
+    {
+      ClockVector cv1{
+          {1, 2}, {2, 10}, {3, 5}, {4, 40}, {11, 3}, {12, 8},
+      };
+      ClockVector cv2{
+          {1, 18}, {2, 4}, {4, 41}, {10, 3}, {12, 8},
+      };
+      ClockVector maxCV = ClockVector::max(cv1, cv2);
+
+      REQUIRE(maxCV.size() == 7);
+      REQUIRE(maxCV.get(1).has_value());
+      REQUIRE(maxCV.get(1).value() == 18);
+      REQUIRE(maxCV[1] == 18);
+
+      REQUIRE(maxCV.get(2).has_value());
+      REQUIRE(maxCV.get(2).value() == 10);
+      REQUIRE(maxCV[2] == 10);
+
+      REQUIRE(maxCV.get(3).has_value());
+      REQUIRE(maxCV.get(3).value() == 5);
+      REQUIRE(maxCV[3] == 5);
+
+      REQUIRE(maxCV.get(4).has_value());
+      REQUIRE(maxCV.get(4).value() == 41);
+      REQUIRE(maxCV[4] == 41);
+
+      REQUIRE(maxCV.get(10).has_value());
+      REQUIRE(maxCV.get(10).value() == 3);
+      REQUIRE(maxCV[10] == 3);
+
+      REQUIRE(maxCV.get(11).has_value());
+      REQUIRE(maxCV.get(11).value() == 3);
+      REQUIRE(maxCV[11] == 3);
+
+      REQUIRE(maxCV.get(12).has_value());
+      REQUIRE(maxCV.get(12).value() == 8);
+      REQUIRE(maxCV[12] == 8);
+    }
+
+    SECTION("Example 3")
+    {
+      ClockVector cv1{{1, 2}, {4, 41}, {12, 0}, {100, 5}};
+      ClockVector cv2{{2, 4}, {4, 10}, {10, 3}, {12, 8}, {19, 0}, {21, 6}, {22, 0}};
+      ClockVector cv3{{21, 60}, {22, 6}, {100, 3}};
+      ClockVector maxCV = ClockVector::max(cv1, cv2);
+      maxCV             = ClockVector::max(maxCV, cv3);
+
+      REQUIRE(maxCV.size() == 9);
+      REQUIRE(maxCV.get(1).has_value());
+      REQUIRE(maxCV.get(1).value() == 2);
+      REQUIRE(maxCV[1] == 2);
+
+      REQUIRE(maxCV.get(2).has_value());
+      REQUIRE(maxCV.get(2).value() == 4);
+      REQUIRE(maxCV[2] == 4);
+
+      REQUIRE(maxCV.get(4).has_value());
+      REQUIRE(maxCV.get(4).value() == 41);
+      REQUIRE(maxCV[4] == 41);
+
+      REQUIRE(maxCV.get(10).has_value());
+      REQUIRE(maxCV.get(10).value() == 3);
+      REQUIRE(maxCV[10] == 3);
+
+      REQUIRE(maxCV.get(12).has_value());
+      REQUIRE(maxCV.get(12).value() == 8);
+      REQUIRE(maxCV[12] == 8);
+
+      REQUIRE(maxCV.get(19).has_value());
+      REQUIRE(maxCV.get(19).value() == 0);
+      REQUIRE(maxCV[19] == 0);
+
+      REQUIRE(maxCV.get(21).has_value());
+      REQUIRE(maxCV.get(21).value() == 60);
+      REQUIRE(maxCV[21] == 60);
+
+      REQUIRE(maxCV.get(22).has_value());
+      REQUIRE(maxCV.get(22).value() == 6);
+      REQUIRE(maxCV[22] == 6);
+
+      REQUIRE(maxCV.get(100).has_value());
+      REQUIRE(maxCV.get(100).value() == 5);
+      REQUIRE(maxCV[100] == 5);
+    }
+  }
+
+  SECTION("Testing without overlaps")
+  {
+    SECTION("Example 1")
+    {
+      ClockVector cv1{{1, 2}};
+      ClockVector cv2{
+          {2, 4},
+          {4, 41},
+          {10, 3},
+          {12, 8},
+      };
+      ClockVector maxCV = ClockVector::max(cv1, cv2);
+
+      REQUIRE(maxCV.size() == 5);
+      REQUIRE(maxCV.get(1).has_value());
+      REQUIRE(maxCV.get(1).value() == 2);
+      REQUIRE(maxCV[1] == 2);
+
+      REQUIRE(maxCV.get(2).has_value());
+      REQUIRE(maxCV.get(2).value() == 4);
+      REQUIRE(maxCV[2] == 4);
+
+      REQUIRE(maxCV.get(4).has_value());
+      REQUIRE(maxCV.get(4).value() == 41);
+      REQUIRE(maxCV[4] == 41);
+
+      REQUIRE(maxCV.get(10).has_value());
+      REQUIRE(maxCV.get(10).value() == 3);
+      REQUIRE(maxCV[10] == 3);
+
+      REQUIRE(maxCV.get(12).has_value());
+      REQUIRE(maxCV.get(12).value() == 8);
+      REQUIRE(maxCV[12] == 8);
+    }
+
+    SECTION("Example 2")
+    {
+      ClockVector cv1{{1, 2}, {4, 41}};
+      ClockVector cv2{
+          {2, 4},
+          {10, 3},
+          {12, 8},
+      };
+      ClockVector maxCV = ClockVector::max(cv1, cv2);
+
+      REQUIRE(maxCV.size() == 5);
+      REQUIRE(maxCV.get(1).has_value());
+      REQUIRE(maxCV.get(1).value() == 2);
+      REQUIRE(maxCV[1] == 2);
+
+      REQUIRE(maxCV.get(2).has_value());
+      REQUIRE(maxCV.get(2).value() == 4);
+      REQUIRE(maxCV[2] == 4);
+
+      REQUIRE(maxCV.get(4).has_value());
+      REQUIRE(maxCV.get(4).value() == 41);
+      REQUIRE(maxCV[4] == 41);
+
+      REQUIRE(maxCV.get(10).has_value());
+      REQUIRE(maxCV.get(10).value() == 3);
+      REQUIRE(maxCV[10] == 3);
+
+      REQUIRE(maxCV.get(12).has_value());
+      REQUIRE(maxCV.get(12).value() == 8);
+      REQUIRE(maxCV[12] == 8);
+    }
+
+    SECTION("Example 3")
+    {
+      ClockVector cv1{{1, 2}, {4, 41}};
+      ClockVector cv2{{2, 4}, {10, 3}, {12, 8}, {19, 0}, {21, 6}};
+      ClockVector cv3{{22, 6}, {100, 3}};
+      ClockVector maxCV = ClockVector::max(cv1, cv2);
+      maxCV             = ClockVector::max(maxCV, cv3);
+
+      REQUIRE(maxCV.size() == 9);
+      REQUIRE(maxCV.get(1).has_value());
+      REQUIRE(maxCV.get(1).value() == 2);
+      REQUIRE(maxCV[1] == 2);
+
+      REQUIRE(maxCV.get(2).has_value());
+      REQUIRE(maxCV.get(2).value() == 4);
+      REQUIRE(maxCV[2] == 4);
+
+      REQUIRE(maxCV.get(4).has_value());
+      REQUIRE(maxCV.get(4).value() == 41);
+      REQUIRE(maxCV[4] == 41);
+
+      REQUIRE(maxCV.get(10).has_value());
+      REQUIRE(maxCV.get(10).value() == 3);
+      REQUIRE(maxCV[10] == 3);
+
+      REQUIRE(maxCV.get(12).has_value());
+      REQUIRE(maxCV.get(12).value() == 8);
+      REQUIRE(maxCV[12] == 8);
+
+      REQUIRE(maxCV.get(19).has_value());
+      REQUIRE(maxCV.get(19).value() == 0);
+      REQUIRE(maxCV[19] == 0);
+
+      REQUIRE(maxCV.get(21).has_value());
+      REQUIRE(maxCV.get(21).value() == 6);
+      REQUIRE(maxCV[21] == 6);
+
+      REQUIRE(maxCV.get(22).has_value());
+      REQUIRE(maxCV.get(22).value() == 6);
+      REQUIRE(maxCV[22] == 6);
+
+      REQUIRE(maxCV.get(100).has_value());
+      REQUIRE(maxCV.get(100).value() == 3);
+      REQUIRE(maxCV[100] == 3);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/mc/explo/odpor/Execution.cpp b/src/mc/explo/odpor/Execution.cpp
new file mode 100644 (file)
index 0000000..0694161
--- /dev/null
@@ -0,0 +1,501 @@
+/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/mc/explo/odpor/Execution.hpp"
+#include "src/mc/api/State.hpp"
+#include "xbt/asserts.h"
+#include "xbt/string.hpp"
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_odpor_execution, mc_dfs, "ODPOR exploration algorithm of the model-checker");
+
+namespace simgrid::mc::odpor {
+
+std::vector<std::string> get_textual_trace(const PartialExecution& w)
+{
+  std::vector<std::string> trace;
+  for (const auto& t : w) {
+    auto a = xbt::string_printf("Actor %ld: %s", t->aid_, t->to_string(true).c_str());
+    trace.emplace_back(std::move(a));
+  }
+  return trace;
+}
+
+Execution::Execution(const PartialExecution& w)
+{
+  push_partial_execution(w);
+}
+
+void Execution::push_transition(std::shared_ptr<Transition> t)
+{
+  if (t == nullptr) {
+    throw std::invalid_argument("Unexpectedly received `nullptr`");
+  }
+  ClockVector max_clock_vector;
+  for (const Event& e : this->contents_) {
+    if (e.get_transition()->depends(t.get())) {
+      max_clock_vector = ClockVector::max(max_clock_vector, e.get_clock_vector());
+    }
+  }
+  max_clock_vector[t->aid_] = this->size();
+  contents_.push_back(Event({std::move(t), max_clock_vector}));
+}
+
+void Execution::push_partial_execution(const PartialExecution& w)
+{
+  for (const auto& t : w) {
+    push_transition(t);
+  }
+}
+
+std::vector<std::string> Execution::get_textual_trace() const
+{
+  std::vector<std::string> trace;
+  for (const auto& t : this->contents_) {
+    auto a = xbt::string_printf("Actor %ld: %s", t.get_transition()->aid_, t.get_transition()->to_string(true).c_str());
+    trace.emplace_back(std::move(a));
+  }
+  return trace;
+}
+
+std::unordered_set<Execution::EventHandle> Execution::get_racing_events_of(Execution::EventHandle target) const
+{
+  std::unordered_set<Execution::EventHandle> racing_events;
+  // This keep tracks of events that happens-before the target
+  std::unordered_set<Execution::EventHandle> disqualified_events;
+
+  // For each event of the execution
+  for (auto e_i = target; e_i != std::numeric_limits<Execution::EventHandle>::max(); e_i--) {
+    // We need `e_i -->_E target` as a necessary condition
+    if (not happens_before(e_i, target)) {
+      XBT_DEBUG("ODPOR_RACING_EVENTS with `%u` : `%u` discarded because `%u` --\\-->_E `%u`", target, e_i, e_i, target);
+      continue;
+    }
+
+    // Further, `proc(e_i) != proc(target)`
+    if (get_actor_with_handle(e_i) == get_actor_with_handle(target)) {
+      disqualified_events.insert(e_i);
+      XBT_DEBUG("ODPOR_RACING_EVENTS with `%u` : `%u` disqualified because proc(`%u`)=proc(`%u`)", target, e_i, e_i,
+                target);
+      continue;
+    }
+
+    // There could an event that "happens-between" the two events which would discount `e_i` as a race
+    for (auto e_j = e_i; e_j < target; e_j++) {
+      // If both:
+      // 1. e_i --->_E e_j; and
+      // 2. disqualified_events.count(e_j) > 0
+      // then e_i --->_E target indirectly (either through
+      // e_j directly, or transitively through e_j)
+      if (disqualified_events.count(e_j) > 0 && happens_before(e_i, e_j)) {
+        XBT_DEBUG("ODPOR_RACING_EVENTS with `%u` : `%u` disqualified because `%u` happens-between `%u`-->`%u`-->`%u`)",
+                  target, e_i, e_j, e_i, e_j, target);
+        disqualified_events.insert(e_i);
+        break;
+      }
+    }
+
+    // If `e_i` wasn't disqualified in the last round,
+    // it's in a race with `target`. After marking it
+    // as such, we ensure no other event `e` can happen-before
+    // it (since this would transitively make it the event
+    // which "happens-between" `target` and `e`)
+    if (disqualified_events.count(e_i) == 0) {
+      XBT_DEBUG("ODPOR_RACING_EVENTS with `%u` : `%u` is a valid racing event", target, e_i);
+      racing_events.insert(e_i);
+      disqualified_events.insert(e_i);
+    }
+  }
+
+  return racing_events;
+}
+
+std::unordered_set<Execution::EventHandle> Execution::get_reversible_races_of(EventHandle handle) const
+{
+  std::unordered_set<EventHandle> reversible_races;
+  const auto* this_transition = get_transition_for_handle(handle);
+  for (EventHandle race : get_racing_events_of(handle)) {
+    const auto* other_transition = get_transition_for_handle(race);
+
+    if (this_transition->reversible_race(other_transition)) {
+      reversible_races.insert(race);
+    }
+  }
+  return reversible_races;
+}
+
+Execution Execution::get_prefix_before(Execution::EventHandle handle) const
+{
+  return Execution(std::vector<Event>{contents_.begin(), contents_.begin() + handle});
+}
+
+std::unordered_set<aid_t>
+Execution::get_missing_source_set_actors_from(EventHandle e, const std::unordered_set<aid_t>& backtrack_set) const
+{
+  // If this execution is empty, there are no initials
+  // relative to the last transition added to the execution
+  // since such a transition does not exist
+  if (empty()) {
+    return std::unordered_set<aid_t>{};
+  }
+
+  // To actually compute `I_[E'](v) ∩ backtrack(E')`, we must
+  // first compute `E'` and "move" in the direction of `v`.
+  // We perform a scan over `E` (this execution) and make
+  // note of any events which occur after `e` but don't
+  // "happen-after" `e` by pushing them onto `E'`. Note that
+  // correctness is still preserved in computing `v` "on-the-fly"
+  // to determine if an event `e` by actor `q` is an initial for `E'`
+  // after `v`: only those events that "occur-before" `e` in `v` could
+  // "happen-before" `ve for any valid "happens-before" relation
+  // (see property 1 in the ODPOR paper, viz. "is included in <_E")
+
+  // First, grab `E' := pre(e, E)` and determine what actor `p` is
+  const auto next_E_p = get_latest_event_handle().value();
+  xbt_assert(e != next_E_p,
+             "This method assumes that the event `e` (%u) and `next_[E](p)` (%u)"
+             "are in a reversible race, yet we claim to have such a race between the"
+             "same event. This indicates the the SDPOR pseudocode implementation is broken "
+             "as it supplies these values.",
+             e, next_E_p);
+  Execution E_prime_v = get_prefix_before(e);
+  std::vector<sdpor::Execution::EventHandle> v;
+  std::unordered_set<aid_t> I_E_prime_v;
+  std::unordered_set<aid_t> disqualified_actors;
+
+  // Note `e + 1` here: `notdep(e, E)` is defined as the
+  // set of events that *occur-after* but don't *happen-after* `e`
+  for (auto e_prime = e + 1; e_prime <= next_E_p; ++e_prime) {
+    // Any event `e*` which occurs after `e` but which does not
+    // happen after `e` is a member of `v`. In addition to marking
+    // the event in `v`, we also "simulate" running the action `v`
+    // from E'
+    if (not happens_before(e, e_prime) || e_prime == next_E_p) {
+      // First, push the transition onto the hypothetical execution
+      E_prime_v.push_transition(get_event_with_handle(e_prime).get_transition());
+      const EventHandle e_prime_in_E_prime_v = E_prime_v.get_latest_event_handle().value();
+
+      // When checking whether any event in `dom_[E'](v)` happens before
+      // `next_[E'](q)` below for thread `q`, we must consider that the
+      // events relative to `E` (this execution) are different than those
+      // relative to `E'.v`. Thus e.g. event `7` in `E` may be event `4`
+      // in `E'.v`. Since we are asking about "happens-before"
+      // `-->_[E'.v]` about `E'.v`, we must build `v` relative to `E'`.
+      //
+      // Note that we add `q` to v regardless of whether `q` itself has been
+      // disqualified since  we've determined that `e_prime` "occurs-after" but
+      // does not "happen-after" `e`
+      v.push_back(e_prime_in_E_prime_v);
+
+      const aid_t q = E_prime_v.get_actor_with_handle(e_prime_in_E_prime_v);
+      if (disqualified_actors.count(q) > 0) { // Did we already note that `q` is not an initial?
+        continue;
+      }
+      const bool is_initial = std::none_of(v.begin(), v.end(), [&](const auto& e_star) {
+        return E_prime_v.happens_before(e_star, e_prime_in_E_prime_v);
+      });
+      if (is_initial) {
+        // If the backtrack set already contains `q`, we're done:
+        // they've made note to search for (or have already searched for)
+        // this initial
+        if (backtrack_set.count(q) > 0) {
+          return std::unordered_set<aid_t>{};
+        } else {
+          I_E_prime_v.insert(q);
+        }
+      } else {
+        // If `q` is disqualified as a candidate, clearly
+        // no event occurring after `e_prime` in `E` executed
+        // by actor `q` will qualify since any (valid) happens-before
+        // relation orders actions taken by each actor
+        disqualified_actors.insert(q);
+      }
+    }
+  }
+  xbt_assert(not I_E_prime_v.empty(),
+             "For any non-empty execution, we know that "
+             "at minimum one actor is an initial since "
+             "some execution is possible with respect to a "
+             "prefix before event `%u`, yet we didn't find anyone. "
+             "This implies the implementation of this function is broken.",
+             e);
+  return I_E_prime_v;
+}
+
+std::optional<PartialExecution> Execution::get_odpor_extension_from(EventHandle e, EventHandle e_prime,
+                                                                    const State& state_at_e) const
+{
+  // `e` is assumed to be in a reversible race with `e_prime`.
+  // If `e > e_prime`, then `e` occurs-after `e_prime` which means
+  // `e` could not race with if
+  if (e > e_prime) {
+    throw std::invalid_argument("ODPOR extensions can only be computed for "
+                                "events in a reversible race, which is claimed, "
+                                "yet the racing event 'occurs-after' the target");
+  }
+
+  if (empty()) {
+    return std::nullopt;
+  }
+
+  PartialExecution v;
+  std::vector<Execution::EventHandle> v_handles;
+  std::unordered_set<aid_t> WI_E_prime_v;
+  std::unordered_set<aid_t> disqualified_actors;
+  Execution E_prime_v                           = get_prefix_before(e);
+  const std::unordered_set<aid_t> sleep_E_prime = state_at_e.get_sleeping_actors();
+
+  // Note `e + 1` here: `notdep(e, E)` is defined as the
+  // set of events that *occur-after* but don't *happen-after* `e`
+  //
+  // SUBTLE NOTE: ODPOR requires us to compute `notdep(e, E)` EVEN THOUGH
+  // the race is between `e` and `e'`; that is, events occurring in `E`
+  // that "occur-after" `e'` may end up in the partial execution `v`.
+  //
+  // Observe that `notdep(e, E).proc(e')` will contain all transitions
+  // that don't happen-after `e` in the order they appear FOLLOWED BY
+  // THE **TRANSITION** ASSOCIATED WITH **`e'`**!!
+  //
+  // SUBTLE NOTE: Observe that any event that "happens-after" `e'`
+  // must necessarily "happen-after" `e` as well, since `e` and
+  // `e'` are presumed to be in a reversible race. Hence, we know that
+  // all events `e_star` such that `e` "happens-before" `e_star` cannot affect
+  // the enabledness of `e'`; furthermore, `e'` cannot affect the enabledness
+  // of any event independent with `e` that "occurs-after" `e'`
+  for (auto e_star = e + 1; e_star <= get_latest_event_handle().value(); ++e_star) {
+    // Any event `e*` which occurs after `e` but which does not
+    // happen after `e` is a member of `v`. In addition to marking
+    // the event in `v`, we also "simulate" running the action `v` from E'
+    // to be able to compute `--->[E'.v]`
+    if (not happens_before(e, e_star)) {
+      xbt_assert(e_star != e_prime,
+                 "Invariant Violation: We claimed events %u and %u were in a reversible race, yet we also "
+                 "claim that they do not happen-before one another. This is impossible: "
+                 "are you sure that the two events are in a reversible race?",
+                 e, e_prime);
+      E_prime_v.push_transition(get_event_with_handle(e_star).get_transition());
+      v.push_back(get_event_with_handle(e_star).get_transition());
+
+      XBT_DEBUG("Added Event `%u` (%ld:%s) to the construction of v", e_star, get_actor_with_handle(e_star),
+                get_event_with_handle(e_star).get_transition()->to_string().c_str());
+
+      const EventHandle e_star_in_E_prime_v = E_prime_v.get_latest_event_handle().value();
+
+      // When checking whether any event in `dom_[E'](v)` happens before
+      // `next_[E'](q)` below for thread `q`, we must consider that the
+      // events relative to `E` (this execution) are different than those
+      // relative to `E'.v`. Thus e.g. event `7` in `E` may be event `4`
+      // in `E'.v`. Since we are asking about "happens-before"
+      // `-->_[E'.v]` about `E'.v`, we must build `v` relative to `E'`
+      v_handles.push_back(e_star_in_E_prime_v);
+
+      // Note that we add `q` to v regardless of whether `q` itself has been
+      // disqualified since `q` may itself disqualify other actors
+      // (i.e. even if `q` is disqualified from being an initial, it
+      // is still contained in the sequence `v`)
+      const aid_t q = E_prime_v.get_actor_with_handle(e_star_in_E_prime_v);
+      if (disqualified_actors.count(q) > 0) { // Did we already note that `q` is not an initial?
+        continue;
+      }
+      const bool is_initial = std::none_of(v_handles.begin(), v_handles.end(), [&](const auto& handle) {
+        return E_prime_v.happens_before(handle, e_star_in_E_prime_v);
+      });
+      if (is_initial) {
+        // If the sleep set already contains `q`, we're done:
+        // we've found an initial contained in the sleep set and
+        // so the intersection is non-empty
+        if (sleep_E_prime.count(q) > 0) {
+          return std::nullopt;
+        } else {
+          WI_E_prime_v.insert(q);
+        }
+      } else {
+        // If `q` is disqualified as a candidate, clearly
+        // no event occurring after `e_prime` in `E` executed
+        // by actor `q` will qualify since any (valid) happens-before
+        // relation orders actions taken by each actor
+        disqualified_actors.insert(q);
+      }
+    } else {
+      XBT_DEBUG("Event `%u` (%ld:%s) dismissed from the construction of v", e_star, get_actor_with_handle(e_star),
+                get_event_with_handle(e_star).get_transition()->to_string().c_str());
+    }
+  }
+
+  // Now we add `e_prime := <q, i>` to `E'.v` and repeat the same work
+  // It's possible `proc(e_prime)` is an initial
+  //
+  // Note the form of `v` in the pseudocode:
+  //  `v := notdep(e, E).e'^
+  E_prime_v.push_transition(get_event_with_handle(e_prime).get_transition());
+  v.push_back(get_event_with_handle(e_prime).get_transition());
+
+  const EventHandle e_prime_in_E_prime_v = E_prime_v.get_latest_event_handle().value();
+  v_handles.push_back(e_prime_in_E_prime_v);
+
+  const bool is_initial = std::none_of(v_handles.begin(), v_handles.end(), [&](const auto& handle) {
+    return E_prime_v.happens_before(handle, e_prime_in_E_prime_v);
+  });
+  if (is_initial) {
+    if (const aid_t q = E_prime_v.get_actor_with_handle(e_prime_in_E_prime_v); sleep_E_prime.count(q) > 0) {
+      return std::nullopt;
+    } else {
+      WI_E_prime_v.insert(q);
+    }
+  }
+
+  const Execution pre_E_e    = get_prefix_before(e);
+  const auto sleeping_actors = state_at_e.get_sleeping_actors();
+
+  // Check if any enabled actor that is independent with
+  // this execution after `v` is contained in the sleep set
+  for (const auto& [aid, astate] : state_at_e.get_actors_list()) {
+    const bool is_in_WI_E =
+        astate.is_enabled() and pre_E_e.is_independent_with_execution_of(v, astate.get_transition());
+    const bool is_in_sleep_set = sleeping_actors.count(aid) > 0;
+
+    // `action(aid)` is in `WI_[E](v)` but also is contained in the sleep set.
+    // This implies that the intersection between the two is non-empty
+    if (is_in_WI_E && is_in_sleep_set)
+      return std::nullopt;
+  }
+
+  return v;
+}
+
+bool Execution::is_initial_after_execution_of(const PartialExecution& w, aid_t p) const
+{
+  auto E_w = *this;
+  std::vector<EventHandle> w_handles;
+  for (const auto& w_i : w) {
+    // Take one step in the direction of `w`
+    E_w.push_transition(w_i);
+
+    // If that step happened to be executed by `p`,
+    // great: we know that `p` is contained in `w`.
+    // We now need to verify that it doens't "happen-after"
+    // any events which occur before it
+    if (w_i->aid_ == p) {
+      const auto p_handle = E_w.get_latest_event_handle().value();
+      return std::none_of(w_handles.begin(), w_handles.end(),
+                          [&](const auto handle) { return E_w.happens_before(handle, p_handle); });
+    } else {
+      w_handles.push_back(E_w.get_latest_event_handle().value());
+    }
+  }
+  return false;
+}
+
+bool Execution::is_independent_with_execution_of(const PartialExecution& w, std::shared_ptr<Transition> next_E_p) const
+{
+  // INVARIANT: Here, we assume that for any process `p_i` of `w`,
+  // the events of this execution followed by the execution of all
+  // actors occurring before `p_i` in `v` (`p_j`, `0 <= j < i`)
+  // are sufficient to enable `p_i`. This is fortunately the case
+  // with what ODPOR requires of us, viz. to ask the question about
+  // `v := notdep(e, E)` for some execution `E` and event `e` of
+  // that execution.
+  auto E_p_w = *this;
+  E_p_w.push_transition(std::move(next_E_p));
+  const auto p_handle = E_p_w.get_latest_event_handle().value();
+
+  // As we add events to `w`, verify that none
+  // of them "happen-after" the event associated with
+  // the step `next_E_p` (viz. p_handle)
+  for (const auto& w_i : w) {
+    E_p_w.push_transition(w_i);
+    const auto w_i_handle = E_p_w.get_latest_event_handle().value();
+    if (E_p_w.happens_before(p_handle, w_i_handle)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+std::optional<PartialExecution> Execution::get_shortest_odpor_sq_subset_insertion(const PartialExecution& v,
+                                                                                  const PartialExecution& w) const
+{
+  // See section 4 of Abdulla. et al.'s 2017 ODPOR paper for details (specifically
+  // where the [iterative] computation of `v ~_[E] w` is described)
+  auto E_v   = *this;
+  auto w_now = w;
+
+  for (const auto& next_E_p : v) {
+    // Is `p in `I_[E](w)`?
+    if (const aid_t p = next_E_p->aid_; E_v.is_initial_after_execution_of(w_now, p)) {
+      // Remove `p` from w and continue
+
+      // INVARIANT: If `p` occurs in `w`, it had better refer to the same
+      // transition referenced by `v`. Unfortunately, we have two
+      // sources of truth here which can be manipulated at the same
+      // time as arguments to the function. If ODPOR works correctly,
+      // they should always refer to the same value; but as a sanity check,
+      // we have an assert that tests that at least the types are the same.
+      const auto action_by_p_in_w =
+          std::find_if(w_now.begin(), w_now.end(), [=](const auto& action) { return action->aid_ == p; });
+      xbt_assert(action_by_p_in_w != w_now.end(), "Invariant violated: actor `p` "
+                                                  "is claimed to be an initial after `w` but is "
+                                                  "not actually contained in `w`. This indicates that there "
+                                                  "is a bug computing initials");
+      const auto& w_action = *action_by_p_in_w;
+      xbt_assert(w_action->type_ == next_E_p->type_,
+                 "Invariant violated: `v` claims that actor `%ld` executes '%s' while "
+                 "`w` claims that it executes '%s'. These two partial executions both "
+                 "refer to `next_[E](p)`, which should be the same",
+                 p, next_E_p->to_string(false).c_str(), w_action->to_string(false).c_str());
+      w_now.erase(action_by_p_in_w);
+    }
+    // Is `E ⊢ p ◇ w`?
+    else if (E_v.is_independent_with_execution_of(w_now, next_E_p)) {
+      // INVARIANT: Note that it is impossible for `p` to be
+      // excluded from the set `I_[E](w)` BUT ALSO be contained in
+      // `w` itself if `E ⊢ p ◇ w` (intuitively, the fact that `E ⊢ p ◇ w`
+      // means that are able to move `p` anywhere in `w` IF it occurred, so
+      // if it really does occur we know it must then be an initial).
+      // We assert this is the case here
+      const auto action_by_p_in_w =
+          std::find_if(w_now.begin(), w_now.end(), [=](const auto& action) { return action->aid_ == p; });
+      xbt_assert(action_by_p_in_w == w_now.end(),
+                 "Invariant violated: We claimed that actor `%ld` is not an initial "
+                 "after `w`, yet it's independent with all actions of `w` AND occurs in `w`."
+                 "This indicates that there is a bug computing initials",
+                 p);
+    } else {
+      // Neither of the two above conditions hold, so the relation fails
+      return std::nullopt;
+    }
+
+    // Move one step forward in the direction of `v` and repeat
+    E_v.push_transition(next_E_p);
+  }
+  return std::optional<PartialExecution>{std::move(w_now)};
+}
+
+bool Execution::happens_before(Execution::EventHandle e1_handle, Execution::EventHandle e2_handle) const
+{
+  // 1. "happens-before" (-->_E) is a subset of "occurs before" (<_E)
+  // and is an irreflexive relation
+  if (e1_handle >= e2_handle) {
+    return false;
+  }
+
+  // Each execution maintains a stack of clock vectors which are updated
+  // according to the procedure outlined in section 4 of the original DPOR paper
+  const Event& e2     = get_event_with_handle(e2_handle);
+  const aid_t proc_e1 = get_actor_with_handle(e1_handle);
+
+  if (const auto e1_in_e2_clock = e2.get_clock_vector().get(proc_e1); e1_in_e2_clock.has_value()) {
+    return e1_handle <= e1_in_e2_clock.value();
+  }
+  // If `e1` does not appear in e2's clock vector, this implies
+  // not only that the transitions associated with `e1` and `e2
+  // are independent, but further that there are no transitive
+  // dependencies between e1 and e2
+  return false;
+}
+
+} // namespace simgrid::mc::odpor
diff --git a/src/mc/explo/odpor/Execution.hpp b/src/mc/explo/odpor/Execution.hpp
new file mode 100644 (file)
index 0000000..6d8ca42
--- /dev/null
@@ -0,0 +1,365 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_ODPOR_EXECUTION_HPP
+#define SIMGRID_MC_ODPOR_EXECUTION_HPP
+
+#include "src/mc/api/ClockVector.hpp"
+#include "src/mc/explo/odpor/odpor_forward.hpp"
+#include "src/mc/mc_forward.hpp"
+#include "src/mc/mc_record.hpp"
+#include "src/mc/transition/Transition.hpp"
+
+#include <list>
+#include <optional>
+#include <unordered_set>
+#include <vector>
+
+namespace simgrid::mc::odpor {
+
+std::vector<std::string> get_textual_trace(const PartialExecution& w);
+
+/**
+ * @brief The occurrence of a transition in an execution
+ *
+ * An execution is set of *events*, where each element represents
+ * the occurrence or execution of the `i`th step of a particular
+ * actor `j`
+ */
+class Event {
+  std::pair<std::shared_ptr<Transition>, ClockVector> contents_;
+
+public:
+  Event()                        = default;
+  Event(Event&&)                 = default;
+  Event(const Event&)            = default;
+  Event& operator=(const Event&) = default;
+  explicit Event(std::pair<std::shared_ptr<Transition>, ClockVector> pair) : contents_(std::move(pair)) {}
+
+  std::shared_ptr<Transition> get_transition() const { return std::get<0>(contents_); }
+  const ClockVector& get_clock_vector() const { return std::get<1>(contents_); }
+};
+
+/**
+ * @brief An ordered sequence of transitions which describe
+ * the evolution of a process undergoing model checking
+ *
+ * An execution conceptually is just a string of actors
+ * ids (e.g. "1.2.3.1.2.2.1.1"), where the `i`th occurrence
+ * of actor id `j` corresponds to the `i`th action executed
+ * by the actor with id `j` (viz. the `i`th step of actor `j`).
+ * Executions can stand alone on their own or can extend
+ * the execution of other sequences
+ *
+ * Executions are conceived based on the following papers:
+ * 1. "Source Sets: A Foundation for Optimal Dynamic Partial Order Reduction"
+ * by Abdulla et al.
+ *
+ * In addition to representing an actual steps taken,
+ * an execution keeps track of the "happens-before"
+ * relation among the transitions in the execution
+ * by following the procedure outlined in section 4 of the
+ * original DPOR paper with clock vectors.
+ * As new transitions are added to the execution, clock vectors are
+ * computed as appropriate and associated with the corresponding position
+ * in the execution. This allows us to determine “happens-before” in
+ * constant-time between points in the execution (called events
+ * [which is unfortunately the same name used in UDPOR for a slightly
+ * different concept]), albeit for an up-front cost of traversing the
+ * execution stack. The happens-before relation is important in many
+ * places in SDPOR and ODPOR.
+ *
+ * @note: For more nuanced happens-before relations, clock
+ * vectors may not always suffice. Clock vectors work
+ * well with transition-based dependencies like that used in
+ * SimGrid; but to have a more refined independence relation,
+ * an event-based dependency approach is needed. See the section 2
+ * in the ODPOR paper [1] concerning event-based dependencies and
+ * how the happens-before relation can be refined in a
+ * computation model much like that of SimGrid. In fact, the same issue
+ * arrises with UDPOR with context-sensitive dependencies:
+ * the two concepts are analogous if not identical
+ */
+class Execution {
+private:
+  std::vector<Event> contents_;
+  Execution(std::vector<Event>&& contents) : contents_(std::move(contents)) {}
+
+public:
+  using EventHandle = uint32_t;
+
+  Execution()                            = default;
+  Execution(const Execution&)            = default;
+  Execution& operator=(Execution const&) = default;
+  Execution(Execution&&)                 = default;
+  Execution(const PartialExecution&);
+
+  std::vector<std::string> get_textual_trace() const;
+
+  size_t size() const { return this->contents_.size(); }
+  bool empty() const { return this->contents_.empty(); }
+  auto begin() const { return this->contents_.begin(); }
+  auto end() const { return this->contents_.end(); }
+
+  /**
+   * @brief Computes the "core" portion the SDPOR algorithm,
+   * viz. the intersection of the backtracking set and the
+   * set of initials with respect to the *last* event added
+   * to the execution
+   *
+   * The "core" portion of the SDPOR algorithm is found on
+   * lines 6-9 of the pseudocode:
+   *
+   * 6 | let E' := pre(E, e)
+   * 7 | let v :=  notdep(e, E).p
+   * 8 | if I_[E'](v) ∩ backtrack(E') = empty then
+   * 9 |    --> add some q in I_[E'](v) to backtrack(E')
+   *
+   * This method computes all of the lines simultaneously,
+   * returning the set `I_[E'](v)` if condition on line 8 holds.
+   * The event `e` and the set `backtrack(E')` are the provided
+   * arguments to the method.
+   *
+   * @param e the event with respect to which to determine
+   * whether a backtrack point needs to be added for the
+   * prefix corresponding to the execution prior to `e`
+   *
+   * @param backtrack_set The set of actors which should
+   * not be considered for selection as an SDPOR initial.
+   * While this set need not necessarily correspond to the
+   * backtrack set `backtrack(E')`, doing so provides what
+   * is expected for SDPOR
+   *
+   * See the SDPOR algorithm pseudocode in [1] for more
+   * details for the context of the function.
+   *
+   * @precondition: This method assumes that events `e` and
+   * `e' := get_latest_event_handle()` are in a *reversible* race,
+   * as is explicitly the case in SDPOR
+   *
+   * @returns a set of actors not already contained in `backtrack_set`
+   * which serve as an initials to reverse the race between `e`
+   * and `e' := get_latest_event_handle()`; that is, an initial that is
+   * not already contained in the set `backtrack_set`.
+   */
+  std::unordered_set<aid_t> get_missing_source_set_actors_from(EventHandle e,
+                                                               const std::unordered_set<aid_t>& backtrack_set) const;
+
+  /**
+   * @brief Computes the analogous lines from the SDPOR algorithm
+   * in the ODPOR algorithm, viz. the intersection of the sleep set
+   * and the set of weak initials with respect to the given pair
+   * of racing events
+   *
+   * This method computes lines 4-6 of the ODPOR pseudocode, viz.:
+   *
+   * 4 | let E' := pre(E, e)
+   * 5 | let v := notdep(e, E).e'^
+   * 6 | if sleep(E') ∩ WI_[E'](v) = empty then
+   * 7 |   --> wut(E') := insert_[E'](v, wut(E'))
+   *
+   * The sequence `v` is computed and returned as needed, based on whether
+   * the check on line 6 passes.
+   *
+   * @precondition: This method assumes that events `e` and
+   * `e_prime` are in a *reversible* race, as is the case
+   * in ODPOR.
+   *
+   * @returns a partial execution `v := notdep(e, E)` (where `E` refers
+   * to this execution) that should be inserted into a wakeup tree with
+   * respect to this execution if `sleep(E') ∩ WI_[E'](v) = empty`, and
+   * `std::nullopt` otherwise
+   */
+  std::optional<PartialExecution> get_odpor_extension_from(EventHandle e, EventHandle e_prime,
+                                                           const State& state_at_e) const;
+
+  /**
+   * @brief For a given sequence of actors `v` and a sequence of transitions `w`,
+   * computes the sequence, if any, that should be inserted as a child in wakeup tree for
+   * this execution
+   *
+   * Recall that the procedure for implementing the insertion
+   * is outlined in section 6.2 of Abdulla et al. 2017 as follows:
+   *
+   * | Let `v` be the smallest (w.r.t to "<") sequence in [the tree] B
+   * | such that `v ~_[E] w`. If `v` is a leaf node, the tree can be left
+   * | unmodified.
+   * |
+   * | Otherwise let `w'` be the shortest sequence such that `w [=_[E] v.w'`
+   * | and add `v.w'` as a new leaf, ordered after all already existing nodes
+   * | of the form `v.w''`
+   *
+   * The procedure for determining whether `v ~_[E] w` is given as Lemma 4.6 of
+   * Abdulla et al. 2017:
+   *
+   * | The relation `v ~_[E] w` holds if either
+   * | (1) v = <>, or
+   * | (2) v := p.v' and either
+   * |     (a) p in I_[E](w) and `v' ~_[E.p] (w \ p)`
+   * |     (b) E ⊢ p ◊ w and `v' ~_[E.p] w`
+   *
+   * This method computes the result `v.w'` as needed (viz. only if `v ~_[E] w`
+   * with respect to this execution `E`). The implementation takes advantage
+   * of the fact that determining whether `v ~_[E] w` yields "for free" the
+   * the shortest such `w'` we are looking for; if we ultimately determine
+   * that `v ~_[E] w`, the work we did to do so leaves us precisely with `w'`,
+   * so we can simply prepend `v` to it and call it a day
+   *
+   * @precondition: This method assumes that `E.v` is a valid execution, viz.
+   * that the events of `E` are sufficient to enabled `v_0` and that
+   * `v_0, ..., v_{i - 1}` are sufficient to enable `v_i`. This is the
+   * case when e.g. `v := notdep(e, E).p` for example in ODPOR
+   *
+   * @returns a partial execution `v.w'` that should be inserted
+   * as a child of a wakeup tree node representing the sequence `v`
+   * if `v ~_[E] w`, or `std::nullopt` if that relation does not hold
+   * between the two sequences `v` and `w`
+   */
+  std::optional<PartialExecution> get_shortest_odpor_sq_subset_insertion(const PartialExecution& v,
+                                                                         const PartialExecution& w) const;
+
+  /**
+   * @brief For a given sequence `w`, determines whether p in I_[E](w)
+   *
+   * @note: You may notice that some of the other methods compute this
+   * value as well. What we notice, though, in those cases is that
+   * we are repeatedly asking about initials with respect to an execution.
+   * It is better, then, to bunch the work together in those cases to
+   * get asymptotically better results (e.g. instead of calling with all
+   * `N` actors, we can process them "in-parallel" as is done with the
+   * computation of SDPOR initials)
+   */
+  bool is_initial_after_execution_of(const PartialExecution& w, aid_t p) const;
+
+  /**
+   * @brief Determines whether `E ⊢ p ◊ w` given the next action taken by `p`
+   */
+  bool is_independent_with_execution_of(const PartialExecution& w, std::shared_ptr<Transition> next_E_p) const;
+
+  /**
+   * @brief Determines the event associated with the given handle `handle`
+   */
+  const Event& get_event_with_handle(EventHandle handle) const { return contents_[handle]; }
+
+  /**
+   * @brief Determines the actor associated with the given event handle `handle`
+   */
+  aid_t get_actor_with_handle(EventHandle handle) const { return get_event_with_handle(handle).get_transition()->aid_; }
+
+  /**
+   * @brief Determines the transition associated with the given handle `handle`
+   */
+  const Transition* get_transition_for_handle(EventHandle handle) const
+  {
+    return get_event_with_handle(handle).get_transition().get();
+  }
+
+  /**
+   * @brief Returns a handle to the newest event of the execution, if such an event exists
+   *
+   * @returns the handle to the last event of the execution.
+   * If the sequence is empty, no such handle exists and the
+   * method returns `std::nullopt`
+   */
+  std::optional<EventHandle> get_latest_event_handle() const
+  {
+    return contents_.empty() ? std::nullopt : std::optional<EventHandle>{static_cast<EventHandle>(size() - 1)};
+  }
+
+  /**
+   * @brief Returns a set of events which are in
+   * "immediate conflict" (according to the definition given
+   * in the ODPOR paper) with the given event
+   *
+   * Two events `e` and `e'` in an execution `E` are said to
+   * *race* iff
+   *
+   * 1. `proc(e) != proc(e')`; that is, the events correspond to
+   * the execution of different actors
+   * 2. `e -->_E e'` and there is no `e''` in `E` such that
+   *  `e -->_E e''` and `e'' -->_E e'`; that is, the two events
+   * "happen-before" one another in `E` and no other event in
+   * `E` "happens-between" `e` and `e'`
+   *
+   * @param handle the event with respect to which races are
+   * computed
+   * @returns a set of event handles, each element of which is an
+   * event in this execution which is in a *race* with event `handle`
+   */
+  std::unordered_set<EventHandle> get_racing_events_of(EventHandle handle) const;
+
+  /**
+   * @brief Returns a set of events which are in a reversible
+   * race with the given event handle `handle`
+   *
+   * Two events `e` and `e'` in an execution `E` are said to
+   * be in a *reversible race* iff
+   *
+   * 1. `e` and `e'` race
+   * 2. In any equivalent execution sequence `E'` to `E`
+   * where `e` occurs immediately before `e'`, the actor
+   * running `e'` was enabled in the state prior to `e`
+   *
+   * @param handle the event with respect to which
+   * reversible races are computed
+   * @returns a set of event handles, each element of which is an event
+   * in this execution which is in a *reversible race* with event `handle`
+   */
+  std::unordered_set<EventHandle> get_reversible_races_of(EventHandle handle) const;
+
+  /**
+   * @brief Computes `pre(e, E)` as described in ODPOR [1]
+   *
+   * The execution `pre(e, E)` for an event `e` in an
+   * execution `E` is the contiguous prefix of events
+   * `E' <= E` up to but excluding the event `e` itself.
+   * Roughly speaking, the prefix intuitively represents
+   * the "history" of causes which permitted event `e`
+   * to exist
+   */
+  Execution get_prefix_before(EventHandle) const;
+
+  /**
+   * @brief Whether the event represented by `e1`
+   * "happens-before" the event represented by
+   * `e2` in the context of this execution
+   *
+   * In the terminology of the ODPOR paper,
+   * this function computes
+   *
+   * `e1 --->_E e2`
+   *
+   * where `E` is this execution
+   *
+   * @note: The happens-before relation computed by this
+   * execution is "coarse" in the sense that context-sensitive
+   * independence is not exploited. To include such context-sensitive
+   * dependencies requires a new method of keeping track of
+   * the happens-before procedure, which is nontrivial...
+   */
+  bool happens_before(EventHandle e1, EventHandle e2) const;
+
+  /**
+   * @brief Extends the execution by one more step
+   *
+   * Intutively, pushing a transition `t` onto execution `E`
+   * is equivalent to making the execution become (using the
+   * notation of [1]) `E.proc(t)` where `proc(t)` is the
+   * actor which executed transition `t`.
+   */
+  void push_transition(std::shared_ptr<Transition>);
+
+  /**
+   * @brief Extends the execution by a sequence of steps
+   *
+   * This method has the equivalent effect of pushing the
+   * transitions of the partial execution one-by-one onto
+   * the execution
+   */
+  void push_partial_execution(const PartialExecution&);
+};
+
+} // namespace simgrid::mc::odpor
+#endif
diff --git a/src/mc/explo/odpor/Execution_test.cpp b/src/mc/explo/odpor/Execution_test.cpp
new file mode 100644 (file)
index 0000000..302ccea
--- /dev/null
@@ -0,0 +1,732 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.               */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/3rd-party/catch.hpp"
+#include "src/mc/explo/odpor/Execution.hpp"
+#include "src/mc/explo/odpor/odpor_tests_private.hpp"
+#include "src/mc/transition/TransitionComm.hpp"
+
+using namespace simgrid::mc;
+using namespace simgrid::mc::odpor;
+using namespace simgrid::mc::udpor;
+
+TEST_CASE("simgrid::mc::odpor::Execution: Constructing Executions")
+{
+  Execution execution;
+  REQUIRE(execution.empty());
+  REQUIRE(execution.size() == 0);
+  REQUIRE_FALSE(execution.get_latest_event_handle().has_value());
+}
+
+TEST_CASE("simgrid::mc::odpor::Execution: Testing Happens-Before")
+{
+  SECTION("Example 1")
+  {
+    // We check each permutation for happens before
+    // among the given actions added to the execution
+    const auto a1 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a2 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto a3 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a4 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 4);
+
+    Execution execution;
+    execution.push_transition(a1);
+    execution.push_transition(a2);
+    execution.push_transition(a3);
+    execution.push_transition(a4);
+
+    SECTION("Happens-before is irreflexive")
+    {
+      REQUIRE_FALSE(execution.happens_before(0, 0));
+      REQUIRE_FALSE(execution.happens_before(1, 1));
+      REQUIRE_FALSE(execution.happens_before(2, 2));
+      REQUIRE_FALSE(execution.happens_before(3, 3));
+    }
+
+    SECTION("Happens-before values for each pair of events")
+    {
+      REQUIRE_FALSE(execution.happens_before(0, 1));
+      REQUIRE_FALSE(execution.happens_before(0, 2));
+      REQUIRE(execution.happens_before(0, 3));
+      REQUIRE_FALSE(execution.happens_before(1, 2));
+      REQUIRE_FALSE(execution.happens_before(1, 3));
+      REQUIRE_FALSE(execution.happens_before(2, 3));
+    }
+
+    SECTION("Happens-before is a subset of 'occurs-before' ")
+    {
+      REQUIRE_FALSE(execution.happens_before(1, 0));
+      REQUIRE_FALSE(execution.happens_before(2, 0));
+      REQUIRE_FALSE(execution.happens_before(3, 0));
+      REQUIRE_FALSE(execution.happens_before(2, 1));
+      REQUIRE_FALSE(execution.happens_before(3, 1));
+      REQUIRE_FALSE(execution.happens_before(3, 2));
+    }
+  }
+
+  SECTION("Example 2")
+  {
+    const auto a1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a2 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a3 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a4 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+
+    // Notice that `a5` and `a6` are executed by the same actor; thus, although
+    // the actor is executing independent actions, each still "happen-before"
+    // the another
+
+    Execution execution;
+    execution.push_transition(a1);
+    execution.push_transition(a2);
+    execution.push_transition(a3);
+    execution.push_transition(a4);
+
+    SECTION("Happens-before is irreflexive")
+    {
+      REQUIRE_FALSE(execution.happens_before(0, 0));
+      REQUIRE_FALSE(execution.happens_before(1, 1));
+      REQUIRE_FALSE(execution.happens_before(2, 2));
+      REQUIRE_FALSE(execution.happens_before(3, 3));
+    }
+
+    SECTION("Happens-before values for each pair of events")
+    {
+      REQUIRE_FALSE(execution.happens_before(0, 1));
+      REQUIRE_FALSE(execution.happens_before(0, 2));
+      REQUIRE_FALSE(execution.happens_before(0, 3));
+      REQUIRE(execution.happens_before(1, 2));
+      REQUIRE(execution.happens_before(1, 3));
+      REQUIRE(execution.happens_before(2, 3));
+    }
+
+    SECTION("Happens-before is a subset of 'occurs-before'")
+    {
+      REQUIRE_FALSE(execution.happens_before(1, 0));
+      REQUIRE_FALSE(execution.happens_before(2, 0));
+      REQUIRE_FALSE(execution.happens_before(3, 0));
+      REQUIRE_FALSE(execution.happens_before(2, 1));
+      REQUIRE_FALSE(execution.happens_before(3, 1));
+      REQUIRE_FALSE(execution.happens_before(3, 2));
+    }
+  }
+
+  SECTION("Happens-before is transitively-closed")
+  {
+    SECTION("Example 1")
+    {
+      // Given a reversible race between events `e1` and `e3` in a simulation,
+      // we assert that `e5` would be eliminated from being contained in
+      // the sequence `notdep(e1, E)`
+      const auto e0 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+      const auto e1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+      const auto e2 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+      const auto e3 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+      const auto e4 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+
+      Execution execution;
+      execution.push_partial_execution(PartialExecution{e0, e1, e2, e3, e4});
+      REQUIRE(execution.happens_before(0, 2));
+      REQUIRE(execution.happens_before(2, 4));
+      REQUIRE(execution.happens_before(0, 4));
+    }
+
+    SECTION("Stress testing transitivity of the happens-before relation")
+    {
+      // This test verifies that for each triple of events
+      // in the execution, for a modestly intersting one,
+      // that transitivity holds
+      const auto e0  = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+      const auto e1  = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+      const auto e2  = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+      const auto e3  = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 2, -10);
+      const auto e4  = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+      const auto e5  = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 0);
+      const auto e6  = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 2, -5);
+      const auto e7  = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+      const auto e8  = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 0);
+      const auto e9  = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 2, -10);
+      const auto e10 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+
+      Execution execution;
+      execution.push_partial_execution(PartialExecution{e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10});
+
+      const auto max_handle = execution.get_latest_event_handle();
+      for (Execution::EventHandle e_i = 0; e_i < max_handle; ++e_i) {
+        for (Execution::EventHandle e_j = 0; e_j < max_handle; ++e_j) {
+          for (Execution::EventHandle e_k = 0; e_k < max_handle; ++e_k) {
+            const bool e_i_before_e_j = execution.happens_before(e_i, e_j);
+            const bool e_j_before_e_k = execution.happens_before(e_j, e_k);
+            const bool e_i_before_e_k = execution.happens_before(e_i, e_k);
+            // Logical equivalent of `e_i_before_e_j ^ e_j_before_e_k --> e_i_before_e_k`
+            REQUIRE((not(e_i_before_e_j && e_j_before_e_k) || e_i_before_e_k));
+          }
+        }
+      }
+    }
+  }
+}
+
+TEST_CASE("simgrid::mc::odpor::Execution: Testing Racing Events and Initials")
+{
+  SECTION("Example 1")
+  {
+    const auto a1 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto a3 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a4 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a5 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+
+    Execution execution;
+    execution.push_transition(a1);
+    execution.push_transition(a2);
+    execution.push_transition(a3);
+    execution.push_transition(a4);
+    execution.push_transition(a5);
+
+    // Nothing comes before event 0
+    REQUIRE(execution.get_racing_events_of(0) == std::unordered_set<Execution::EventHandle>{});
+
+    // Events 0 and 1 are independent
+    REQUIRE(execution.get_racing_events_of(1) == std::unordered_set<Execution::EventHandle>{});
+
+    // 2 and 1 are executed by different actors and happen right after each other
+    REQUIRE(execution.get_racing_events_of(2) == std::unordered_set<Execution::EventHandle>{1});
+
+    // Although a3 and a4 are dependent, they are executed by the same actor
+    REQUIRE(execution.get_racing_events_of(3) == std::unordered_set<Execution::EventHandle>{});
+
+    // Event 4 is in a race with neither event 0 nor event 2 since those events
+    // "happen-before" event 3 with which event 4 races
+    //
+    // Furthermore, event 1 is run by the same actor and thus also is not in a race.
+    // Hence, only event 3 races with event 4
+    REQUIRE(execution.get_racing_events_of(4) == std::unordered_set<Execution::EventHandle>{3});
+  }
+
+  SECTION("Example 2: Events with multiple races")
+  {
+    const auto a1 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto a3 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a4 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+
+    Execution execution;
+    execution.push_transition(a1);
+    execution.push_transition(a2);
+    execution.push_transition(a3);
+    execution.push_transition(a4);
+
+    // Nothing comes before event 0
+    REQUIRE(execution.get_racing_events_of(0) == std::unordered_set<Execution::EventHandle>{});
+
+    // Events 0 and 1 are independent
+    REQUIRE(execution.get_racing_events_of(1) == std::unordered_set<Execution::EventHandle>{});
+
+    // Event 2 is independent with event 1 and run by the same actor as event 0
+    REQUIRE(execution.get_racing_events_of(2) == std::unordered_set<Execution::EventHandle>{});
+
+    // All events are dependent with event 3, but event 0 "happens-before" event 2
+    REQUIRE(execution.get_racing_events_of(3) == std::unordered_set<Execution::EventHandle>{1, 2});
+
+    SECTION("Check initials with respect to event 1")
+    {
+      // First, note that v := notdep(1, execution).p == {e2}.{e3} == {e2, e3}
+      // Since e2 -->_E e3, actor 3 is not an initial for E' := pre(1, execution)
+      // with respect to `v`. e2, however, has nothing happening before it in dom_E(v),
+      // so it is an initial of E' wrt. `v`
+      const auto initial_wrt_event1 = execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{});
+      REQUIRE(initial_wrt_event1 == std::unordered_set<aid_t>{1});
+    }
+
+    SECTION("Check initials with respect to event 2")
+    {
+      // First, note that v := notdep(1, execution).p == {}.{e3} == {e3}
+      // e3 has nothing happening before it in dom_E(v), so it is an initial
+      // of E' wrt. `v`
+      const auto initial_wrt_event2 = execution.get_missing_source_set_actors_from(2, std::unordered_set<aid_t>{});
+      REQUIRE(initial_wrt_event2 == std::unordered_set<aid_t>{3});
+    }
+  }
+
+  SECTION("Example 3: Testing 'Lock' Example")
+  {
+    // In this example, `e0` and `e1` are lock actions that
+    // are in a race. We assert that
+    const auto e0 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto e1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto e2 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto e3 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e4 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+
+    Execution execution;
+    execution.push_transition(e0);
+    execution.push_transition(e1);
+    execution.push_transition(e2);
+    execution.push_transition(e3);
+    execution.push_transition(e4);
+    REQUIRE(execution.get_racing_events_of(4) == std::unordered_set<Execution::EventHandle>{0});
+  }
+
+  SECTION("Example 4: Indirect Races")
+  {
+    const auto e0 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto e2 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e3 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e4 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 6);
+    const auto e5 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto e6 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto e7 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto e8 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto e9 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2);
+
+    Execution execution(PartialExecution{e0, e1, e2, e3, e4, e5, e6, e7, e8, e9});
+
+    // Nothing comes before event 0
+    REQUIRE(execution.get_racing_events_of(0) == std::unordered_set<Execution::EventHandle>{});
+
+    // Events 0 and 1 are independent
+    REQUIRE(execution.get_racing_events_of(1) == std::unordered_set<Execution::EventHandle>{});
+
+    // Events 1 and 2 are independent
+    REQUIRE(execution.get_racing_events_of(2) == std::unordered_set<Execution::EventHandle>{});
+
+    // Events 1 and 3 are independent; the rest are executed by the same actor
+    REQUIRE(execution.get_racing_events_of(3) == std::unordered_set<Execution::EventHandle>{});
+
+    // 1. Events 3 and 4 race
+    // 2. Events 2 and 4 do NOT race since 2 --> 3 --> 4
+    // 3. Events 1 and 4 do NOT race since 1 is independent of 4
+    // 4. Events 0 and 4 do NOT race since 0 --> 2 --> 4
+    REQUIRE(execution.get_racing_events_of(4) == std::unordered_set<Execution::EventHandle>{3});
+
+    // Events 4 and 5 race; and because everyone before 4 (including 3) either
+    // a) happens-before, b) races, or c) does not race with 4, 4 is the race
+    REQUIRE(execution.get_racing_events_of(5) == std::unordered_set<Execution::EventHandle>{4});
+
+    // The same logic that applied to event 5 applies to event 6
+    REQUIRE(execution.get_racing_events_of(6) == std::unordered_set<Execution::EventHandle>{5});
+
+    // The same logic applies, except that this time since events 6 and 7 are run
+    // by the same actor, they don'tt actually race with one another
+    REQUIRE(execution.get_racing_events_of(7) == std::unordered_set<Execution::EventHandle>{});
+
+    // Event 8 is independent with everything
+    REQUIRE(execution.get_racing_events_of(8) == std::unordered_set<Execution::EventHandle>{});
+
+    // Event 9 is independent with events 7 and 8; event 6, however, is in race with 9.
+    // The same logic above eliminates events before 6
+    REQUIRE(execution.get_racing_events_of(9) == std::unordered_set<Execution::EventHandle>{6});
+  }
+
+  SECTION("Example 5: Stress testing race detection")
+  {
+    const auto e0  = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto e1  = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e2  = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e3  = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 2, -10);
+    const auto e4  = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto e5  = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 0);
+    const auto e6  = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 2, -5);
+    const auto e7  = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 1, -5);
+    const auto e8  = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 0, 4);
+    const auto e9  = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 2, -10);
+    const auto e10 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+
+    Execution execution(PartialExecution{e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10});
+
+    // Nothing comes before event 0
+    CHECK(execution.get_racing_events_of(0) == std::unordered_set<Execution::EventHandle>{});
+
+    // Events 0 and 1 are independent
+    CHECK(execution.get_racing_events_of(1) == std::unordered_set<Execution::EventHandle>{});
+
+    // Events 1 and 2 are executed by the same actor, even though they are dependent
+    CHECK(execution.get_racing_events_of(2) == std::unordered_set<Execution::EventHandle>{});
+
+    // Events 2 and 3 are independent while events 1 and 2 are dependent
+    CHECK(execution.get_racing_events_of(3) == std::unordered_set<Execution::EventHandle>{1});
+
+    // Event 4 is independent with everything so it can never be in a race
+    CHECK(execution.get_racing_events_of(4) == std::unordered_set<Execution::EventHandle>{});
+
+    // Event 5 is independent with event 4. Since events 2 and 3 are dependent with event 5,
+    // but are independent of each other, both events are in a race with event 5
+    CHECK(execution.get_racing_events_of(5) == std::unordered_set<Execution::EventHandle>{2, 3});
+
+    // Events 5 and 6 are dependent. Everyone before 5 who's dependent with 5
+    // cannot be in a race with 6; everyone before 5 who's independent with 5
+    // could not race with 6
+    CHECK(execution.get_racing_events_of(6) == std::unordered_set<Execution::EventHandle>{5});
+
+    // Same goes for event 7 as for 6
+    CHECK(execution.get_racing_events_of(7) == std::unordered_set<Execution::EventHandle>{6});
+
+    // Events 5 and 8 are both run by the same actor; events in-between are independent
+    CHECK(execution.get_racing_events_of(8) == std::unordered_set<Execution::EventHandle>{});
+
+    // Event 6 blocks event 9 from racing with event 6
+    CHECK(execution.get_racing_events_of(9) == std::unordered_set<Execution::EventHandle>{});
+
+    // Event 10 is independent with everything so it can never be in a race
+    CHECK(execution.get_racing_events_of(10) == std::unordered_set<Execution::EventHandle>{});
+  }
+
+  SECTION("Example with many races for one event")
+  {
+    const auto e0 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e1 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto e2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto e3 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto e4 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 5);
+    const auto e5 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 6);
+    const auto e6 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 7);
+
+    Execution execution(PartialExecution{e0, e1, e2, e3, e4, e5, e6});
+    REQUIRE(execution.get_racing_events_of(6) == std::unordered_set<Execution::EventHandle>{0, 1, 2, 3, 4, 5});
+  }
+}
+
+TEST_CASE("simgrid::mc::odpor::Execution: Independence Tests")
+{
+  SECTION("Complete independence")
+  {
+    // Every transition is independent with every other and run by different actors. Hopefully
+    // we say that the events are independent with each other...
+    const auto a0 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto a2 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a3 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto a4 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 5);
+    const auto a5 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 6);
+    const auto a6 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 7);
+    const auto a7 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 7);
+    Execution execution(PartialExecution{a0, a1, a2, a3});
+
+    REQUIRE(execution.is_independent_with_execution_of(PartialExecution{a4, a5}, a6));
+    REQUIRE(execution.is_independent_with_execution_of(PartialExecution{a6, a5}, a1));
+    REQUIRE(execution.is_independent_with_execution_of(PartialExecution{a6, a1}, a0));
+    REQUIRE(Execution().is_independent_with_execution_of(PartialExecution{a7, a7, a1}, a3));
+    REQUIRE(Execution().is_independent_with_execution_of(PartialExecution{a4, a0, a1}, a3));
+    REQUIRE(Execution().is_independent_with_execution_of(PartialExecution{a0, a7, a1}, a2));
+
+    // In this case, we notice that `a6` and `a7` are executed by the same actor.
+    // Hence, a6 cannot be independent with extending the execution with a4.a5.a7.
+    // Notice that we are treating *a6* as the next step of actor 7 (that is what we
+    // supplied as an argument)
+    REQUIRE_FALSE(execution.is_independent_with_execution_of(PartialExecution{a4, a5, a7}, a6));
+  }
+
+  SECTION("Independence is trivial with an empty extension")
+  {
+    REQUIRE(Execution().is_independent_with_execution_of(
+        PartialExecution{}, std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1)));
+  }
+
+  SECTION("Dependencies stopping independence from being possible")
+  {
+    const auto a0    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a1    = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a2    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a3    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto a4    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto a5    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto a6    = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a7    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a8    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto indep = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    Execution execution(PartialExecution{a0, a1, a2, a3});
+
+    // We see that although `a4` comes after `a1` with which it is dependent, it
+    // would come before "a6" in the partial execution `w`, so it would not be independent
+    REQUIRE_FALSE(execution.is_independent_with_execution_of(PartialExecution{a5, a6, a7}, a4));
+
+    // Removing `a6` from the picture, though, gives us the independence we're looking for.
+    REQUIRE(execution.is_independent_with_execution_of(PartialExecution{a5, a7}, a4));
+
+    // BUT, we we ask about a transition which is run by the same actor, even if they would be
+    // independent otherwise, we again lose independence
+    REQUIRE_FALSE(execution.is_independent_with_execution_of(PartialExecution{a5, a7, a8}, a4));
+
+    // This is a more interesting case:
+    // `indep` clearly is independent with the rest of the series, even though
+    // there are dependencies among the other events in the partial execution
+    REQUIRE(Execution().is_independent_with_execution_of(PartialExecution{a1, a6, a7}, indep));
+
+    // This ensures that independence is trivial with an empty partial execution
+    REQUIRE(execution.is_independent_with_execution_of(PartialExecution{}, a1));
+  }
+
+  SECTION("More interesting dependencies stopping independence")
+  {
+    const auto e0 = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 1, 5);
+    const auto e1 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto e3 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto e4 = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 3, 5);
+    const auto e5 = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 4, 4);
+    Execution execution(PartialExecution{e0, e1, e2, e3, e4, e5});
+
+    SECTION("Action run by same actor disqualifies independence")
+    {
+      const auto w_1 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+      const auto w_2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+      const auto w_3 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+      const auto w_4 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 4);
+      const auto w   = PartialExecution{w_1, w_2, w_3};
+
+      const auto actor4_action  = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 4);
+      const auto actor4_action2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+
+      // Action `actor4_action` is independent with everything EXCEPT the last transition
+      // which is executed by the same actor
+      execution.is_independent_with_execution_of(w, actor4_action);
+
+      // Action `actor4_action2` is independent with everything
+      // EXCEPT the last transition which is executed by the same actor
+      execution.is_independent_with_execution_of(w, actor4_action);
+    }
+  }
+}
+
+TEST_CASE("simgrid::mc::odpor::Execution: Initials Test")
+{
+  const auto a0    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto a1    = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto a2    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 3);
+  const auto a3    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+  const auto a4    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+  const auto a5    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2);
+  const auto a6    = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+  const auto a7    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto a8    = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+  const auto indep = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+  Execution execution(PartialExecution{a0, a1, a2, a3});
+
+  SECTION("Initials trivial with empty executions")
+  {
+    // There are no initials for an empty extension since
+    // a requirement is that the actor be contained in the
+    // extension itself
+    REQUIRE_FALSE(execution.is_initial_after_execution_of(PartialExecution{}, 0));
+    REQUIRE_FALSE(execution.is_initial_after_execution_of(PartialExecution{}, 1));
+    REQUIRE_FALSE(execution.is_initial_after_execution_of(PartialExecution{}, 2));
+    REQUIRE_FALSE(Execution().is_initial_after_execution_of(PartialExecution{}, 0));
+    REQUIRE_FALSE(Execution().is_initial_after_execution_of(PartialExecution{}, 1));
+    REQUIRE_FALSE(Execution().is_initial_after_execution_of(PartialExecution{}, 2));
+  }
+
+  SECTION("The first actor is always an initial")
+  {
+    // Even in the case that the action is dependent with every
+    // other, if it is the first action to occur as part of the
+    // extension of the execution sequence, by definition it is
+    // an initial (recall that initials intuitively tell you which
+    // actions can be run starting from an execution `E`; if we claim
+    // to witness `E.w`, then clearly at least the first step of `w` is an initial)
+    REQUIRE(execution.is_initial_after_execution_of(PartialExecution{a3}, a3->aid_));
+    REQUIRE(execution.is_initial_after_execution_of(PartialExecution{a2, a3, a6}, a2->aid_));
+    REQUIRE(execution.is_initial_after_execution_of(PartialExecution{a6, a1, a0}, a6->aid_));
+    REQUIRE(Execution().is_initial_after_execution_of(PartialExecution{a0, a1, a2, a3}, a0->aid_));
+    REQUIRE(Execution().is_initial_after_execution_of(PartialExecution{a5, a2, a8, a7, a6, a0}, a5->aid_));
+    REQUIRE(Execution().is_initial_after_execution_of(PartialExecution{a8, a7, a1}, a8->aid_));
+  }
+
+  SECTION("Example: Disqualified and re-qualified after switching ordering")
+  {
+    // Even though actor `2` executes an independent
+    // transition later on, it is blocked since its first transition
+    // is dependent with actor 1's transition
+    REQUIRE_FALSE(Execution().is_initial_after_execution_of(PartialExecution{a1, a5, indep}, 2));
+
+    // However, if actor 2 executes its independent action first, it DOES become an initial
+    REQUIRE(Execution().is_initial_after_execution_of(PartialExecution{a1, indep, a5}, 2));
+  }
+
+  SECTION("Example: Large partial executions")
+  {
+    // The record trace is `1 3 4 4 3 1 4 2`
+
+    // Actor 1 starts the execution
+    REQUIRE(Execution().is_initial_after_execution_of(PartialExecution{a1, a2, a3, a4, a6, a7, a8, indep}, 1));
+
+    // Actor 2 all the way at the end is independent with everybody: despite
+    // the tangle that comes before it, we can more it to the front with no issue
+    REQUIRE(Execution().is_initial_after_execution_of(PartialExecution{a1, a2, a3, a4, a6, a7, a8, indep}, 2));
+
+    // Actor 3 is eliminated since `a1` is dependent with `a2`
+    REQUIRE_FALSE(Execution().is_initial_after_execution_of(PartialExecution{a1, a2, a3, a4, a6, a7, a8, indep}, 3));
+
+    // Likewise with actor 4
+    REQUIRE_FALSE(Execution().is_initial_after_execution_of(PartialExecution{a1, a2, a3, a4, a6, a7, a8, indep}, 4));
+  }
+
+  SECTION("Example: Stress tests for initials computation")
+  {
+    const auto v_1 = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 1, 3);
+    const auto v_2 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto v_3 = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 2, 3);
+    const auto v_4 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto v_5 = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 3, 8);
+    const auto v_6 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto v_7 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto v_8 = std::make_shared<DependentIfSameValueAction>(Transition::Type::UNKNOWN, 4, 3);
+    const auto v   = PartialExecution{v_1, v_2, v_3, v_4};
+
+    // Actor 1 being the first actor in the expansion, it is clearly an initial
+    REQUIRE(Execution().is_initial_after_execution_of(v, 1));
+
+    // Actor 2 can't be switched before actor 1 without creating an trace
+    // that leads to a different state than that of `E.v := ().v := v`
+    REQUIRE_FALSE(Execution().is_initial_after_execution_of(v, 2));
+
+    // The first action of Actor 3 is independent with what comes before it, so it can
+    // be moved forward. Note that this is the case even though it later executes and action
+    // that's dependent with most everyone else
+    REQUIRE(Execution().is_initial_after_execution_of(v, 3));
+
+    // Actor 4 is blocked actor 3's second action `v_7`
+    REQUIRE_FALSE(Execution().is_initial_after_execution_of(v, 4));
+  }
+}
+
+TEST_CASE("simgrid::mc::odpor::Execution: SDPOR Backtracking Simulation")
+{
+  // This test case assumes that each detected race is detected to also
+  // be reversible. For each reversible
+  const auto e0 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto e1 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto e2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 3);
+  const auto e3 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+  const auto e4 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+  const auto e5 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2);
+  const auto e6 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+  const auto e7 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+
+  Execution execution;
+
+  execution.push_transition(e0);
+  REQUIRE(execution.get_racing_events_of(0) == std::unordered_set<Execution::EventHandle>{});
+
+  execution.push_transition(e1);
+  REQUIRE(execution.get_racing_events_of(1) == std::unordered_set<Execution::EventHandle>{});
+
+  // Actor 3, since it starts the extension from event 1, clearly is an initial from there
+  execution.push_transition(e2);
+  REQUIRE(execution.get_racing_events_of(2) == std::unordered_set<Execution::EventHandle>{1});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{}) == std::unordered_set<aid_t>{3});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{4, 5}) ==
+        std::unordered_set<aid_t>{3});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{3}) == std::unordered_set<aid_t>{});
+
+  // e1 and e3 are in an reversible race. Actor 4 is not hindered from being moved to
+  // the front since e2 is independent with e3; hence, it is an initial
+  execution.push_transition(e3);
+  REQUIRE(execution.get_racing_events_of(3) == std::unordered_set<Execution::EventHandle>{1});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{}) == std::unordered_set<aid_t>{4});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{3, 5}) ==
+        std::unordered_set<aid_t>{4});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{4}) == std::unordered_set<aid_t>{});
+
+  // e4 is not in a race since e3 is run by the same actor and occurs before e4
+  execution.push_transition(e4);
+  REQUIRE(execution.get_racing_events_of(4) == std::unordered_set<Execution::EventHandle>{});
+
+  // e5 is independent with everything between e1 and e5, and `proc(e5) == 2`
+  execution.push_transition(e5);
+  REQUIRE(execution.get_racing_events_of(5) == std::unordered_set<Execution::EventHandle>{1});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{}) == std::unordered_set<aid_t>{2});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{4, 5}) ==
+        std::unordered_set<aid_t>{2});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{2}) == std::unordered_set<aid_t>{});
+
+  // Event 6 has two races: one with event 4 and one with event 5. In the latter race, actor 3 follows
+  // immediately after and so is evidently a source set actor; in the former race, only actor 2 can
+  // be brought to the front of the queue
+  execution.push_transition(e6);
+  REQUIRE(execution.get_racing_events_of(6) == std::unordered_set<Execution::EventHandle>{4, 5});
+  CHECK(execution.get_missing_source_set_actors_from(4, std::unordered_set<aid_t>{}) == std::unordered_set<aid_t>{2});
+  CHECK(execution.get_missing_source_set_actors_from(4, std::unordered_set<aid_t>{6, 7}) ==
+        std::unordered_set<aid_t>{2});
+  CHECK(execution.get_missing_source_set_actors_from(4, std::unordered_set<aid_t>{2}) == std::unordered_set<aid_t>{});
+  CHECK(execution.get_missing_source_set_actors_from(5, std::unordered_set<aid_t>{}) == std::unordered_set<aid_t>{3});
+  CHECK(execution.get_missing_source_set_actors_from(5, std::unordered_set<aid_t>{6, 7}) ==
+        std::unordered_set<aid_t>{3});
+  CHECK(execution.get_missing_source_set_actors_from(5, std::unordered_set<aid_t>{3}) == std::unordered_set<aid_t>{});
+
+  // Finally, event e7 races with e6 and `proc(e7) = 1` is brought forward
+  execution.push_transition(e7);
+  REQUIRE(execution.get_racing_events_of(7) == std::unordered_set<Execution::EventHandle>{6});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{}) == std::unordered_set<aid_t>{1});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{4, 5}) ==
+        std::unordered_set<aid_t>{1});
+  CHECK(execution.get_missing_source_set_actors_from(1, std::unordered_set<aid_t>{1}) == std::unordered_set<aid_t>{});
+}
+
+TEST_CASE("simgrid::mc::odpor::Execution: ODPOR Smallest Sequence Tests")
+{
+  const auto a0 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+  const auto a1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 4);
+  const auto a2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 3);
+  const auto a3 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto a4 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+  const auto a5 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+
+  Execution execution;
+  execution.push_transition(a0);
+  execution.push_transition(a1);
+  execution.push_transition(a2);
+  execution.push_transition(a3);
+  execution.push_transition(a4);
+  execution.push_transition(a5);
+
+  SECTION("Equivalent insertions")
+  {
+    SECTION("Example: Eliminated through independence")
+    {
+      // TODO: Is this even a sensible question to ask if the two sequences
+      // don't agree upon what each actor executed after `E`?
+      const auto insertion =
+          Execution().get_shortest_odpor_sq_subset_insertion(PartialExecution{a1, a2}, PartialExecution{a2, a5});
+      REQUIRE(insertion.has_value());
+      REQUIRE(insertion.value() == PartialExecution{});
+    }
+
+    SECTION("Exact match yields empty set")
+    {
+      const auto insertion =
+          Execution().get_shortest_odpor_sq_subset_insertion(PartialExecution{a1, a2}, PartialExecution{a1, a2});
+      REQUIRE(insertion.has_value());
+      REQUIRE(insertion.value() == PartialExecution{});
+    }
+  }
+
+  SECTION("Match against empty executions")
+  {
+    SECTION("Empty `v` trivially yields `w`")
+    {
+      auto insertion =
+          Execution().get_shortest_odpor_sq_subset_insertion(PartialExecution{}, PartialExecution{a1, a5, a2});
+      REQUIRE(insertion.has_value());
+      REQUIRE(insertion.value() == PartialExecution{a1, a5, a2});
+
+      insertion = execution.get_shortest_odpor_sq_subset_insertion(PartialExecution{}, PartialExecution{a1, a5, a2});
+      REQUIRE(insertion.has_value());
+      REQUIRE(insertion.value() == PartialExecution{a1, a5, a2});
+    }
+
+    SECTION("Empty `w` yields empty execution")
+    {
+      auto insertion =
+          Execution().get_shortest_odpor_sq_subset_insertion(PartialExecution{a1, a4, a5}, PartialExecution{});
+      REQUIRE(insertion.has_value());
+      REQUIRE(insertion.value() == PartialExecution{});
+
+      insertion = execution.get_shortest_odpor_sq_subset_insertion(PartialExecution{a1, a5, a2}, PartialExecution{});
+      REQUIRE(insertion.has_value());
+      REQUIRE(insertion.value() == PartialExecution{});
+    }
+  }
+}
diff --git a/src/mc/explo/odpor/WakeupTree.cpp b/src/mc/explo/odpor/WakeupTree.cpp
new file mode 100644 (file)
index 0000000..73b2171
--- /dev/null
@@ -0,0 +1,249 @@
+/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/mc/explo/odpor/WakeupTree.hpp"
+#include "src/mc/explo/odpor/Execution.hpp"
+#include "xbt/asserts.h"
+#include "xbt/string.hpp"
+
+#include <algorithm>
+#include <exception>
+#include <memory>
+#include <queue>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_wut, mc, "Logging specific to ODPOR WakeupTrees");
+
+namespace simgrid::mc::odpor {
+
+void WakeupTreeNode::add_child(WakeupTreeNode* node)
+{
+  this->children_.push_back(node);
+  node->parent_ = this;
+}
+
+std::string WakeupTreeNode::string_of_whole_tree(int indentation_level) const
+{
+  std::string tabulations = "";
+  for (int i = 0; i < indentation_level; i++)
+    tabulations += "  ";
+  std::string final_string = action_ == nullptr ? "<>\n"
+                                                : tabulations + "Actor " + std::to_string(action_->aid_) + ": " +
+                                                      action_->to_string(true) + "\n";
+  for (auto node : children_)
+    final_string += node->string_of_whole_tree(indentation_level + 1);
+  return final_string;
+}
+
+PartialExecution WakeupTreeNode::get_sequence() const
+{
+  // TODO: Prevent having to compute this at the node level
+  // and instead track this with the iterator
+  PartialExecution seq_;
+  const WakeupTreeNode* cur_node = this;
+  while (cur_node != nullptr && not cur_node->is_root()) {
+    seq_.push_front(cur_node->action_);
+    cur_node = cur_node->parent_;
+  }
+  return seq_;
+}
+
+void WakeupTreeNode::detatch_from_parent()
+{
+  if (parent_ != nullptr) {
+    // TODO: There may be a better method
+    // of keeping track of a node's reference to
+    // its parent, perhaps keeping track
+    // of a std::list<>::iterator instead.
+    // This would allow us to detach a node
+    // in O(1) instead of O(|children|) time
+    parent_->children_.remove(this);
+  }
+}
+
+WakeupTree::WakeupTree() : WakeupTree(std::make_unique<WakeupTreeNode>()) {}
+WakeupTree::WakeupTree(std::unique_ptr<WakeupTreeNode> root) : root_(root.get())
+{
+  this->insert_node(std::move(root));
+}
+
+std::vector<std::string> WakeupTree::get_single_process_texts() const
+{
+  std::vector<std::string> trace;
+  for (const auto* child : root_->children_) {
+    const auto t = child->get_action();
+    auto message = xbt::string_printf("Actor %ld: %s", t->aid_, t->to_string(true).c_str());
+    trace.emplace_back(std::move(message));
+  }
+  return trace;
+}
+
+std::optional<aid_t> WakeupTree::get_min_single_process_actor() const
+{
+  if (const auto node = get_min_single_process_node(); node.has_value()) {
+    return node.value()->get_actor();
+  }
+  return std::nullopt;
+}
+
+std::optional<WakeupTreeNode*> WakeupTree::get_min_single_process_node() const
+{
+  if (empty()) {
+    return std::nullopt;
+  }
+  // INVARIANT: The induced post-order relation always places children
+  // in order before the parent. The list of children maintained by
+  // each node represents that ordering, and the first child of
+  // the root is by definition the smallest of the single-process nodes
+  xbt_assert(not this->root_->children_.empty(), "What the");
+  return this->root_->children_.front();
+}
+
+std::string WakeupTree::string_of_whole_tree() const
+{
+  return root_->string_of_whole_tree(0);
+}
+
+WakeupTree WakeupTree::make_subtree_rooted_at(WakeupTreeNode* root)
+{
+  // Perform a BFS search to perform a deep copy of the portion
+  // of the tree underneath and including `root`. Note that `root`
+  // is contained within the context of a *different* wakeup tree;
+  // hence, we have to be careful to update each node's children
+  // appropriately
+  auto subtree = WakeupTree();
+
+  std::list<std::pair<WakeupTreeNode*, WakeupTreeNode*>> frontier{std::make_pair(root, subtree.root_)};
+  while (not frontier.empty()) {
+    auto [node_in_other_tree, subtree_equivalent] = frontier.front();
+    frontier.pop_front();
+
+    // For each child of the node corresponding to that in `subtree`,
+    // make clones of each of its children and add them to `frontier`
+    // to that their children are added, and so on.
+    for (WakeupTreeNode* child_in_other_tree : node_in_other_tree->get_ordered_children()) {
+      WakeupTreeNode* child_equivalent = subtree.make_node(child_in_other_tree->get_action());
+      subtree_equivalent->add_child(child_equivalent);
+      frontier.push_back(std::make_pair(child_in_other_tree, child_equivalent));
+    }
+  }
+  return subtree;
+}
+
+void WakeupTree::remove_subtree_rooted_at(WakeupTreeNode* root)
+{
+  if (not contains(root)) {
+    throw std::invalid_argument("Attempting to remove a subtree pivoted from a node "
+                                "that is not contained in this wakeup tree");
+  }
+
+  std::list<WakeupTreeNode*> subtree_contents{root};
+  std::list<WakeupTreeNode*> frontier{root};
+  while (not frontier.empty()) {
+    const auto* node = frontier.front();
+    frontier.pop_front();
+    for (const auto& child : node->get_ordered_children()) {
+      frontier.push_back(child);
+      subtree_contents.push_back(child);
+    }
+  }
+
+  // After having found each node with BFS, now we can
+  // remove them. This prevents the "joys" of iteration during mutation.
+  // We also remove the `root` from being referenced by its own parent (since
+  // it will soon be destroyed)
+  root->detatch_from_parent();
+  for (WakeupTreeNode* node_to_remove : subtree_contents) {
+    this->remove_node(node_to_remove);
+  }
+}
+
+void WakeupTree::remove_subtree_at_aid(aid_t proc)
+{
+  for (const auto& child : root_->get_ordered_children())
+    if (child->get_actor() == proc) {
+      this->remove_subtree_rooted_at(child);
+      break;
+    }
+}
+
+void WakeupTree::remove_min_single_process_subtree()
+{
+  if (const auto node = get_min_single_process_node(); node.has_value()) {
+    remove_subtree_rooted_at(node.value());
+  }
+}
+
+bool WakeupTree::contains(const WakeupTreeNode* node) const
+{
+  return std::find_if(this->nodes_.begin(), this->nodes_.end(), [=](const auto& pair) { return pair.first == node; }) !=
+         this->nodes_.end();
+}
+
+WakeupTreeNode* WakeupTree::make_node(std::shared_ptr<Transition> u)
+{
+  auto node                 = std::make_unique<WakeupTreeNode>(std::move(u));
+  auto* node_handle         = node.get();
+  this->nodes_[node_handle] = std::move(node);
+  return node_handle;
+}
+
+void WakeupTree::insert_node(std::unique_ptr<WakeupTreeNode> node)
+{
+  auto* node_handle         = node.get();
+  this->nodes_[node_handle] = std::move(node);
+}
+
+void WakeupTree::remove_node(WakeupTreeNode* node)
+{
+  this->nodes_.erase(node);
+}
+
+WakeupTree::InsertionResult WakeupTree::insert(const Execution& E, const PartialExecution& w)
+{
+  // See section 6.2 of Abdulla. et al.'s 2017 ODPOR paper for details
+
+  // Find the first node `v` in the tree such that
+  // `v ~_[E] w` and `v`  is not a leaf node
+  for (WakeupTreeNode* node : *this) {
+    if (const auto shortest_sequence = E.get_shortest_odpor_sq_subset_insertion(node->get_sequence(), w);
+        shortest_sequence.has_value()) {
+      // Insert the sequence as a child of `node`, but only
+      // if the node is not already a leaf
+      if (not node->is_leaf() || node == this->root_) {
+        // NOTE: It's entirely possible that the shortest
+        // sequence we are inserting is empty. Consider the
+        // following two cases:
+        //
+        // 1. `w` is itself empty. Evidently, insertion succeeds but nothing needs
+        // to happen
+        //
+        // 2. a leaf node in the tree already contains `w` exactly.
+        // In this case, the empty `w'` returned (viz. `shortest_seq`)
+        // such that `w [=_[E] v.w'` would be empty
+        this->insert_sequence_after(node, shortest_sequence.value());
+        return node == this->root_ ? InsertionResult::root : InsertionResult::interior_node;
+      }
+      // Since we're following the post-order traversal of the tree,
+      // the first such node we see is the smallest w.r.t "<"
+      return InsertionResult::leaf;
+    }
+  }
+  xbt_die("Insertion should always succeed with the root node (which contains no "
+          "prior execution). If we've reached this point, this implies either that "
+          "the wakeup tree traversal is broken or that computation of the shortest "
+          "sequence to insert into the tree is broken");
+}
+
+void WakeupTree::insert_sequence_after(WakeupTreeNode* node, const PartialExecution& w)
+{
+  WakeupTreeNode* cur_node = node;
+  for (const auto& w_i : w) {
+    WakeupTreeNode* new_node = this->make_node(w_i);
+    cur_node->add_child(new_node);
+    cur_node = new_node;
+  }
+}
+
+} // namespace simgrid::mc::odpor
diff --git a/src/mc/explo/odpor/WakeupTree.hpp b/src/mc/explo/odpor/WakeupTree.hpp
new file mode 100644 (file)
index 0000000..def2840
--- /dev/null
@@ -0,0 +1,245 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_ODPOR_WAKEUP_TREE_HPP
+#define SIMGRID_MC_ODPOR_WAKEUP_TREE_HPP
+
+#include "src/mc/explo/odpor/WakeupTreeIterator.hpp"
+#include "src/mc/explo/odpor/odpor_forward.hpp"
+#include "src/mc/transition/Transition.hpp"
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace simgrid::mc::odpor {
+
+/**
+ * @brief A single node in a wakeup tree
+ *
+ * Each node in a wakeup tree represents a single step
+ * taken in an extension of the execution represented
+ * by the tree within which the node is contained. That is,
+ * a node in the tree is one step on a "pre-defined"
+ * path forward for some execution sequence. The partial
+ * execution that is implicitly represented by the node
+ * is that formed by taking each step on the (unique)
+ * path in the tree from the root node to this node.
+ * Thus, the tree itself contains all of the paths
+ * that "should be" searched, while each node is
+ * simply a step on each path.
+ */
+class WakeupTreeNode {
+private:
+  WakeupTreeNode* parent_ = nullptr;
+
+  /** An ordered list of children of for this node in the tree */
+  std::list<WakeupTreeNode*> children_;
+
+  /** @brief The contents of the node */
+  std::shared_ptr<Transition> action_;
+
+  /** @brief Removes the node as a child from the parent */
+  void detatch_from_parent();
+
+  /** Allows the owning tree to insert directly into the child */
+  friend WakeupTree;
+  friend WakeupTreeIterator;
+
+public:
+  explicit WakeupTreeNode(std::shared_ptr<Transition> u) : action_(u) {}
+
+  WakeupTreeNode()                                 = default;
+  ~WakeupTreeNode()                                = default;
+  WakeupTreeNode(const WakeupTreeNode&)            = delete;
+  WakeupTreeNode(WakeupTreeNode&&)                 = default;
+  WakeupTreeNode& operator=(const WakeupTreeNode&) = delete;
+  WakeupTreeNode& operator=(WakeupTreeNode&&)      = default;
+
+  auto begin() const { return this->children_.begin(); }
+  auto end() const { return this->children_.end(); }
+  auto rbegin() const { return this->children_.rbegin(); }
+  auto rend() const { return this->children_.rend(); }
+
+  bool is_leaf() const { return children_.empty(); }
+  bool is_root() const { return parent_ == nullptr; }
+  aid_t get_actor() const { return action_->aid_; }
+  PartialExecution get_sequence() const;
+  std::shared_ptr<Transition> get_action() const { return action_; }
+  const std::list<WakeupTreeNode*>& get_ordered_children() const { return children_; }
+
+  std::string string_of_whole_tree(int indentation_level) const;
+
+  /** Insert a node `node` as a new child of this node */
+  void add_child(WakeupTreeNode* node);
+};
+
+/**
+ * @brief The structure used by ODPOR to maintains paths of execution
+ * that should be followed in the future
+ *
+ * The wakeup tree data structure is formally defined in the Abdulla et al.
+ * 2017 ODPOR paper. Conceptually, the tree consists of nodes which are
+ * mapped to actions. Each node represents a partial extension of an execution,
+ * the complete extension being the transitions taken in sequence from
+ * the root of the tree to the node itself. Leaf nodes in the tree conceptually,
+ * then, represent paths that are guaranteed to explore different parts
+ * of the search space.
+ *
+ * Iteration over a wakeup tree occurs as a post-order traversal of its nodes
+ *
+ * @note A wakeup tree is defined relative to some execution `E`. The
+ * structure itself does not hold onto a reference of the execution with
+ * respect to which it is a wakeup tree.
+ *
+ * @todo: If the idea of execution "views"  is ever added -- viz. being able
+ * to share the contents of a single execution -- then a wakeup tree could
+ * contain a reference to such a view which would then be maintained by the
+ * manipulator of the tree
+ */
+class WakeupTree {
+private:
+  WakeupTreeNode* root_;
+
+  /**
+   * @brief All of the nodes that are currently are a part of the tree
+   *
+   * @invariant Each node event maps itself to the owner of that node,
+   * i.e. the unique pointer that manages the data at the address. The tree owns all
+   * of the addresses that are referenced by the nodes WakeupTreeNode.
+   * ODPOR guarantees that nodes are persisted as long as needed.
+   */
+  std::unordered_map<WakeupTreeNode*, std::unique_ptr<WakeupTreeNode>> nodes_;
+
+  void insert_node(std::unique_ptr<WakeupTreeNode> node);
+  void insert_sequence_after(WakeupTreeNode* node, const PartialExecution& w);
+  void remove_node(WakeupTreeNode* node);
+  bool contains(const WakeupTreeNode* node) const;
+
+  /**
+   * @brief Removes the node `root` and all of its descendants from
+   * this wakeup tree
+   *
+   * @throws: If the node `root` is not contained in this tree, an
+   * exception is raised
+   */
+  void remove_subtree_rooted_at(WakeupTreeNode* root);
+
+  /**
+   * @brief Adds a new node to the tree, disconnected from
+   * any other, which represents the partial execution
+   * "fragment" `u`
+   */
+  WakeupTreeNode* make_node(std::shared_ptr<Transition> u);
+
+  /* Allow the iterator to access the contents of the tree */
+  friend WakeupTreeIterator;
+
+public:
+  WakeupTree();
+  explicit WakeupTree(std::unique_ptr<WakeupTreeNode> root);
+
+  /**
+   * @brief Creates a copy of the subtree whose root is the node
+   * `root` in this tree
+   */
+  static WakeupTree make_subtree_rooted_at(WakeupTreeNode* root);
+
+  auto begin() const { return WakeupTreeIterator(*this); }
+  auto end() const { return WakeupTreeIterator(); }
+
+  std::vector<std::string> get_single_process_texts() const;
+
+  std::string string_of_whole_tree() const;
+
+  /**
+   * @brief Remove the subtree of the smallest (with respect
+   * to the tree's "<" relation) single-process node.
+   *
+   * A "single-process" node is one whose execution represents
+   * taking a single action (i.e. those of the root node). The
+   * smallest under "<" is that which is continuously selected and
+   * removed by ODPOR.
+   *
+   * If the tree is empty, this method has no effect.
+   */
+  void remove_min_single_process_subtree();
+
+  void remove_subtree_at_aid(aid_t proc);
+
+  /**
+   * @brief Whether or not this tree is considered empty
+   *
+   * @note Unlike other collection types, a wakeup tree is
+   * considered "empty" if it only contains the root node;
+   * that is, if it is "uninteresting". In such a case,
+   */
+  bool empty() const { return nodes_.size() == static_cast<size_t>(1); }
+
+  /**
+   * @brief Returns the number of *non-empty* entries in the tree, viz. the
+   * number of nodes in the tree that have an action mapped to them
+   */
+  size_t get_num_entries() const { return not empty() ? (nodes_.size() - 1) : static_cast<size_t>(0); }
+
+  /**
+   * @brief Returns the number of nodes in the tree, including the root node
+   */
+  size_t get_num_nodes() const { return nodes_.size(); }
+
+  /**
+   * @brief Gets the actor of the node that is the "smallest" (with respect
+   * to the tree's "<" relation) single-process node.
+   *
+   * If the tree is empty, returns std::nullopt
+   */
+  std::optional<aid_t> get_min_single_process_actor() const;
+
+  /**
+   * @brief Gets the node itself that is the "smallest" (with respect
+   * to the tree's "<" relation) single-process node.
+   *
+   * If the tree is empty, returns std::nullopt
+   */
+  std::optional<WakeupTreeNode*> get_min_single_process_node() const;
+
+  /** @brief Describes how a tree insertion was carried out */
+  enum class InsertionResult { leaf, interior_node, root };
+
+  /**
+   * @brief Inserts an sequence `seq` of processes into the tree
+   * such that that this tree is a wakeup tree relative to the
+   * given execution
+   *
+   * A key component of managing wakeup trees in ODPOR is
+   * determining what should be inserted into a wakeup tree.
+   * The procedure for implementing the insertion is outlined in section 6.2
+   * of Abdulla et al. 2017 as follows:
+   *
+   * | Let `v` be the smallest (w.r.t to "<") sequence in [the tree] B
+   * | such that `v ~_[E] w`. If `v` is a leaf node, the tree can be left
+   * | unmodified.
+   * |
+   * | Otherwise let `w'` be the shortest sequence such that `w [=_[E] v.w'`
+   * | and add `v.w'` as a new leaf, ordered after all already existing nodes
+   * | of the form `v.w''`
+   *
+   * This method performs the post-order search of part one and the insertion of
+   * `v.w'` of part two of the above procedure. Note that the execution will
+   * provide `v.w'` (see `Execution::get_shortest_odpor_sq_subset_insertion()`).
+   *
+   * @invariant: It is assumed that this tree is a wakeup tree
+   * with respect to the given execution `E`
+   *
+   * @return Whether a sequence equivalent to `seq` is already contained
+   * as a leaf node in the tree
+   */
+  InsertionResult insert(const Execution& E, const PartialExecution& seq);
+};
+
+} // namespace simgrid::mc::odpor
+#endif
diff --git a/src/mc/explo/odpor/WakeupTreeIterator.cpp b/src/mc/explo/odpor/WakeupTreeIterator.cpp
new file mode 100644 (file)
index 0000000..9017fd8
--- /dev/null
@@ -0,0 +1,86 @@
+/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/mc/explo/odpor/WakeupTreeIterator.hpp"
+#include "src/mc/explo/odpor/WakeupTree.hpp"
+#include "xbt/asserts.h"
+
+namespace simgrid::mc::odpor {
+
+WakeupTreeIterator::WakeupTreeIterator(const WakeupTree& tree) : root_list{tree.root_}
+{
+  post_order_iteration.push(root_list.begin());
+  push_until_left_most_found();
+}
+
+void WakeupTreeIterator::push_until_left_most_found()
+{
+  // INVARIANT: Since we are traversing over a tree,
+  // there are no cycles. This means that at least
+  // one node in the tree won't have any children,
+  // so the loop will eventually terminate
+  WakeupTreeNode* cur_top_node = *post_order_iteration.top();
+  while (not cur_top_node->is_leaf()) {
+    // INVARIANT: Since we push children in
+    // reverse order (right-most to left-most),
+    // we ensure that we'll always process left-most
+    // children first
+    auto& children = cur_top_node->children_;
+    for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
+      // iter.base() points one element past where we seek; that is,
+      // we want the value one position forward
+      post_order_iteration.push(std::prev(iter.base()));
+    }
+    has_added_children.push(cur_top_node);
+    cur_top_node = *post_order_iteration.top();
+  }
+}
+
+void WakeupTreeIterator::increment()
+{
+  // If there are no nodes in the stack, we've
+  // completed the traversal: there's nothing left
+  // to do
+  if (post_order_iteration.empty()) {
+    return;
+  }
+
+  post_order_iteration.pop();
+
+  // If there are now no longer any nodes left,
+  // we know that `prev_top` must be the original
+  // root; that is, we were *just* pointing at the
+  // original root, so we're done
+  if (post_order_iteration.empty()) {
+    return;
+  }
+
+  xbt_assert(not has_added_children.empty(), "Invariant violated: There are more "
+                                             "nodes in the iteration that we must search "
+                                             "yet nobody has claimed to have added these nodes. "
+                                             "This implies that the algorithm is not iterating over "
+                                             "the wakeup tree is not following the post-fix order "
+                                             "correctly");
+
+  // Otherwise, look at what is the new, current top node.
+  // We're traversing the tree in
+  //
+  // If we've already added our children, we want
+  // to be sure not to add them again; but we ALSO
+  // want to be sure that we now start checking against
+  // the the node that's next in line as "finished"
+  //
+  // INVARIANT: Since we're searching in post-fix order,
+  // it always suffices to compare the current node
+  // with the top of the stack of nodes which have added their
+  // children
+  if (*post_order_iteration.top() == has_added_children.top()) {
+    has_added_children.pop();
+  } else {
+    push_until_left_most_found();
+  }
+}
+
+} // namespace simgrid::mc::odpor
\ No newline at end of file
diff --git a/src/mc/explo/odpor/WakeupTreeIterator.hpp b/src/mc/explo/odpor/WakeupTreeIterator.hpp
new file mode 100644 (file)
index 0000000..c33d483
--- /dev/null
@@ -0,0 +1,88 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_ODPOR_WAKEUP_TREE_ITERATOR_HPP
+#define SIMGRID_MC_ODPOR_WAKEUP_TREE_ITERATOR_HPP
+
+#include "src/mc/explo/odpor/odpor_forward.hpp"
+
+#include <boost/iterator/iterator_facade.hpp>
+#include <list>
+#include <stack>
+
+namespace simgrid::mc::odpor {
+
+/**
+ * @brief A forward-iterator that performs a postorder traversal
+ * of the nodes of a WakeupTree
+ *
+ * Inserting a sequence `w` into a wakeup tree `B` with respect to
+ * some execution `E` requires determining the "<-minimal" node `N`
+ * with sequence `v` in the tree such that `v ~_[E] w`. The "<" relation
+ * over a wakeup tree orders its nodes by first recursively ordering all
+ * children of a node `N` followed by the node `N` itself, viz. a postorder.
+ * This iterator provides such a postorder traversal over the nodes in the
+ * wakeup tree.
+ */
+class WakeupTreeIterator
+    : public boost::iterator_facade<WakeupTreeIterator, WakeupTreeNode*, boost::forward_traversal_tag> {
+public:
+  // Use rule-of-three, and implicitely disable the move constructor which cannot be 'noexcept' (as required by C++ Core
+  // Guidelines), due to the std::list and std:stack<std::deque> members.
+  WakeupTreeIterator()                          = default;
+  WakeupTreeIterator(const WakeupTreeIterator&) = default;
+  ~WakeupTreeIterator()                         = default;
+
+  explicit WakeupTreeIterator(const WakeupTree& tree);
+
+private:
+  using node_handle = std::list<WakeupTreeNode*>::iterator;
+
+  /**
+   *  @brief A list which is used to "store" the root node of the traversed
+   * wakeup tree
+   *
+   * The root node is, by definition, not the child of any other node. This
+   * means that the root node also is contained in any list into which the
+   * iterator can generate a pointer (iterator). This list takes the role
+   * of allowing the iterator to treat the root node like any other.
+   */
+  std::list<WakeupTreeNode*> root_list;
+
+  /**
+   * @brief The current "view" of the iteration in post-order traversal
+   */
+  std::stack<node_handle> post_order_iteration;
+
+  /**
+   * @brief The nodes in the current ordering that have already
+   * added their own children
+   *
+   * We need to be able to determine whether to add the children
+   * of a given node. Eventually, we want to search that node itself,
+   * but we have to first search its children. Later, when we
+   * reach each node in this stack again, we'll remember not to add
+   * its children and will search the node in the stack instead.
+   */
+  std::stack<WakeupTreeNode*> has_added_children;
+
+  /**
+   * @brief Search the wakeup tree until a leaf node appears at the front
+   * of the iteration, pushing all children towards the top of the stack
+   * as the search progresses
+   */
+  void push_until_left_most_found();
+
+  // boost::iterator_facade<...> interface to implement
+  void increment();
+  bool equal(const WakeupTreeIterator& other) const { return post_order_iteration == other.post_order_iteration; }
+  WakeupTreeNode*& dereference() const { return *post_order_iteration.top(); }
+
+  // Allows boost::iterator_facade<...> to function properly
+  friend class boost::iterator_core_access;
+};
+
+} // namespace simgrid::mc::odpor
+#endif
diff --git a/src/mc/explo/odpor/WakeupTree_test.cpp b/src/mc/explo/odpor/WakeupTree_test.cpp
new file mode 100644 (file)
index 0000000..e0ef032
--- /dev/null
@@ -0,0 +1,469 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.               */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/3rd-party/catch.hpp"
+#include "src/mc/explo/odpor/Execution.hpp"
+#include "src/mc/explo/odpor/WakeupTree.hpp"
+#include "src/mc/explo/udpor/udpor_tests_private.hpp"
+#include "src/xbt/utils/iter/LazyPowerset.hpp"
+
+using namespace simgrid::mc;
+using namespace simgrid::mc::odpor;
+using namespace simgrid::mc::udpor;
+
+static void test_tree_iterator(const WakeupTree& tree, const std::vector<PartialExecution>& expected)
+{
+  uint64_t num_nodes_traversed = 0;
+  auto tree_iter               = tree.begin();
+  for (auto expected_iter = expected.begin(); expected_iter != expected.end();
+       ++expected_iter, ++tree_iter, ++num_nodes_traversed) {
+    REQUIRE(tree_iter != tree.end());
+    REQUIRE((*tree_iter)->get_sequence() == *expected_iter);
+  }
+  REQUIRE(num_nodes_traversed == tree.get_num_nodes());
+}
+
+static void test_tree_empty(const WakeupTree& tree)
+{
+  REQUIRE(tree.empty());
+  REQUIRE(tree.get_num_entries() == 0);
+  REQUIRE(tree.get_num_nodes() == 1);
+  REQUIRE_FALSE(tree.get_min_single_process_node().has_value());
+  REQUIRE_FALSE(tree.get_min_single_process_actor().has_value());
+  test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{}});
+}
+
+TEST_CASE("simgrid::mc::odpor::WakeupTree: Constructing Trees")
+{
+  SECTION("Constructing empty trees")
+  {
+    test_tree_empty(WakeupTree());
+  }
+
+  SECTION("Testing subtree creation and manipulation")
+  {
+    // Here, we make everything dependent. This will ensure that each unique sequence
+    // inserted into the tree never "eventually looks like"
+    const auto a0 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a1 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto a2 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a3 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto a4 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 5);
+    const auto a5 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 6);
+
+    Execution execution;
+    execution.push_transition(a0);
+    execution.push_transition(a1);
+    execution.push_transition(a2);
+    execution.push_transition(a3);
+    execution.push_transition(a4);
+    execution.push_transition(a5);
+
+    // The tree is as follows:
+    //                  {}
+    //               /     /
+    //             a1       a4
+    //           /    /       /
+    //          a2    a3       a1
+    //         /     /   /      /
+    //        a3    a2   a5     a2
+    //       /     /             /
+    //      a4    a4             a3
+    //
+    // Recall that new nodes (in this case the one with
+    // action `a2`) are added such that they are "greater than" (under
+    // the tree's `<` relation) all those that exist under the given parent
+    WakeupTree tree;
+    tree.insert(Execution(), {a1, a2, a3, a4});
+    tree.insert(Execution(), {a1, a3, a2, a4});
+    tree.insert(Execution(), {a1, a3, a2, a4, a5});
+    tree.insert(Execution(), {a1, a3, a5});
+    tree.insert(Execution(), {a4, a2, a1, a3});
+    REQUIRE(tree.get_num_nodes() == 13);
+    test_tree_iterator(tree, std::vector<PartialExecution>{
+                                 PartialExecution{a1, a2, a3, a4}, PartialExecution{a1, a2, a3},
+                                 PartialExecution{a1, a2}, PartialExecution{a1, a3, a2, a4},
+                                 PartialExecution{a1, a3, a2}, PartialExecution{a1, a3, a5}, PartialExecution{a1, a3},
+                                 PartialExecution{a1}, PartialExecution{a4, a2, a1, a3}, PartialExecution{a4, a2, a1},
+                                 PartialExecution{a4, a2}, PartialExecution{a4}, PartialExecution{}});
+
+    SECTION("Cloning a tree from the root produces the same tree")
+    {
+      // The root node is the last node
+      auto tree_root = tree.begin();
+      std::advance(tree_root, tree.get_num_nodes() - 1);
+
+      WakeupTree clone = WakeupTree::make_subtree_rooted_at(*tree_root);
+      REQUIRE(clone.empty() == tree.empty());
+      REQUIRE(clone.get_num_entries() == tree.get_num_entries());
+      REQUIRE(clone.get_num_nodes() == tree.get_num_nodes());
+
+      auto tree_iter = tree.begin();
+      for (auto clone_iter = clone.begin(); clone_iter != clone.end(); ++clone_iter, ++tree_iter) {
+        REQUIRE(tree_iter != tree.end());
+        REQUIRE((*tree_iter)->get_sequence() == (*clone_iter)->get_sequence());
+      }
+    }
+
+    SECTION("Cloning a subtree from a leaf gives an empty tree")
+    {
+      // Let's pick the first leaf
+      WakeupTree clone = WakeupTree::make_subtree_rooted_at(*tree.begin());
+      REQUIRE(clone.empty());
+      REQUIRE(clone.get_num_entries() == 0);
+      REQUIRE(clone.get_num_nodes() == 1);
+    }
+
+    SECTION("Cloning a subtree from an interior node gives the subtree underneath")
+    {
+      // Here, we pick the second-to-last node in the
+      // series, which is the right-most child of the root
+      auto right_most = tree.begin();
+      std::advance(right_most, tree.get_num_nodes() - 2);
+
+      WakeupTree clone = WakeupTree::make_subtree_rooted_at(*right_most);
+      REQUIRE_FALSE(clone.empty());
+      REQUIRE(clone.get_num_entries() == 3);
+      REQUIRE(clone.get_num_nodes() == 4);
+      // Importantly, note that action `a4` is not included in
+      // any of the executions; for in the subtree `clone` `a4`
+      // is now the root.
+      test_tree_iterator(clone, std::vector<PartialExecution>{PartialExecution{a2, a1, a3}, PartialExecution{a2, a1},
+                                                              PartialExecution{a2}, PartialExecution{}});
+    }
+
+    SECTION("Removing the first single-process subtree")
+    {
+      // Prior to removal, the first `a1` was the first single-process node
+      REQUIRE(tree.get_min_single_process_node().has_value());
+      REQUIRE(tree.get_min_single_process_actor().has_value());
+      REQUIRE(tree.get_min_single_process_actor().value() == a1->aid_);
+
+      tree.remove_min_single_process_subtree();
+
+      // Now the first `a4` is
+      REQUIRE(tree.get_min_single_process_node().has_value());
+      REQUIRE(tree.get_min_single_process_actor().has_value());
+      REQUIRE(tree.get_min_single_process_actor().value() == a4->aid_);
+
+      REQUIRE(tree.get_num_nodes() == 5);
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a4, a2, a1, a3},
+                                                             PartialExecution{a4, a2, a1}, PartialExecution{a4, a2},
+                                                             PartialExecution{a4}, PartialExecution{}});
+      tree.remove_min_single_process_subtree();
+
+      // At this point, we've removed each single-process subtree, so
+      // the tree should be empty
+      REQUIRE(tree.empty());
+    }
+
+    SECTION("Removing the first single-process subtree from an empty tree has no effect")
+    {
+      WakeupTree empty_tree;
+      test_tree_empty(empty_tree);
+
+      empty_tree.remove_min_single_process_subtree();
+
+      // There should be no effect: the tree should still be empty
+      // and the function should have no effect
+      test_tree_empty(empty_tree);
+    }
+  }
+}
+
+TEST_CASE("simgrid::mc::odpor::WakeupTree: Testing Insertion for Empty Executions")
+{
+  SECTION("Following an execution")
+  {
+    // We imagine the following completed execution `E`
+    // consisting of executing actions a0-a3. Execution
+    // `E` is the first such maximal execution explored
+    // by ODPOR, which implies that a) all sleep sets are
+    // empty and b) all wakeup trees (i.e. for each prefix) consist of the root
+    // node with a single leaf containing the action
+    // taken, save for the wakeup tree of the execution itself
+    // which is empty.
+
+    // We first notice that there's a reversible race between
+    // events 0 and 3.
+
+    const auto a0 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto a2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a3 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto a4 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+
+    Execution execution;
+    execution.push_transition(a0);
+    execution.push_transition(a1);
+    execution.push_transition(a2);
+    execution.push_transition(a3);
+    execution.push_transition(a4);
+
+    REQUIRE(execution.get_racing_events_of(2) == std::unordered_set<Execution::EventHandle>{0});
+    REQUIRE(execution.get_racing_events_of(3) == std::unordered_set<Execution::EventHandle>{0});
+
+    WakeupTree tree;
+
+    SECTION("Attempting to insert the empty sequence into an empty tree should have no effect")
+    {
+      tree.insert(Execution(), {});
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{}});
+    }
+
+    // First, we initialize the tree to how it looked prior
+    // to the insertion of the race.
+    tree.insert(Execution(), {a0});
+
+    // Then, after insertion, we ensure that the node was
+    // indeed added to the tree.
+    tree.insert(Execution(), {a1, a3});
+    test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a1, a3},
+                                                           PartialExecution{a1}, PartialExecution{}});
+
+    SECTION("Attempting to re-insert the same EXACT sequence should have no effect")
+    {
+      tree.insert(Execution(), {a1, a3});
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a1, a3},
+                                                             PartialExecution{a1}, PartialExecution{}});
+    }
+
+    SECTION("Attempting to re-insert an equivalent sequence should have no effect")
+    {
+      // a3 and a1 are interchangeable since `a1` is independent with everything.
+      // Since we found an equivalent sequence that is a leaf, nothing should result..
+      tree.insert(Execution(), {a3, a1});
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a1, a3},
+                                                             PartialExecution{a1}, PartialExecution{}});
+    }
+
+    SECTION("Attempting to insert the empty sequence should have no effect")
+    {
+      tree.insert(Execution(), {});
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a1, a3},
+                                                             PartialExecution{a1}, PartialExecution{}});
+    }
+
+    SECTION("Inserting an extension should create a branch point")
+    {
+      // `a1.a2` shares the same `a1` prefix as `a1.a3`. Thus, the tree
+      // should now look as follows:
+      //
+      //                 {}
+      //               /    /
+      //             a0     a1
+      //                   /   /
+      //                  a3   a4
+      //
+      // Recall that new nodes (in this case the one with
+      // action `a2`) are added such that they are "greater than" (under
+      // the tree's `<` relation) all those that exist under the given parent.
+      tree.insert(Execution(), {a1, a4});
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a1, a3},
+                                                             PartialExecution{a1, a4}, PartialExecution{a1},
+                                                             PartialExecution{}});
+    }
+
+    SECTION("Inserting an equivalent sequence to a leaf should preserve the tree as-is")
+    {
+      // `a1.a2` is equivalent to `a1.a3` since `a2` and `a3` are independent
+      // (`E ⊢ p ◊ w` where `p := proc(a2)` and `w := a3`). Thus, the tree
+      // should now STILL look as follows:
+      //
+      //                 {}
+      //               /    /
+      //             a0     a1
+      //                   /
+      //                  a3
+      //
+      // Recall that new nodes (in this case the one with
+      // action `a2`) are added such that they are "greater than" (under
+      // the tree's `<` relation) all those that exist under the given parent.
+      tree.insert(Execution(), {a1, a3});
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a1, a3},
+                                                             PartialExecution{a1}, PartialExecution{}});
+    }
+  }
+
+  SECTION("Performing Arbitrary Insertions")
+  {
+    const auto a0 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto a1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 4);
+    const auto a2 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto a3 = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto a4 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto a5 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 4);
+    WakeupTree tree;
+
+    SECTION("Attempting to insert the empty sequence into an empty tree should have no effect")
+    {
+      tree.insert(Execution(), {});
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{}});
+    }
+
+    SECTION("Attempting to re-insert the same sequence multiple times should have no extra effect")
+    {
+      tree.insert(Execution(), {a4});
+      tree.insert(Execution(), {a4});
+      tree.insert(Execution(), {a4});
+      REQUIRE(tree.get_num_nodes() == 2);
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a4}, PartialExecution{}});
+    }
+
+    SECTION("Attempting to insert an independent sequence same should have no extra effect")
+    {
+      // a4 and a1 are independent actions. Intuitively, then, we need only
+      // search one ordering of the two actions. The wakeup tree handles
+      // this by computing the `~` relation. The relation itself determines
+      // whether the `a1` is an initial of `a3`, which it is not. It then
+      // checks whether `a1` is independent with everything in the sequence
+      // (in this case, consisting only of `a1`) which IS true. Since `a4`
+      // is already a leaf node of the tree, it suffices to only have `a4`
+      // in this tree to guide ODPOR.
+      tree.insert(Execution(), {a4});
+      tree.insert(Execution(), {a1});
+      REQUIRE(tree.get_num_nodes() == 2);
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a4}, PartialExecution{}});
+    }
+
+    SECTION(
+        "Attempting to insert a progression of executions should have no extra effect when the first process is a leaf")
+    {
+      // All progressions starting with `a0` are effectively already accounted
+      // for by inserting `a0` since we `a0` "can always be made to look like"
+      // (viz. the `~` relation) `a0.*` where `*` is some sequence of actions
+      tree.insert(Execution(), {a0});
+      tree.insert(Execution(), {a0, a3});
+      tree.insert(Execution(), {a0, a3, a2});
+      tree.insert(Execution(), {a0, a3, a2, a4});
+      tree.insert(Execution(), {a0, a3, a2, a4});
+      REQUIRE(tree.get_num_nodes() == 2);
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{}});
+    }
+
+    SECTION("Stress test with multiple branch points: `~_E` with different looking sequences")
+    {
+      // After the insertions below, the tree looks like the following:
+      //                {}
+      //              /    /
+      //            a0     a2
+      //                 /  |   /
+      //               a0  a3   a5
+      tree.insert(Execution(), {a0});
+      tree.insert(Execution(), {a2, a0});
+      tree.insert(Execution(), {a2, a3});
+      tree.insert(Execution(), {a2, a5});
+      REQUIRE(tree.get_num_nodes() == 6);
+      test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a2, a0},
+                                                             PartialExecution{a2, a3}, PartialExecution{a2, a5},
+                                                             PartialExecution{a2}, PartialExecution{}});
+      SECTION("Adding more stress")
+      {
+        // In this case, `a2` and `a1` can be interchanged with each other.
+        // Thus `a2.a1 == a1.a2`. Since there is already an interior node
+        // containing `a2`, we attempt to add the what remains (viz. `a1`) to the
+        // series. HOWEVER: we notice that `a2.a5` is "eventually equivalent to"
+        // (that is `~` with) `a1.a2` since `a2` is an initial of the latter and
+        // `a1` and `a5` are independent of each other.
+        tree.insert(Execution(), {a1, a2});
+        REQUIRE(tree.get_num_nodes() == 6);
+        test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a2, a0},
+                                                               PartialExecution{a2, a3}, PartialExecution{a2, a5},
+                                                               PartialExecution{a2}, PartialExecution{}});
+
+        // With a3.a0, we notice that starting a sequence with `a3` is
+        // always different than starting one with either `a0` or
+        //
+        // After the insertion, the tree looks like the following:
+        //                     {}
+        //              /     /        /
+        //            a0     a2        a3
+        //                 /  |  /     |
+        //               a0  a3  a5    a0
+        tree.insert(Execution(), {a3, a0});
+        REQUIRE(tree.get_num_nodes() == 8);
+        test_tree_iterator(tree, std::vector<PartialExecution>{PartialExecution{a0}, PartialExecution{a2, a0},
+                                                               PartialExecution{a2, a3}, PartialExecution{a2, a5},
+                                                               PartialExecution{a2}, PartialExecution{a3, a0},
+                                                               PartialExecution{a3}, PartialExecution{}});
+      }
+    }
+  }
+
+  SECTION("Insertion with more subtle equivalents")
+  {
+    const auto cd_1 = std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto i_2  = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+    const auto i_3  = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+    const auto d_1  = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1);
+    const auto d_2  = std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 2);
+    WakeupTree complex_tree;
+    // After the insertions below, the tree looks like the following:
+    //                              {}
+    //                           /     /
+    //                       cd_1      i_2
+    //                       /            /
+    //                    i_2              d_2
+    //                   /                  /
+    //                 d_1                 cd_1
+    //                 /                 /      /
+    //               i_3               d_1      i_3
+    //              /                  /          /
+    //            d_2                i_3          d_2
+    //            /                  /              /
+    //          d_2                d_2              d_1
+    //
+    // d_1.i_3.d_2 is equivalent to i_3.d_2.d_1
+    complex_tree.insert(Execution(), {cd_1, i_2, d_1, i_3, d_2, d_2});
+    complex_tree.insert(Execution(), {i_2, d_2, cd_1, d_1, i_3, d_2});
+    complex_tree.insert(Execution(), {i_2, d_2, cd_1, i_3, d_2, d_1});
+    REQUIRE(complex_tree.get_num_nodes() == 16);
+    test_tree_iterator(complex_tree, std::vector<PartialExecution>{{cd_1, i_2, d_1, i_3, d_2, d_2},
+                                                                   {cd_1, i_2, d_1, i_3, d_2},
+                                                                   {cd_1, i_2, d_1, i_3},
+                                                                   {cd_1, i_2, d_1},
+                                                                   {cd_1, i_2},
+                                                                   {cd_1},
+                                                                   {i_2, d_2, cd_1, d_1, i_3, d_2},
+                                                                   {i_2, d_2, cd_1, d_1, i_3},
+                                                                   {i_2, d_2, cd_1, d_1},
+                                                                   {i_2, d_2, cd_1, i_3, d_2, d_1},
+                                                                   {i_2, d_2, cd_1, i_3, d_2},
+                                                                   {i_2, d_2, cd_1, i_3},
+                                                                   {i_2, d_2, cd_1},
+                                                                   {i_2, d_2},
+                                                                   {i_2},
+                                                                   {}});
+    // Here we note that the sequence that we are attempting to insert, viz.
+    //
+    //    i_3.i_2.d_2.cd_1.d_2.d_1
+    //
+    // is already equivalent to
+    //
+    //    i_2.d_2.cd_1.i_3.d_2.d_1
+    complex_tree.insert(Execution(), {i_3, i_2, d_2, cd_1, d_2, d_1});
+    REQUIRE(complex_tree.get_num_nodes() == 16);
+
+    // Here we note that the sequence that we are attempting to insert, viz.
+    //
+    //    i_2.d_2.cd_1.d_1.i_3
+    //
+    // is already equivalent to
+    //
+    //    i_2.d_2.cd_1.i_3.d_2.d_1
+    complex_tree.insert(Execution(), {i_2, d_2, cd_1, d_1, i_3});
+    REQUIRE(complex_tree.get_num_nodes() == 16);
+
+    // Here we note that the sequence that we are attempting to insert, viz.
+    //
+    //    i_2.d_2.cd_1
+    //
+    // is accounted for by an interior node of the tree. Since there is no
+    // "extra" portions that are different from what is already
+    // contained in the tree, nothing is added and the tree stays the same
+    complex_tree.insert(Execution(), {i_2, d_2, cd_1});
+    REQUIRE(complex_tree.get_num_nodes() == 16);
+  }
+}
\ No newline at end of file
diff --git a/src/mc/explo/odpor/odpor_forward.hpp b/src/mc/explo/odpor/odpor_forward.hpp
new file mode 100644 (file)
index 0000000..52388bc
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/** @file odpor_forward.hpp
+ *
+ *  Forward definitions for MC types specific to ODPOR
+ */
+
+#ifndef SIMGRID_MC_ODPOR_FORWARD_HPP
+#define SIMGRID_MC_ODPOR_FORWARD_HPP
+
+#include "src/mc/mc_forward.hpp"
+#include <list>
+#include <memory>
+#include <simgrid/forward.h>
+
+namespace simgrid::mc::odpor {
+
+using PartialExecution = std::list<std::shared_ptr<Transition>>;
+
+class Event;
+class Execution;
+class ReversibleRaceCalculator;
+class WakeupTree;
+class WakeupTreeNode;
+class WakeupTreeIterator;
+
+} // namespace simgrid::mc::odpor
+
+namespace simgrid::mc {
+
+// Permit ODPOR or SDPOR to be used as namespaces
+// Many of the structures overlap, so it doesn't
+// make sense to some in one and not the other.
+// Having one for each algorithm makes the corresponding
+// code easier to read
+namespace sdpor = simgrid::mc::odpor;
+
+} // namespace simgrid::mc
+
+#endif
diff --git a/src/mc/explo/odpor/odpor_tests_private.hpp b/src/mc/explo/odpor/odpor_tests_private.hpp
new file mode 100644 (file)
index 0000000..cd76ba3
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/** @file odpor_tests_private.hpp
+ *
+ * A private header file for all ODPOR tests
+ */
+
+#ifndef SIMGRID_MC_ODPOR_TEST_PRIVATE_HPP
+#define SIMGRID_MC_ODPOR_TEST_PRIVATE_HPP
+
+#include "src/mc/explo/udpor/udpor_tests_private.hpp"
+#include "src/mc/transition/Transition.hpp"
+
+namespace simgrid::mc::odpor {
+
+struct DependentIfSameValueAction : public Transition {
+private:
+  const int value;
+
+public:
+  DependentIfSameValueAction(Type type, aid_t issuer, int value, int times_considered = 0)
+      : Transition(type, issuer, times_considered), value(value)
+  {
+  }
+  DependentIfSameValueAction(aid_t issuer, int value, int times_considered = 0)
+      : Transition(simgrid::mc::Transition::Type::UNKNOWN, issuer, times_considered), value(value)
+  {
+  }
+
+  // Dependent only with DependentAction (i.e. not itself)
+  bool depends(const Transition* other) const override
+  {
+    if (aid_ == other->aid_) {
+      return true;
+    }
+
+    if (const auto* same_value = dynamic_cast<const DependentIfSameValueAction*>(other); same_value != nullptr) {
+      return value == same_value->value;
+    }
+
+    // `DependentAction` is dependent with everyone who's not the `IndependentAction`
+    return dynamic_cast<const simgrid::mc::udpor::DependentAction*>(other) != nullptr;
+  }
+};
+
+} // namespace simgrid::mc::odpor
+
+#endif
index f1525fe..5187135 100644 (file)
@@ -21,7 +21,7 @@ int main(int argc, char** argv)
   xbt_assert(argc >= 2, "Missing arguments");
 
   // Currently, we need this before sg_config_init:
-  simgrid::mc::model_checking_mode = simgrid::mc::ModelCheckingMode::CHECKER_SIDE;
+  simgrid::mc::set_model_checking_mode(simgrid::mc::ModelCheckingMode::CHECKER_SIDE);
 
   // The initialization function can touch argv.
   // We make a copy of argv before modifying it in order to pass the original value to the model-checked application:
@@ -36,22 +36,19 @@ int main(int argc, char** argv)
   std::unique_ptr<Exploration> explo;
 
   if (_sg_mc_comms_determinism || _sg_mc_send_determinism)
-    explo = std::unique_ptr<Exploration>(create_communication_determinism_checker(argv_copy, cfg_use_DPOR()));
+    explo = std::unique_ptr<Exploration>(
+        create_communication_determinism_checker(argv_copy, get_model_checking_reduction()));
   else if (_sg_mc_unfolding_checker)
     explo = std::unique_ptr<Exploration>(create_udpor_checker(argv_copy));
-  else if (_sg_mc_property_file.get().empty())
-    explo = std::unique_ptr<Exploration>(create_dfs_exploration(argv_copy, cfg_use_DPOR()));
   else
-    explo = std::unique_ptr<Exploration>(create_liveness_checker(argv_copy));
+    explo = std::unique_ptr<Exploration>(create_dfs_exploration(argv_copy, get_model_checking_reduction()));
 
+  ExitStatus status;
   try {
     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;
+    status = ExitStatus::SUCCESS;
+  } catch (const McError& e) {
+    status = e.value;
   }
-  return SIMGRID_MC_EXIT_SUCCESS;
+  return static_cast<int>(status);
 }
index 98d004b..2dd00cb 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/mc/explo/udpor/Unfolding.hpp"
 #include "src/mc/explo/udpor/UnfoldingEvent.hpp"
 #include "src/mc/explo/udpor/maximal_subsets_iterator.hpp"
+#include "src/xbt/utils/iter/variable_for_loop.hpp"
 #include "xbt/asserts.h"
 
 #include <algorithm>
@@ -21,20 +22,26 @@ Configuration::Configuration(std::initializer_list<const UnfoldingEvent*> events
 {
 }
 
-Configuration::Configuration(const UnfoldingEvent* e) : Configuration(e->get_history())
+Configuration::Configuration(const UnfoldingEvent* e) : Configuration(e->get_local_config())
 {
   // The local configuration should always be a valid configuration. We
   // check the invariant regardless as a sanity check
 }
 
+Configuration::Configuration(const History& history) : Configuration(history.get_all_events()) {}
+
 Configuration::Configuration(const EventSet& events) : events_(events)
 {
-  if (!events_.is_valid_configuration()) {
+  if (not events_.is_valid_configuration()) {
     throw std::invalid_argument("The events do not form a valid configuration");
   }
-}
 
-Configuration::Configuration(const History& history) : Configuration(history.get_all_events()) {}
+  // Since we add in topological order under `<`, we know that the "most-recent"
+  // transition executed by each actor will appear last
+  for (const UnfoldingEvent* e : get_topologically_sorted_events()) {
+    this->latest_event_mapping[e->get_actor()] = e;
+  }
+}
 
 void Configuration::add_event(const UnfoldingEvent* e)
 {
@@ -42,22 +49,25 @@ void Configuration::add_event(const UnfoldingEvent* e)
     throw std::invalid_argument("Expected a nonnull `UnfoldingEvent*` but received NULL instead");
   }
 
+  // The event is already a member of the configuration: there's
+  // nothing to do in this case
   if (this->events_.contains(e)) {
     return;
   }
 
   // Preserves the property that the configuration is conflict-free
-  if (e->conflicts_with(*this)) {
+  if (e->conflicts_with_any(this->events_)) {
     throw std::invalid_argument("The newly added event conflicts with the events already "
                                 "contained in the configuration. Adding this event violates "
                                 "the property that a configuration is conflict-free");
   }
 
   this->events_.insert(e);
-  this->newest_event = e;
+  this->newest_event                         = e;
+  this->latest_event_mapping[e->get_actor()] = e;
 
   // Preserves the property that the configuration is causally closed
-  if (auto history = History(e); !this->events_.contains(history)) {
+  if (auto history = History(e); not this->events_.contains(history)) {
     throw std::invalid_argument("The newly added event has dependencies "
                                 "which are missing from this configuration");
   }
@@ -65,13 +75,41 @@ void Configuration::add_event(const UnfoldingEvent* e)
 
 bool Configuration::is_compatible_with(const UnfoldingEvent* e) const
 {
-  return not e->conflicts_with(*this);
+  // 1. `e`'s history must be contained in the configuration;
+  // otherwise adding the event would violate the invariant
+  // that a configuration is causally-closed
+  //
+  // 2. `e` itself must not conflict with any events of
+  // the configuration; otherwise adding the event would
+  // violate the invariant that a configuration is conflict-free
+  return contains(e->get_history()) && (not e->conflicts_with_any(this->events_));
 }
 
 bool Configuration::is_compatible_with(const History& history) const
 {
-  return std::none_of(history.begin(), history.end(),
-                      [&](const UnfoldingEvent* e) { return e->conflicts_with(*this); });
+  // Note: We don't need to check if the `C` will be causally-closed
+  // after adding `history` to it since a) `C` itself is already
+  // causally-closed and b) the history is already causally closed
+  const auto event_diff = history.get_event_diff_with(*this);
+
+  // The events that are contained outside of the configuration
+  // must themselves be free of conflicts.
+  if (not event_diff.is_conflict_free()) {
+    return false;
+  }
+
+  // Now we need only ensure that there are no conflicts
+  // between events of the configuration and the events
+  // that lie outside of the configuration. There is no
+  // need to check if there are conflicts in `C`: we already
+  // know that it's conflict free
+  const auto begin = simgrid::xbt::variable_for_loop<const EventSet>{{event_diff}, {this->events_}};
+  const auto end   = simgrid::xbt::variable_for_loop<const EventSet>();
+  return std::none_of(begin, end, [=](const auto event_pair) {
+    const UnfoldingEvent* e1 = *event_pair[0];
+    const UnfoldingEvent* e2 = *event_pair[1];
+    return e1->conflicts_with(e2);
+  });
 }
 
 std::vector<const UnfoldingEvent*> Configuration::get_topologically_sorted_events() const
@@ -100,7 +138,7 @@ EventSet Configuration::get_minimally_reproducible_events() const
   // we know that the prior set `S` covered the entire history of C and
   // was maximal. Subsequent sets will miss events earlier in the
   // topological ordering that appear in `S`
-  EventSet minimally_reproducible_events = EventSet();
+  EventSet minimally_reproducible_events;
 
   for (const auto& maximal_set : maximal_subsets_iterator_wrapper<Configuration>(*this)) {
     if (maximal_set.size() > minimally_reproducible_events.size()) {
@@ -125,9 +163,9 @@ std::optional<Configuration> Configuration::compute_k_partial_alternative_to(con
                                                                              size_t k) const
 {
   // 1. Select k (of |D|, whichever is smaller) arbitrary events e_1, ..., e_k from D
-  const auto D_hat = [&]() {
-    const size_t size = std::min(k, D.size());
-    std::vector<const UnfoldingEvent*> D_hat(size);
+  const size_t k_alt_size = std::min(k, D.size());
+  const auto D_hat        = [&k_alt_size, &D]() {
+    std::vector<const UnfoldingEvent*> D_hat(k_alt_size);
     // TODO: Since any subset suffices for computing `k`-partial alternatives,
     // potentially select intelligently here (e.g. perhaps pick events
     // with transitions that we know are totally independent). This may be
@@ -135,7 +173,7 @@ std::optional<Configuration> Configuration::compute_k_partial_alternative_to(con
     // UDPOR
     //
     // For now, simply pick the first `k` events
-    std::copy_n(D.begin(), size, D_hat.begin());
+    std::copy_n(D.begin(), k_alt_size, D_hat.begin());
     return D_hat;
   }();
 
@@ -153,7 +191,7 @@ std::optional<Configuration> Configuration::compute_k_partial_alternative_to(con
   Comb comb(k);
 
   for (const auto* e : U) {
-    for (unsigned i = 0; i < k; i++) {
+    for (size_t i = 0; i < k_alt_size; i++) {
       const UnfoldingEvent* e_i = D_hat[i];
       if (const auto e_local_config = History(e);
           e_i->conflicts_with(e) and (not D.intersects(e_local_config)) and is_compatible_with(e_local_config)) {
@@ -175,7 +213,7 @@ std::optional<Configuration> Configuration::compute_k_partial_alternative_to(con
     for (const auto& event_in_spike : spikes) {
       events.push_back(*event_in_spike);
     }
-    return EventSet(std::move(events));
+    return EventSet(events);
   };
   const auto alternative =
       std::find_if(comb.combinations_begin(), comb.combinations_end(),
@@ -190,4 +228,20 @@ std::optional<Configuration> Configuration::compute_k_partial_alternative_to(con
   return Configuration(History(map_events(*alternative)));
 }
 
+std::optional<const UnfoldingEvent*> Configuration::get_latest_event_of(aid_t aid) const
+{
+  if (const auto latest_event = latest_event_mapping.find(aid); latest_event != latest_event_mapping.end()) {
+    return std::optional<const UnfoldingEvent*>{latest_event->second};
+  }
+  return std::nullopt;
+}
+
+std::optional<const Transition*> Configuration::get_latest_action_of(aid_t aid) const
+{
+  if (const auto latest_event = get_latest_event_of(aid); latest_event.has_value()) {
+    return std::optional<const Transition*>{latest_event.value()->get_transition()};
+  }
+  return std::nullopt;
+}
+
 } // namespace simgrid::mc::udpor
index 619871e..b1f6f93 100644 (file)
@@ -10,6 +10,8 @@
 #include "src/mc/explo/udpor/udpor_forward.hpp"
 
 #include <optional>
+#include <string>
+#include <unordered_map>
 
 namespace simgrid::mc::udpor {
 
@@ -31,8 +33,10 @@ public:
   auto cend() const { return this->events_.cend(); }
 
   bool contains(const UnfoldingEvent* e) const { return this->events_.contains(e); }
+  bool contains(const EventSet& events) const { return events.is_subset_of(this->events_); }
   const EventSet& get_events() const { return this->events_; }
   const UnfoldingEvent* get_latest_event() const { return this->newest_event; }
+  std::string to_string() const { return this->events_.to_string(); }
 
   /**
    * @brief Insert a new event into the configuration
@@ -65,8 +69,16 @@ public:
 
   /**
    * @brief Whether or not the given event can be added to
-   * this configuration while keeping the set of events causally closed
-   * and conflict-free
+   * this configuration while preserving that the configuration
+   * is causally closed and conflict-free
+   *
+   * A configuration `C` is compatible with an event iff
+   * the event can be added to `C` while preserving that
+   * the configuration is causally closed and conflict-free.
+   *
+   * The method effectively answers the following question:
+   *
+   * "Is `C + {e}` a valid configuration?"
    */
   bool is_compatible_with(const UnfoldingEvent* e) const;
 
@@ -74,6 +86,14 @@ public:
    * @brief Whether or not the events in the given history can be added to
    * this configuration while keeping the set of events causally closed
    * and conflict-free
+   *
+   * A configuration `C` is compatible with a history iff all
+   * events of the history can be added to `C` while preserving
+   * that the configuration is causally closed and conflict-free.
+   *
+   * The method effectively answers the following question:
+   *
+   * "Is `C + (U_i [e_i])` a valid configuration?"
    */
   bool is_compatible_with(const History& history) const;
 
@@ -134,6 +154,40 @@ public:
    */
   EventSet get_minimally_reproducible_events() const;
 
+  /**
+   * @brief Determines the event in the configuration whose associated
+   * transition is the latest of the given actor
+   *
+   * @invariant: At most one event in the configuration will correspond
+   * to `preEvt(C, a)` for any action `a`. This can be argued by contradiction.
+   *
+   * If there were more than one event (`e` and `e'`) in any configuration whose
+   * associated transitions `a` were run by the same actor at the same step, then they
+   * could not be causally related (`<`) since `a` could not be enabled in
+   * both subconfigurations C' and C'' containing the hypothetical events
+   * `e` and `e` + `e'`. Since they would not be contained in each other's histories,
+   * they would be in conflict, which cannot happen between any pair of events
+   * in a configuration. Thus `e` and `e'` cannot exist simultaneously
+   */
+  std::optional<const UnfoldingEvent*> get_latest_event_of(aid_t) const;
+  /**
+   * @brief Determines the most recent transition of the given actor
+   * in this configuration, or `pre(a)` as denoted in the thesis of
+   * The Anh Pham
+   *
+   * Conceptually, the execution of an interleaving of the transitions
+   * (i.e. a topological ordering) of a configuration yields a unique
+   * state `state(C)`. Since actions taken by the same actor are always
+   * dependent with one another, any such interleaving always yields a
+   * unique
+   *
+   * @returns the most recent transition of the given actor
+   * in this configuration, or `std::nullopt` if there are no transitions
+   * in this configuration run by the given actor
+   */
+  std::optional<const Transition*> get_latest_action_of(aid_t aid) const;
+  std::optional<const UnfoldingEvent*> pre_event(aid_t aid) const { return get_latest_event_of(aid); }
+
 private:
   /**
    * @brief The most recent event added to the configuration
@@ -145,8 +199,20 @@ private:
    *
    * @invariant For each event `e` in `events_`, the set of
    * dependencies of `e` is also contained in `events_`
+   *
+   * @invariant For each pair of events `e` and `e'` in
+   * `events_`, `e` and `e'` are not in conflict
    */
   EventSet events_;
+
+  /**
+   * @brief Maps actors to the latest events which
+   * are executed by the actor
+   *
+   * @invariant: The events that are contained in the map
+   * are also contained in the set `events_`
+   */
+  std::unordered_map<aid_t, const UnfoldingEvent*> latest_event_mapping;
 };
 
 } // namespace simgrid::mc::udpor
index 8deb62e..a20f382 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <unordered_map>
 
+using namespace simgrid::mc;
 using namespace simgrid::mc::udpor;
 
 TEST_CASE("simgrid::mc::udpor::Configuration: Constructing Configurations")
@@ -26,11 +27,11 @@ TEST_CASE("simgrid::mc::udpor::Configuration: Constructing Configurations")
   //          e3
   //         /  /
   //        e4   e5
-  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>());
+  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(1));
+  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>(3));
+  UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>(4));
 
   SECTION("Creating a configuration without events")
   {
@@ -95,10 +96,10 @@ TEST_CASE("simgrid::mc::udpor::Configuration: Adding Events")
   //           /
   //         /  /
   //        e3   e4
-  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
+  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(1));
+  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+  UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>(3));
 
   REQUIRE_THROWS_AS(Configuration().add_event(nullptr), std::invalid_argument);
   REQUIRE_THROWS_AS(Configuration().add_event(&e2), std::invalid_argument);
@@ -138,10 +139,10 @@ TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order")
   //          e3
   //         /
   //        e4
-  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
+  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(1));
+  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(2));
+  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(3));
+  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>(4));
 
   SECTION("Topological ordering for entire set")
   {
@@ -196,12 +197,12 @@ TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order More Compli
   //        e4   e6
   //        /
   //       e5
-  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e5(EventSet({&e4}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e6(EventSet({&e3}), std::make_shared<IndependentAction>());
+  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(1));
+  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(2));
+  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(3));
+  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>(4));
+  UnfoldingEvent e5(EventSet({&e4}), std::make_shared<IndependentAction>(5));
+  UnfoldingEvent e6(EventSet({&e3}), std::make_shared<IndependentAction>(6));
 
   SECTION("Topological ordering for subsets")
   {
@@ -305,18 +306,18 @@ TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order Very Compli
   //        /   /     /
   //         /  /   /
   //         [   e12    ]
-  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e8(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e5(EventSet({&e4}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e6(EventSet({&e4}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e7(EventSet({&e2, &e8}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e9(EventSet({&e6, &e7}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e10(EventSet({&e7}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e11(EventSet({&e8}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e12(EventSet({&e5, &e9, &e10}), std::make_shared<IndependentAction>());
+  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(1));
+  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(2));
+  UnfoldingEvent e8(EventSet({&e1}), std::make_shared<IndependentAction>(3));
+  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(4));
+  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>(5));
+  UnfoldingEvent e5(EventSet({&e4}), std::make_shared<IndependentAction>(6));
+  UnfoldingEvent e6(EventSet({&e4}), std::make_shared<IndependentAction>(7));
+  UnfoldingEvent e7(EventSet({&e2, &e8}), std::make_shared<IndependentAction>(8));
+  UnfoldingEvent e9(EventSet({&e6, &e7}), std::make_shared<IndependentAction>(9));
+  UnfoldingEvent e10(EventSet({&e7}), std::make_shared<IndependentAction>(10));
+  UnfoldingEvent e11(EventSet({&e8}), std::make_shared<IndependentAction>(11));
+  UnfoldingEvent e12(EventSet({&e5, &e9, &e10}), std::make_shared<IndependentAction>(12));
   Configuration C{&e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12};
 
   SECTION("Test every combination of the maximal configuration (forward graph)")
@@ -329,7 +330,7 @@ TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order Very Compli
 
     std::for_each(ordered_events.begin(), ordered_events.end(), [&events_seen](const UnfoldingEvent* e) {
       History history(e);
-      for (auto* e_hist : history) {
+      for (const auto* e_hist : history) {
         // In this demo, we want to make sure that
         // we don't mark not yet seeing `e` as an error.
         // The history of `e` traverses `e` itself. All
@@ -357,7 +358,7 @@ TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order Very Compli
     std::for_each(ordered_events.begin(), ordered_events.end(), [&events_seen](const UnfoldingEvent* e) {
       History history(e);
 
-      for (auto* e_hist : history) {
+      for (const auto* e_hist : history) {
         // Unlike the test above, we DO want to ensure
         // that `e` itself ALSO isn't yet seen
 
@@ -376,15 +377,13 @@ TEST_CASE("simgrid::mc::udpor::Configuration: Topological Sort Order Very Compli
 
     SECTION("Forward direction")
     {
-      auto ordered_events              = C.get_topologically_sorted_events();
-      const EventSet ordered_event_set = EventSet(std::move(ordered_events));
+      const auto ordered_event_set = EventSet(C.get_topologically_sorted_events());
       REQUIRE(events_seen == ordered_event_set);
     }
 
     SECTION("Reverse direction")
     {
-      auto ordered_events              = C.get_topologically_sorted_events_of_reverse_graph();
-      const EventSet ordered_event_set = EventSet(std::move(ordered_events));
+      const auto ordered_event_set = EventSet(C.get_topologically_sorted_events_of_reverse_graph());
       REQUIRE(events_seen == ordered_event_set);
     }
   }
@@ -407,14 +406,14 @@ TEST_CASE("simgrid::mc::udpor::maximal_subsets_iterator: Basic Testing of Maxima
   //           e3    e6
   //           /     / /
   //          e4    e7 e8
-  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e7(EventSet({&e6}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e8(EventSet({&e6}), std::make_shared<IndependentAction>());
+  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(1));
+  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+  UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>(3));
+  UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>(4));
+  UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>(5));
+  UnfoldingEvent e7(EventSet({&e6}), std::make_shared<IndependentAction>(6));
+  UnfoldingEvent e8(EventSet({&e6}), std::make_shared<IndependentAction>(7));
 
   SECTION("Iteration over an empty configuration yields only the empty set")
   {
@@ -465,7 +464,8 @@ TEST_CASE("simgrid::mc::udpor::maximal_subsets_iterator: Basic Testing of Maxima
     {
       EventSet interesting_bunch{&e2, &e4, &e7, &e8};
 
-      maximal_subsets_iterator first(C, [&](const UnfoldingEvent* e) { return interesting_bunch.contains(e); });
+      maximal_subsets_iterator first(
+          C, [&interesting_bunch](const UnfoldingEvent* e) { return interesting_bunch.contains(e); });
       maximal_subsets_iterator last;
 
       for (; first != last; ++first) {
@@ -498,7 +498,8 @@ TEST_CASE("simgrid::mc::udpor::maximal_subsets_iterator: Basic Testing of Maxima
     {
       EventSet interesting_bunch{&e3, &e5, &e6};
 
-      maximal_subsets_iterator first(C, [&](const UnfoldingEvent* e) { return interesting_bunch.contains(e); });
+      maximal_subsets_iterator first(
+          C, [&interesting_bunch](const UnfoldingEvent* e) { return interesting_bunch.contains(e); });
       maximal_subsets_iterator last;
 
       for (; first != last; ++first) {
@@ -540,24 +541,24 @@ TEST_CASE("simgrid::mc::udpor::maximal_subsets_iterator: Stress Test for Maximal
   //               |   e11 e12 e13 e14   e15
   //               |   /      / / /   /  /
   //               +-> e16     e17     e18
-  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e3(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e5(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e6(EventSet({&e3}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e7(EventSet({&e3}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e8(EventSet({&e4}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e9(EventSet({&e4, &e5, &e6}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e10(EventSet({&e6, &e7}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e11(EventSet({&e8}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e12(EventSet({&e8}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e13(EventSet({&e9}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e14(EventSet({&e9}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e15(EventSet({&e10}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e16(EventSet({&e5, &e11}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e17(EventSet({&e12, &e13, &e14}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e18(EventSet({&e14, &e15}), std::make_shared<IndependentAction>());
+  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(1));
+  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(2));
+  UnfoldingEvent e3(EventSet({&e1}), std::make_shared<IndependentAction>(3));
+  UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>(4));
+  UnfoldingEvent e5(EventSet({&e2}), std::make_shared<IndependentAction>(5));
+  UnfoldingEvent e6(EventSet({&e3}), std::make_shared<IndependentAction>(6));
+  UnfoldingEvent e7(EventSet({&e3}), std::make_shared<IndependentAction>(7));
+  UnfoldingEvent e8(EventSet({&e4}), std::make_shared<IndependentAction>(8));
+  UnfoldingEvent e9(EventSet({&e4, &e5, &e6}), std::make_shared<IndependentAction>(9));
+  UnfoldingEvent e10(EventSet({&e6, &e7}), std::make_shared<IndependentAction>(10));
+  UnfoldingEvent e11(EventSet({&e8}), std::make_shared<IndependentAction>(11));
+  UnfoldingEvent e12(EventSet({&e8}), std::make_shared<IndependentAction>(12));
+  UnfoldingEvent e13(EventSet({&e9}), std::make_shared<IndependentAction>(13));
+  UnfoldingEvent e14(EventSet({&e9}), std::make_shared<IndependentAction>(14));
+  UnfoldingEvent e15(EventSet({&e10}), std::make_shared<IndependentAction>(15));
+  UnfoldingEvent e16(EventSet({&e5, &e11}), std::make_shared<IndependentAction>(16));
+  UnfoldingEvent e17(EventSet({&e12, &e13, &e14}), std::make_shared<IndependentAction>(17));
+  UnfoldingEvent e18(EventSet({&e14, &e15}), std::make_shared<IndependentAction>(18));
   Configuration C{&e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18};
 
   SECTION("Every subset iterated over is maximal")
@@ -601,7 +602,196 @@ TEST_CASE("simgrid::mc::udpor::maximal_subsets_iterator: Stress Test for Maximal
   }
 }
 
-TEST_CASE("simgrid::mc::udpor:Configuration: Computing Full Alternatives in Reader/Writer Example")
+TEST_CASE("simgrid::mc::udpor::Configuration: Latest Transitions")
+{
+  // The following tests concern the given event structure (labeled as "event(actor)")
+  //                  e1(1)
+  //                 /     /
+  //              e2(1)   e3(2)
+  //              /    //     /
+  //            e4(3) e5(2)  e6(1)
+  //                  /   /
+  //               e7(1) e8(1)
+  const auto t1 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto t2 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto t3 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+  const auto t4 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 3);
+  const auto t5 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 2);
+  const auto t6 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto t7 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+  const auto t8 = std::make_shared<IndependentAction>(Transition::Type::UNKNOWN, 1);
+
+  const UnfoldingEvent e1(EventSet(), t1);
+  const UnfoldingEvent e2(EventSet({&e1}), t2);
+  const UnfoldingEvent e3(EventSet({&e1}), t3);
+  const UnfoldingEvent e4(EventSet({&e2}), t4);
+  const UnfoldingEvent e5(EventSet({&e2, &e3}), t5);
+  const UnfoldingEvent e6(EventSet({&e3}), t6);
+  const UnfoldingEvent e7(EventSet({&e5}), t7);
+  const UnfoldingEvent e8(EventSet({&e5}), t8);
+
+  SECTION("Test that the latest events are correct on initialization")
+  {
+    SECTION("Empty configuration has no events")
+    {
+      Configuration C;
+      REQUIRE_FALSE(C.get_latest_event_of(1).has_value());
+      REQUIRE_FALSE(C.get_latest_event_of(2).has_value());
+      REQUIRE_FALSE(C.get_latest_event_of(3).has_value());
+
+      REQUIRE_FALSE(C.get_latest_action_of(1).has_value());
+      REQUIRE_FALSE(C.get_latest_action_of(2).has_value());
+      REQUIRE_FALSE(C.get_latest_action_of(3).has_value());
+    }
+
+    SECTION("Missing two actors")
+    {
+      Configuration C{&e1};
+      REQUIRE(C.get_latest_event_of(1).has_value());
+      REQUIRE(C.get_latest_event_of(1).value() == &e1);
+
+      REQUIRE_FALSE(C.get_latest_event_of(2).has_value());
+      REQUIRE_FALSE(C.get_latest_event_of(3).has_value());
+
+      REQUIRE(C.get_latest_action_of(1).has_value());
+      REQUIRE(C.get_latest_action_of(1).value() == t1.get());
+
+      REQUIRE_FALSE(C.get_latest_action_of(2).has_value());
+      REQUIRE_FALSE(C.get_latest_action_of(3).has_value());
+    }
+
+    SECTION("Two events with one actor yields the latest event")
+    {
+      Configuration C{&e1, &e2};
+      REQUIRE(C.get_latest_event_of(1).has_value());
+      REQUIRE(C.get_latest_event_of(1).value() == &e2);
+
+      REQUIRE_FALSE(C.get_latest_event_of(2).has_value());
+      REQUIRE_FALSE(C.get_latest_event_of(3).has_value());
+
+      REQUIRE(C.get_latest_action_of(1).has_value());
+      REQUIRE(C.get_latest_action_of(1).value() == t2.get());
+
+      REQUIRE_FALSE(C.get_latest_action_of(2).has_value());
+      REQUIRE_FALSE(C.get_latest_action_of(3).has_value());
+    }
+
+    SECTION("Two events with two actors")
+    {
+      Configuration C{&e1, &e3};
+      REQUIRE(C.get_latest_event_of(1).has_value());
+      REQUIRE(C.get_latest_event_of(1).value() == &e1);
+
+      REQUIRE(C.get_latest_event_of(2).has_value());
+      REQUIRE(C.get_latest_event_of(2).value() == &e3);
+
+      REQUIRE_FALSE(C.get_latest_event_of(3).has_value());
+
+      REQUIRE(C.get_latest_action_of(1).has_value());
+      REQUIRE(C.get_latest_action_of(1).value() == t1.get());
+
+      REQUIRE(C.get_latest_action_of(2).has_value());
+      REQUIRE(C.get_latest_action_of(2).value() == t3.get());
+
+      REQUIRE_FALSE(C.get_latest_action_of(3).has_value());
+    }
+
+    SECTION("Three different actors actors")
+    {
+      Configuration C{&e1, &e2, &e3, &e4, &e5};
+      REQUIRE(C.get_latest_event_of(1).has_value());
+      REQUIRE(C.get_latest_event_of(1).value() == &e2);
+
+      REQUIRE(C.get_latest_event_of(2).has_value());
+      REQUIRE(C.get_latest_event_of(2).value() == &e5);
+
+      REQUIRE(C.get_latest_event_of(3).has_value());
+      REQUIRE(C.get_latest_event_of(3).value() == &e4);
+
+      REQUIRE(C.get_latest_action_of(1).has_value());
+      REQUIRE(C.get_latest_action_of(1).value() == t2.get());
+
+      REQUIRE(C.get_latest_action_of(2).has_value());
+      REQUIRE(C.get_latest_action_of(2).value() == t5.get());
+
+      REQUIRE(C.get_latest_action_of(3).has_value());
+      REQUIRE(C.get_latest_action_of(3).value() == t4.get());
+    }
+  }
+
+  SECTION("Test that the latest events are correct when adding new events")
+  {
+    Configuration C;
+    REQUIRE_FALSE(C.get_latest_event_of(1).has_value());
+    REQUIRE_FALSE(C.get_latest_event_of(2).has_value());
+    REQUIRE_FALSE(C.get_latest_event_of(3).has_value());
+    REQUIRE_FALSE(C.get_latest_action_of(1).has_value());
+    REQUIRE_FALSE(C.get_latest_action_of(2).has_value());
+    REQUIRE_FALSE(C.get_latest_action_of(3).has_value());
+
+    C.add_event(&e1);
+    REQUIRE(C.get_latest_event_of(1).has_value());
+    REQUIRE(C.get_latest_event_of(1).value() == &e1);
+    REQUIRE_FALSE(C.get_latest_event_of(2).has_value());
+    REQUIRE_FALSE(C.get_latest_event_of(3).has_value());
+    REQUIRE(C.get_latest_action_of(1).has_value());
+    REQUIRE(C.get_latest_action_of(1).value() == t1.get());
+    REQUIRE_FALSE(C.get_latest_action_of(2).has_value());
+    REQUIRE_FALSE(C.get_latest_action_of(3).has_value());
+
+    C.add_event(&e2);
+    REQUIRE(C.get_latest_event_of(1).has_value());
+    REQUIRE(C.get_latest_event_of(1).value() == &e2);
+    REQUIRE_FALSE(C.get_latest_event_of(2).has_value());
+    REQUIRE_FALSE(C.get_latest_event_of(3).has_value());
+    REQUIRE(C.get_latest_action_of(1).has_value());
+    REQUIRE(C.get_latest_action_of(1).value() == t2.get());
+    REQUIRE_FALSE(C.get_latest_action_of(2).has_value());
+    REQUIRE_FALSE(C.get_latest_action_of(3).has_value());
+
+    C.add_event(&e3);
+    REQUIRE(C.get_latest_event_of(1).has_value());
+    REQUIRE(C.get_latest_event_of(1).value() == &e2);
+    REQUIRE(C.get_latest_event_of(2).has_value());
+    REQUIRE(C.get_latest_event_of(2).value() == &e3);
+    REQUIRE_FALSE(C.get_latest_event_of(3).has_value());
+    REQUIRE(C.get_latest_action_of(1).has_value());
+    REQUIRE(C.get_latest_action_of(1).value() == t2.get());
+    REQUIRE(C.get_latest_action_of(2).has_value());
+    REQUIRE(C.get_latest_action_of(2).value() == t3.get());
+    REQUIRE_FALSE(C.get_latest_action_of(3).has_value());
+
+    C.add_event(&e4);
+    REQUIRE(C.get_latest_event_of(1).has_value());
+    REQUIRE(C.get_latest_event_of(1).value() == &e2);
+    REQUIRE(C.get_latest_event_of(2).has_value());
+    REQUIRE(C.get_latest_event_of(2).value() == &e3);
+    REQUIRE(C.get_latest_event_of(3).has_value());
+    REQUIRE(C.get_latest_event_of(3).value() == &e4);
+    REQUIRE(C.get_latest_action_of(1).has_value());
+    REQUIRE(C.get_latest_action_of(1).value() == t2.get());
+    REQUIRE(C.get_latest_action_of(2).has_value());
+    REQUIRE(C.get_latest_action_of(2).value() == t3.get());
+    REQUIRE(C.get_latest_action_of(3).has_value());
+    REQUIRE(C.get_latest_action_of(3).value() == t4.get());
+
+    C.add_event(&e5);
+    REQUIRE(C.get_latest_event_of(1).has_value());
+    REQUIRE(C.get_latest_event_of(1).value() == &e2);
+    REQUIRE(C.get_latest_event_of(2).has_value());
+    REQUIRE(C.get_latest_event_of(2).value() == &e5);
+    REQUIRE(C.get_latest_event_of(3).has_value());
+    REQUIRE(C.get_latest_event_of(3).value() == &e4);
+    REQUIRE(C.get_latest_action_of(1).has_value());
+    REQUIRE(C.get_latest_action_of(1).value() == t2.get());
+    REQUIRE(C.get_latest_action_of(2).has_value());
+    REQUIRE(C.get_latest_action_of(2).value() == t5.get());
+    REQUIRE(C.get_latest_action_of(3).has_value());
+    REQUIRE(C.get_latest_action_of(3).value() == t4.get());
+  }
+}
+
+TEST_CASE("simgrid::mc::udpor::Configuration: Computing Full Alternatives in Reader/Writer Example")
 {
   // The following tests concern the given event structure that is given as
   // an example in figure 1 of the original UDPOR paper.
@@ -620,38 +810,49 @@ TEST_CASE("simgrid::mc::udpor:Configuration: Computing Full Alternatives in Read
   // then `e4`, and then `e7`
   Unfolding U;
 
-  auto e0        = std::make_unique<UnfoldingEvent>(EventSet(), std::make_shared<ConditionallyDependentAction>());
-  auto e0_handle = e0.get();
+  auto e0 = std::make_unique<UnfoldingEvent>(
+      EventSet(), std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 0));
+  const auto* e0_handle = e0.get();
 
-  auto e1        = std::make_unique<UnfoldingEvent>(EventSet({e0_handle}), std::make_shared<DependentAction>());
-  auto e1_handle = e1.get();
+  auto e1        = std::make_unique<UnfoldingEvent>(EventSet({e0_handle}),
+                                             std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 0));
+  const auto* e1_handle = e1.get();
 
-  auto e2 = std::make_unique<UnfoldingEvent>(EventSet({e1_handle}), std::make_shared<ConditionallyDependentAction>());
-  auto e2_handle = e2.get();
+  auto e2 = std::make_unique<UnfoldingEvent>(
+      EventSet({e1_handle}), std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1));
+  const auto* e2_handle = e2.get();
 
-  auto e3 = std::make_unique<UnfoldingEvent>(EventSet({e1_handle}), std::make_shared<ConditionallyDependentAction>());
-  auto e3_handle = e3.get();
+  auto e3 = std::make_unique<UnfoldingEvent>(
+      EventSet({e1_handle}), std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2));
+  const auto* e3_handle = e3.get();
 
-  auto e4 = std::make_unique<UnfoldingEvent>(EventSet({e0_handle}), std::make_shared<ConditionallyDependentAction>());
-  auto e4_handle = e4.get();
+  auto e4 = std::make_unique<UnfoldingEvent>(
+      EventSet({e0_handle}), std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1));
+  const auto* e4_handle = e4.get();
 
-  auto e5        = std::make_unique<UnfoldingEvent>(EventSet({e4_handle}), std::make_shared<DependentAction>());
-  auto e5_handle = e5.get();
+  auto e5        = std::make_unique<UnfoldingEvent>(EventSet({e4_handle}),
+                                             std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 0));
+  const auto* e5_handle = e5.get();
 
-  auto e6 = std::make_unique<UnfoldingEvent>(EventSet({e5_handle}), std::make_shared<ConditionallyDependentAction>());
-  auto e6_handle = e6.get();
+  auto e6 = std::make_unique<UnfoldingEvent>(
+      EventSet({e5_handle}), std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2));
+  const auto* e6_handle = e6.get();
 
-  auto e7 = std::make_unique<UnfoldingEvent>(EventSet({e0_handle}), std::make_shared<ConditionallyDependentAction>());
-  auto e7_handle = e7.get();
+  auto e7 = std::make_unique<UnfoldingEvent>(
+      EventSet({e0_handle}), std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 2));
+  const auto* e7_handle = e7.get();
 
-  auto e8 = std::make_unique<UnfoldingEvent>(EventSet({e4_handle, e7_handle}), std::make_shared<DependentAction>());
-  auto e8_handle = e8.get();
+  auto e8        = std::make_unique<UnfoldingEvent>(EventSet({e4_handle, e7_handle}),
+                                             std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 0));
+  const auto* e8_handle = e8.get();
 
-  auto e9        = std::make_unique<UnfoldingEvent>(EventSet({e7_handle}), std::make_shared<DependentAction>());
-  auto e9_handle = e9.get();
+  auto e9        = std::make_unique<UnfoldingEvent>(EventSet({e7_handle}),
+                                             std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 0));
+  const auto* e9_handle = e9.get();
 
-  auto e10 = std::make_unique<UnfoldingEvent>(EventSet({e9_handle}), std::make_shared<ConditionallyDependentAction>());
-  auto e10_handle = e10.get();
+  auto e10 = std::make_unique<UnfoldingEvent>(
+      EventSet({e9_handle}), std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 1));
+  const auto* e10_handle = e10.get();
 
   SECTION("Alternative computation call 1")
   {
@@ -766,7 +967,7 @@ TEST_CASE("simgrid::mc::udpor:Configuration: Computing Full Alternatives in Read
     // The first alternative that is found is the one that is chosen. Since
     // traversal over the elements of an unordered_set<> are not guaranteed,
     // both {e0, e4} and {e0, e7} are valid alternatives
-    REQUIRE((alternative.value().get_events() == EventSet({e0_handle, e4_handle}) or
+    REQUIRE((alternative.value().get_events() == EventSet({e0_handle, e4_handle}) ||
              alternative.value().get_events() == EventSet({e0_handle, e7_handle})));
   }
 
@@ -856,8 +1057,8 @@ TEST_CASE("simgrid::mc::udpor:Configuration: Computing Full Alternatives in Read
 
     const auto alternative = C.compute_alternative_to(D_plus_e, U);
     REQUIRE(alternative.has_value());
-    REQUIRE((alternative.value().get_events() == EventSet({e0_handle, e7_handle}) or
-             alternative.value().get_events() == EventSet({e0_handle, e4_handle, e7_handle}) or
+    REQUIRE((alternative.value().get_events() == EventSet({e0_handle, e7_handle}) ||
+             alternative.value().get_events() == EventSet({e0_handle, e4_handle, e7_handle}) ||
              alternative.value().get_events() == EventSet({e0_handle, e4_handle, e7_handle, e8_handle})));
   }
 
@@ -1163,4 +1364,4 @@ TEST_CASE("simgrid::mc::udpor:Configuration: Computing Full Alternatives in Read
       REQUIRE(alternative.value().get_events() == EventSet({e0_handle, e7_handle, e9_handle}));
     }
   }
-}
\ No newline at end of file
+}
index 09cb66b..929234e 100644 (file)
@@ -14,7 +14,7 @@
 
 namespace simgrid::mc::udpor {
 
-EventSet::EventSet(Configuration&& config) : EventSet(config.get_events()) {}
+EventSet::EventSet(const Configuration& config) : EventSet(config.get_events()) {}
 
 void EventSet::remove(const UnfoldingEvent* e)
 {
@@ -90,6 +90,19 @@ EventSet EventSet::make_union(const Configuration& config) const
   return make_union(config.get_events());
 }
 
+EventSet EventSet::make_intersection(const EventSet& other) const
+{
+  std::unordered_set<const UnfoldingEvent*> result;
+
+  for (const UnfoldingEvent* e : other.events_) {
+    if (contains(e)) {
+      result.insert(e);
+    }
+  }
+
+  return EventSet(std::move(result));
+}
+
 EventSet EventSet::get_local_config() const
 {
   return History(*this).get_all_events();
@@ -110,6 +123,11 @@ bool EventSet::contains(const UnfoldingEvent* e) const
   return this->events_.find(e) != this->events_.end();
 }
 
+bool EventSet::contains_equivalent_to(const UnfoldingEvent* e) const
+{
+  return std::find_if(begin(), end(), [=](const UnfoldingEvent* e_in_set) { return *e == *e_in_set; }) != end();
+}
+
 bool EventSet::is_subset_of(const EventSet& other) const
 {
   // If there is some element not contained in `other`, then
@@ -142,13 +160,23 @@ bool EventSet::intersects(const History& history) const
   return std::any_of(history.begin(), history.end(), [=](const UnfoldingEvent* e) { return this->contains(e); });
 }
 
+bool EventSet::intersects(const EventSet& other) const
+{
+  return std::any_of(other.begin(), other.end(), [=](const UnfoldingEvent* e) { return this->contains(e); });
+}
+
+EventSet EventSet::get_largest_maximal_subset() const
+{
+  const History history(*this);
+  return history.get_all_maximal_events();
+}
+
 bool EventSet::is_maximal() const
 {
   // A set of events is maximal if no event from
   // the original set is ruled out when traversing
   // the history of the events
-  const History history(*this);
-  return *this == history.get_all_maximal_events();
+  return *this == this->get_largest_maximal_subset();
 }
 
 bool EventSet::is_conflict_free() const
@@ -192,7 +220,7 @@ std::vector<const UnfoldingEvent*> EventSet::get_topological_ordering() const
         temporarily_marked_events.insert(evt);
 
         EventSet immediate_causes = evt->get_immediate_causes();
-        if (!immediate_causes.empty() && immediate_causes.is_subset_of(temporarily_marked_events)) {
+        if (not immediate_causes.empty() && immediate_causes.is_subset_of(temporarily_marked_events)) {
           throw std::invalid_argument("Attempted to perform a topological sort on a configuration "
                                       "whose contents contain a cycle. The configuration (and the graph "
                                       "connecting all of the events) is an invalid event structure");
@@ -233,6 +261,18 @@ std::vector<const UnfoldingEvent*> EventSet::get_topological_ordering_of_reverse
   return topological_events;
 }
 
+std::string EventSet::to_string() const
+{
+  std::string contents;
+
+  for (const auto* event : *this) {
+    contents += event->to_string();
+    contents += " + ";
+  }
+
+  return contents;
+}
+
 std::vector<const UnfoldingEvent*> EventSet::move_into_vector() const&&
 {
   std::vector<const UnfoldingEvent*> contents;
@@ -245,4 +285,4 @@ std::vector<const UnfoldingEvent*> EventSet::move_into_vector() const&&
   return contents;
 }
 
-} // namespace simgrid::mc::udpor
\ No newline at end of file
+} // namespace simgrid::mc::udpor
index 54c00c8..32be66f 100644 (file)
@@ -8,10 +8,12 @@
 
 #include "src/mc/explo/udpor/udpor_forward.hpp"
 
+#include <algorithm>
 #include <cstddef>
 #include <initializer_list>
 #include <unordered_set>
 #include <vector>
+#include <xbt/asserts.h>
 
 namespace simgrid::mc::udpor {
 
@@ -25,9 +27,12 @@ public:
   EventSet& operator=(const EventSet&) = default;
   EventSet& operator=(EventSet&&)      = default;
   EventSet(EventSet&&)                 = default;
-  explicit EventSet(Configuration&& config);
-  explicit EventSet(std::vector<const UnfoldingEvent*>&& raw_events) : events_(raw_events.begin(), raw_events.end()) {}
-  explicit EventSet(std::unordered_set<const UnfoldingEvent*>&& raw_events) : events_(raw_events) {}
+  explicit EventSet(const Configuration& config);
+  explicit EventSet(const std::vector<const UnfoldingEvent*>& raw_events)
+      : events_(raw_events.begin(), raw_events.end())
+  {
+  }
+  explicit EventSet(std::unordered_set<const UnfoldingEvent*>&& raw_events) : events_(std::move(raw_events)) {}
   explicit EventSet(std::initializer_list<const UnfoldingEvent*> event_list) : events_(std::move(event_list)) {}
 
   auto begin() const { return this->events_.begin(); }
@@ -48,17 +53,22 @@ public:
   EventSet make_union(const UnfoldingEvent*) const;
   EventSet make_union(const EventSet&) const;
   EventSet make_union(const Configuration&) const;
+  EventSet make_intersection(const EventSet&) const;
   EventSet get_local_config() const;
 
   size_t size() const;
   bool empty() const;
+
   bool contains(const UnfoldingEvent*) const;
   bool contains(const History&) const;
+  bool contains_equivalent_to(const UnfoldingEvent*) const;
+  bool intersects(const EventSet&) const;
   bool intersects(const History&) const;
   bool is_subset_of(const EventSet&) const;
 
   bool operator==(const EventSet& other) const { return this->events_ == other.events_; }
   bool operator!=(const EventSet& other) const { return this->events_ != other.events_; }
+  std::string to_string() const;
 
   /**
    * @brief Whether or not this set of events could
@@ -104,6 +114,12 @@ public:
    */
   bool is_conflict_free() const;
 
+  /**
+   * @brief Produces the largest subset of this
+   * set of events which is maximal
+   */
+  EventSet get_largest_maximal_subset() const;
+
   /**
    * @brief Orders the events of the set such that
    * "more recent" events (i.e. those that are farther down in
index 684ac5d..4c8287c 100644 (file)
@@ -41,7 +41,9 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Initial conditions when creating sets")
 
   SECTION("Initialization with one or more elements")
   {
-    UnfoldingEvent e1, e2, e3;
+    UnfoldingEvent e1;
+    UnfoldingEvent e2;
+    UnfoldingEvent e3;
 
     SECTION("Set initializer")
     {
@@ -68,7 +70,9 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Initial conditions when creating sets")
 TEST_CASE("simgrid::mc::udpor::EventSet: Insertions")
 {
   EventSet event_set;
-  UnfoldingEvent e1, e2, e3;
+  UnfoldingEvent e1;
+  UnfoldingEvent e2;
+  UnfoldingEvent e3;
 
   SECTION("Inserting unique elements")
   {
@@ -192,7 +196,9 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Set Equality")
   UnfoldingEvent e2;
   UnfoldingEvent e3;
   UnfoldingEvent e4;
-  EventSet A{&e1, &e2, &e3}, B{&e1, &e2, &e3}, C{&e1, &e2, &e3};
+  EventSet A{&e1, &e2, &e3};
+  EventSet B{&e1, &e2, &e3};
+  EventSet C{&e1, &e2, &e3};
 
   SECTION("Equality implies containment")
   {
@@ -267,10 +273,16 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Set Equality")
 
 TEST_CASE("simgrid::mc::udpor::EventSet: Set Union Tests")
 {
-  UnfoldingEvent e1, e2, e3, e4;
+  UnfoldingEvent e1;
+  UnfoldingEvent e2;
+  UnfoldingEvent e3;
+  UnfoldingEvent e4;
 
   // C = A + B
-  EventSet A{&e1, &e2, &e3}, B{&e2, &e3, &e4}, C{&e1, &e2, &e3, &e4}, D{&e1, &e3};
+  EventSet A{&e1, &e2, &e3};
+  EventSet B{&e2, &e3, &e4};
+  EventSet C{&e1, &e2, &e3, &e4};
+  EventSet D{&e1, &e3};
 
   SECTION("Unions with no effect")
   {
@@ -395,7 +407,12 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Set Difference Tests")
   // D is a subset of A and C
   // E is a subset of B and C
   // F is a subset of A, C, and D
-  EventSet A{&e1, &e2, &e3}, B{&e2, &e3, &e4}, C{&e1, &e2, &e3, &e4}, D{&e1, &e3}, E{&e4}, F{&e1};
+  EventSet A{&e1, &e2, &e3};
+  EventSet B{&e2, &e3, &e4};
+  EventSet C{&e1, &e2, &e3, &e4};
+  EventSet D{&e1, &e3};
+  EventSet E{&e4};
+  EventSet F{&e1};
 
   SECTION("Difference with no effect")
   {
@@ -465,7 +482,10 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Set Difference Tests")
 
 TEST_CASE("simgrid::mc::udpor::EventSet: Subset Tests")
 {
-  UnfoldingEvent e1, e2, e3, e4;
+  UnfoldingEvent e1;
+  UnfoldingEvent e2;
+  UnfoldingEvent e3;
+  UnfoldingEvent e4;
 
   // A is a subset of C only
   // B is a subset of C only
@@ -473,7 +493,12 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Subset Tests")
   // D is NOT a subset of B
   // B is NOT a subset of D
   // ...
-  EventSet A{&e1, &e2, &e3}, B{&e2, &e3, &e4}, C{&e1, &e2, &e3, &e4}, D{&e1, &e3}, E{&e2, &e3}, F{&e1, &e2, &e3};
+  EventSet A{&e1, &e2, &e3};
+  EventSet B{&e2, &e3, &e4};
+  EventSet C{&e1, &e2, &e3, &e4};
+  EventSet D{&e1, &e3};
+  EventSet E{&e2, &e3};
+  EventSet F{&e1, &e2, &e3};
 
   SECTION("Subset operator properties")
   {
@@ -527,12 +552,12 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Testing Configurations")
   // The tests enumerate all possible subsets of the events
   // in the structure and test whether those subsets are
   // maximal and/or valid configurations
-  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>());
-  UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>());
+  UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+  UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(1));
+  UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+  UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>(3));
+  UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>(4));
+  UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>(5));
 
   SECTION("Valid Configurations")
   {
@@ -745,15 +770,15 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Moving into a collection")
   EventSet C_copy = C;
   EventSet D_copy = D;
 
-  std::vector<const UnfoldingEvent*> actual_A = std::move(A).move_into_vector();
-  std::vector<const UnfoldingEvent*> actual_B = std::move(B).move_into_vector();
-  std::vector<const UnfoldingEvent*> actual_C = std::move(C).move_into_vector();
-  std::vector<const UnfoldingEvent*> actual_D = std::move(D).move_into_vector();
+  const std::vector<const UnfoldingEvent*> actual_A = std::move(A).move_into_vector();
+  const std::vector<const UnfoldingEvent*> actual_B = std::move(B).move_into_vector();
+  const std::vector<const UnfoldingEvent*> actual_C = std::move(C).move_into_vector();
+  const std::vector<const UnfoldingEvent*> actual_D = std::move(D).move_into_vector();
 
-  EventSet A_copy_remade(std::move(actual_A));
-  EventSet B_copy_remade(std::move(actual_B));
-  EventSet C_copy_remade(std::move(actual_C));
-  EventSet D_copy_remade(std::move(actual_D));
+  EventSet A_copy_remade(actual_A);
+  EventSet B_copy_remade(actual_B);
+  EventSet C_copy_remade(actual_C);
+  EventSet D_copy_remade(actual_D);
 
   REQUIRE(A_copy == A_copy_remade);
   REQUIRE(B_copy == B_copy_remade);
@@ -778,12 +803,12 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Checking conflicts")
 
   SECTION("No conflicts throughout the whole structure with independent actions")
   {
-    UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>());
+    UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(1));
+    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+    UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>(3));
+    UnfoldingEvent e5(EventSet({&e1}), std::make_shared<IndependentAction>(4));
+    UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>(5));
 
     // 6 choose 0 = 1 test
     CHECK(EventSet().is_conflict_free());
@@ -958,12 +983,12 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Checking conflicts")
 
   SECTION("Conditional conflicts")
   {
-    UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<ConditionallyDependentAction>());
-    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e5(EventSet({&e1}), std::make_shared<DependentAction>());
-    UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>());
+    UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<ConditionallyDependentAction>(1));
+    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+    UnfoldingEvent e4(EventSet({&e2}), std::make_shared<IndependentAction>(3));
+    UnfoldingEvent e5(EventSet({&e1}), std::make_shared<DependentAction>(4));
+    UnfoldingEvent e6(EventSet({&e5}), std::make_shared<IndependentAction>(5));
 
     // 6 choose 0 = 1 test
     // There are no events even to be in conflict with
@@ -1086,44 +1111,34 @@ TEST_CASE("simgrid::mc::udpor::EventSet: Topological Ordering Property Observed
       return subset_local;
     }();
 
-    {
-      // To test this, we verify that at each point none of the events
-      // that follow after any particular event `e` are contained in
-      // `e`'s history
-      EventSet invalid_events   = subset;
-      const auto ordered_events = subset.get_topological_ordering();
-
-      std::for_each(ordered_events.begin(), ordered_events.end(), [&](const UnfoldingEvent* e) {
-        History history(e);
-        for (auto* e_hist : history) {
-          if (e_hist == e)
-            continue;
-          REQUIRE_FALSE(invalid_events.contains(e_hist));
-        }
-        invalid_events.remove(e);
-      });
+    // To test this, we verify that at each point none of the events
+    // that follow after any particular event `e` are contained in
+    // `e`'s history
+    EventSet invalid_events = subset;
+    for (const auto* e : subset.get_topological_ordering()) {
+      for (const auto* e_hist : History(e)) {
+        if (e_hist == e)
+          continue;
+        REQUIRE_FALSE(invalid_events.contains(e_hist));
+      }
+      invalid_events.remove(e);
     }
-    {
-      // To test this, we verify that at each point none of the events
-      // that we've processed in the ordering are ever seen again
-      // in anybody else's history
-      EventSet events_seen;
-      const auto ordered_events = subset.get_topological_ordering_of_reverse_graph();
-
-      std::for_each(ordered_events.begin(), ordered_events.end(), [&events_seen](const UnfoldingEvent* e) {
-        History history(e);
-
-        for (auto* e_hist : history) {
-          // Unlike the test above, we DO want to ensure
-          // that `e` itself ALSO isn't yet seen
-
-          // If this event has been "seen" before,
-          // this implies that event `e` appears later
-          // in the list than one of its ancestors
-          REQUIRE_FALSE(events_seen.contains(e_hist));
-        }
-        events_seen.insert(e);
-      });
+
+    // To test this, we verify that at each point none of the events
+    // that we've processed in the ordering are ever seen again
+    // in anybody else's history
+    EventSet events_seen;
+    for (const auto* e : subset.get_topological_ordering_of_reverse_graph()) {
+      for (const auto* e_hist : History(e)) {
+        // Unlike the test above, we DO want to ensure
+        // that `e` itself ALSO isn't yet seen
+
+        // If this event has been "seen" before,
+        // this implies that event `e` appears later
+        // in the list than one of its ancestors
+        REQUIRE_FALSE(events_seen.contains(e_hist));
+      }
+      events_seen.insert(e);
     }
   }
 }
diff --git a/src/mc/explo/udpor/ExtensionSetCalculator.cpp b/src/mc/explo/udpor/ExtensionSetCalculator.cpp
new file mode 100644 (file)
index 0000000..e928105
--- /dev/null
@@ -0,0 +1,636 @@
+/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/mc/explo/udpor/ExtensionSetCalculator.hpp"
+#include "src/mc/explo/udpor/Configuration.hpp"
+#include "src/mc/explo/udpor/History.hpp"
+#include "src/mc/explo/udpor/Unfolding.hpp"
+
+#include <functional>
+#include <unordered_map>
+#include <xbt/asserts.h>
+#include <xbt/ex.h>
+
+using namespace simgrid::mc;
+
+namespace simgrid::mc::udpor {
+
+EventSet ExtensionSetCalculator::partially_extend(const Configuration& C, Unfolding* U,
+                                                  std::shared_ptr<Transition> action)
+{
+  using Action     = Transition::Type;
+  using Handler    = std::function<EventSet(const Configuration&, Unfolding*, const std::shared_ptr<Transition>)>;
+  using HandlerMap = std::unordered_map<Action, Handler>;
+
+  const static HandlerMap handlers = {
+      {Action::COMM_ASYNC_RECV, &ExtensionSetCalculator::partially_extend_CommRecv},
+      {Action::COMM_ASYNC_SEND, &ExtensionSetCalculator::partially_extend_CommSend},
+      {Action::COMM_WAIT, &ExtensionSetCalculator::partially_extend_CommWait},
+      {Action::COMM_TEST, &ExtensionSetCalculator::partially_extend_CommTest},
+      {Action::MUTEX_ASYNC_LOCK, &ExtensionSetCalculator::partially_extend_MutexAsyncLock},
+      {Action::MUTEX_UNLOCK, &ExtensionSetCalculator::partially_extend_MutexUnlock},
+      {Action::MUTEX_WAIT, &ExtensionSetCalculator::partially_extend_MutexWait},
+      {Action::MUTEX_TEST, &ExtensionSetCalculator::partially_extend_MutexTest},
+      {Action::ACTOR_JOIN, &ExtensionSetCalculator::partially_extend_ActorJoin}};
+
+  if (const auto handler = handlers.find(action->type_); handler != handlers.end()) {
+    return handler->second(C, U, std::move(action));
+  } else {
+    xbt_die("There is currently no specialized computation for the transition "
+            "'%s' for computing extension sets in UDPOR, so the model checker cannot "
+            "determine how to proceed. Please submit a bug report requesting "
+            "that the transition be supported in SimGrid using UDPOR and consider "
+            "using the other model-checking algorithms supported by SimGrid instead "
+            "in the meantime",
+            action->to_string().c_str());
+  }
+}
+
+EventSet ExtensionSetCalculator::partially_extend_CommSend(const Configuration& C, Unfolding* U,
+                                                           std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+
+  const auto send_action        = std::static_pointer_cast<CommSendTransition>(action);
+  const auto pre_event_a_C      = C.pre_event(send_action->aid_);
+  const unsigned sender_mailbox = send_action->get_mailbox();
+
+  // 1. Create `e' := <a, config(preEvt(a, C))>` and add `e'` to `ex(C)`
+  // NOTE: If `preEvt(a, C)` doesn't exist, we're effectively asking
+  // about `config({})`
+  if (pre_event_a_C.has_value()) {
+    const auto* e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), send_action);
+    exC.insert(e_prime);
+  } else {
+    const auto* e_prime = U->discover_event(EventSet(), send_action);
+    exC.insert(e_prime);
+  }
+
+  // 2. foreach e ∈ C s.t. λ(e) ∈ {AsyncSend(m, _), TestAny(Com)} where
+  // Com contains a matching c' = AsyncReceive(m, _) with `action`
+  for (const auto e : C) {
+    const bool transition_type_check = [&]() {
+      const auto* async_send = dynamic_cast<const CommSendTransition*>(e->get_transition());
+      return async_send && async_send->get_mailbox() == sender_mailbox;
+      // TODO: Add `TestAny` dependency
+    }();
+
+    if (transition_type_check) {
+      EventSet K = EventSet({e, pre_event_a_C.value_or(e)}).get_largest_maximal_subset();
+
+      // TODO: Check D_K(a, lambda(e)) (only matters in the case of CommTest)
+      const auto e_prime = U->discover_event(std::move(K), send_action);
+      exC.insert(e_prime);
+    }
+  }
+
+  // TODO: Add `TestAny` dependency case
+  return exC;
+}
+
+EventSet ExtensionSetCalculator::partially_extend_CommRecv(const Configuration& C, Unfolding* U,
+                                                           std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+
+  const auto recv_action      = std::static_pointer_cast<CommRecvTransition>(action);
+  const unsigned recv_mailbox = recv_action->get_mailbox();
+  const auto pre_event_a_C    = C.pre_event(recv_action->aid_);
+
+  // 1. Create `e' := <a, config(preEvt(a, C))>` and add `e'` to `ex(C)`
+  if (pre_event_a_C.has_value()) {
+    const auto* e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), recv_action);
+    exC.insert(e_prime);
+  } else {
+    const auto* e_prime = U->discover_event(EventSet(), recv_action);
+    exC.insert(e_prime);
+  }
+
+  // 2. foreach e ∈ C s.t. λ(e) ∈ {AsyncSend(m, _), TestAny(Com)} where
+  // Com contains a matching c' = AsyncReceive(m, _) with a
+  for (const auto e : C) {
+    const bool transition_type_check = [&]() {
+      const auto* async_recv = dynamic_cast<const CommRecvTransition*>(e->get_transition());
+      return async_recv && async_recv->get_mailbox() == recv_mailbox;
+      // TODO: Add `TestAny` dependency
+    }();
+
+    if (transition_type_check) {
+      EventSet K = EventSet({e, pre_event_a_C.value_or(e)}).get_largest_maximal_subset();
+
+      // TODO: Check D_K(a, lambda(e)) (ony matters in the case of TestAny)
+      if (true) {
+        const auto* e_prime = U->discover_event(std::move(K), recv_action);
+        exC.insert(e_prime);
+      }
+    }
+  }
+
+  // TODO: Add `TestAny` dependency case
+  return exC;
+}
+
+EventSet ExtensionSetCalculator::partially_extend_CommWait(const Configuration& C, Unfolding* U,
+                                                           std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+
+  const auto wait_action   = std::static_pointer_cast<CommWaitTransition>(action);
+  const auto wait_comm     = wait_action->get_comm();
+  const auto pre_event_a_C = C.pre_event(wait_action->aid_);
+
+  // Determine the _issuer_ of the communication of the `CommWait` event
+  // in `C`. The issuer of the `CommWait` in `C` is the event in `C`
+  // whose transition is the `CommRecv` or `CommSend` whose resulting
+  // communication this `CommWait` waits on
+  const auto issuer = std::find_if(C.begin(), C.end(), [&](const UnfoldingEvent* e) {
+    if (const auto* e_issuer_receive = dynamic_cast<const CommRecvTransition*>(e->get_transition())) {
+      return e_issuer_receive->aid_ == wait_action->aid_ && wait_comm == e_issuer_receive->get_comm();
+    }
+
+    if (const auto* e_issuer_send = dynamic_cast<const CommSendTransition*>(e->get_transition())) {
+      return e_issuer_send->aid_ == wait_action->aid_ && wait_comm == e_issuer_send->get_comm();
+    }
+
+    return false;
+  });
+  xbt_assert(issuer != C.end(),
+             "Invariant violation! A (supposedly) enabled `CommWait` transition "
+             "waiting on communication %u should not be enabled: the receive/send "
+             "transition which generated the communication is not an action taken "
+             "to reach state(C) (the state of the configuration), which should "
+             "be an impossibility if `%s` is enabled. Please report this as "
+             "a bug in SimGrid's UDPOR implementation",
+             wait_action->get_comm(), wait_action->to_string(false).c_str());
+  const UnfoldingEvent* e_issuer = *issuer;
+  const History e_issuer_history(e_issuer);
+
+  // 1. if `a` is enabled at state(config({preEvt(a,C)})), then
+  // create `e' := <a, config({preEvt(a,C)})>` and add `e'` to `ex(C)`
+  //
+  // First, if `pre_event_a_C == std::nullopt`, then there is nothing to
+  // do: `CommWait` will never be enabled in the empty configuration (at
+  // least two actions must be executed before)
+  if (pre_event_a_C.has_value(); const auto* unwrapped_pre_event = pre_event_a_C.value()) {
+    // A necessary condition is that the issuer be present in
+    // config({preEvt(a, C)}); otherwise, the `CommWait` could not
+    // be enabled since the communication on which it waits would not
+    // have been created for it!
+    if (const auto config_pre_event = History(unwrapped_pre_event); config_pre_event.contains(e_issuer)) {
+      // If the issuer is a `CommRecv` (resp. `CommSend`), then we check that there
+      // are at least as many `CommSend` (resp. `CommRecv`) transitions in `config_pre_event`
+      // as needed to reach the receive/send number that is `issuer`.
+      // ...
+      // ...
+      if (const auto* e_issuer_receive = dynamic_cast<const CommRecvTransition*>(e_issuer->get_transition())) {
+        const unsigned issuer_mailbox = e_issuer_receive->get_mailbox();
+
+        // Check from the config -> how many sends have there been
+        const unsigned send_position =
+            std::count_if(config_pre_event.begin(), config_pre_event.end(), [=](const auto e) {
+              const auto* e_send = dynamic_cast<const CommSendTransition*>(e->get_transition());
+              return e_send && e_send->get_mailbox() == issuer_mailbox;
+            });
+
+        // Check from e_issuer -> what place is the issuer in?
+        const unsigned receive_position =
+            std::count_if(e_issuer_history.begin(), e_issuer_history.end(), [=](const auto e) {
+              const auto* e_receive = dynamic_cast<const CommRecvTransition*>(e->get_transition());
+              return e_receive && e_receive->get_mailbox() == issuer_mailbox;
+            });
+
+        if (send_position >= receive_position) {
+          exC.insert(U->discover_event(EventSet({unwrapped_pre_event}), wait_action));
+        }
+
+      } else if (const auto* e_issuer_send = dynamic_cast<const CommSendTransition*>(e_issuer->get_transition())) {
+        const unsigned issuer_mailbox = e_issuer_send->get_mailbox();
+
+        // Check from e_issuer -> what place is the issuer in?
+        const unsigned send_position =
+            std::count_if(e_issuer_history.begin(), e_issuer_history.end(), [=](const auto e) {
+              const auto* e_send = dynamic_cast<const CommSendTransition*>(e->get_transition());
+              return e_send && e_send->get_mailbox() == issuer_mailbox;
+            });
+
+        // Check from the config -> how many sends have there been
+        const unsigned receive_position =
+            std::count_if(config_pre_event.begin(), config_pre_event.end(), [=](const auto e) {
+              const auto* e_receive = dynamic_cast<const CommRecvTransition*>(e->get_transition());
+              return e_receive && e_receive->get_mailbox() == issuer_mailbox;
+            });
+
+        if (send_position <= receive_position) {
+          exC.insert(U->discover_event(EventSet({unwrapped_pre_event}), wait_action));
+        }
+
+      } else {
+        xbt_die("The transition which created the communication on which `%s` waits "
+                "is neither an async send nor an async receive. The current UDPOR "
+                "implementation does not know how to check if `CommWait` is enabled in "
+                "this case. Was a new transition added?",
+                e_issuer->get_transition()->to_string().c_str());
+      }
+    }
+  }
+
+  // 3. foreach event e in C do
+  if (const auto* e_issuer_send = dynamic_cast<const CommSendTransition*>(e_issuer->get_transition())) {
+    for (const auto e : C) {
+      // If the provider of the communication for `CommWait` is a
+      // `CommSend(m)`, then we only care about `e` if `λ(e) == `CommRecv(m)`.
+      // All other actions would be independent with the wait action (including
+      // another `CommSend` to the same mailbox: `CommWait` is "waiting" for its
+      // corresponding receive action)
+      if (e->get_transition()->type_ != Transition::Type::COMM_ASYNC_RECV) {
+        continue;
+      }
+
+      const auto issuer_mailbox        = e_issuer_send->get_mailbox();
+      if (const auto* e_recv = dynamic_cast<const CommRecvTransition*>(e->get_transition());
+          e_recv->get_mailbox() != issuer_mailbox) {
+        continue;
+      }
+
+      // If the `issuer` is not in `config(K)`, this implies that
+      // `WaitAny()` is always disabled in `config(K)`; hence, it
+      // is independent of any transition in `config(K)` (according
+      // to formal definition of independence)
+      auto K              = EventSet({e, pre_event_a_C.value_or(e)});
+      const auto config_K = History(K);
+      if (not config_K.contains(e_issuer)) {
+        continue;
+      }
+
+      // What send # is the issuer
+      const unsigned send_position =
+          std::count_if(e_issuer_history.begin(), e_issuer_history.end(), [=](const auto ev) {
+            const auto* e_send = dynamic_cast<const CommSendTransition*>(ev->get_transition());
+            return e_send && e_send->get_mailbox() == issuer_mailbox;
+          });
+
+      // What receive # is the event `e`?
+      const unsigned receive_position = std::count_if(config_K.begin(), config_K.end(), [=](const auto ev) {
+        const auto* e_receive = dynamic_cast<const CommRecvTransition*>(ev->get_transition());
+        return e_receive && e_receive->get_mailbox() == issuer_mailbox;
+      });
+
+      if (send_position == receive_position) {
+        exC.insert(U->discover_event(std::move(K), wait_action));
+      }
+    }
+  } else if (const auto* e_issuer_recv = dynamic_cast<const CommRecvTransition*>(e_issuer->get_transition())) {
+    for (const auto e : C) {
+      // If the provider of the communication for `CommWait` is a
+      // `CommRecv(m)`, then we only care about `e` if `λ(e) == `CommSend(m)`.
+      // All other actions would be independent with the wait action (including
+      // another `CommRecv` to the same mailbox: `CommWait` is "waiting" for its
+      // corresponding send action)
+      if (e->get_transition()->type_ != Transition::Type::COMM_ASYNC_SEND) {
+        continue;
+      }
+
+      const auto issuer_mailbox        = e_issuer_recv->get_mailbox();
+      if (const auto* e_send = dynamic_cast<const CommSendTransition*>(e->get_transition());
+          e_send->get_mailbox() != issuer_mailbox) {
+        continue;
+      }
+
+      // If the `issuer` is not in `config(K)`, this implies that
+      // `WaitAny()` is always disabled in `config(K)`; hence, it
+      // is independent of any transition in `config(K)` (according
+      // to formal definition of independence)
+      auto K              = EventSet({e, pre_event_a_C.value_or(e)});
+      const auto config_K = History(K);
+      if (not config_K.contains(e_issuer)) {
+        continue;
+      }
+
+      // What receive # is the event `e`?
+      const unsigned send_position = std::count_if(config_K.begin(), config_K.end(), [=](const auto ev) {
+        const auto* e_send = dynamic_cast<const CommSendTransition*>(ev->get_transition());
+        return e_send && e_send->get_mailbox() == issuer_mailbox;
+      });
+
+      // What send # is the issuer
+      const unsigned receive_position =
+          std::count_if(e_issuer_history.begin(), e_issuer_history.end(), [=](const auto ev) {
+            const auto* e_receive = dynamic_cast<const CommRecvTransition*>(ev->get_transition());
+            return e_receive && e_receive->get_mailbox() == issuer_mailbox;
+          });
+
+      if (send_position == receive_position) {
+        exC.insert(U->discover_event(std::move(K), wait_action));
+      }
+    }
+  } else {
+    xbt_die("The transition which created the communication on which `%s` waits "
+            "is neither an async send nor an async receive. The current UDPOR "
+            "implementation does not know how to check if `CommWait` is enabled in "
+            "this case. Was a new transition added?",
+            e_issuer->get_transition()->to_string().c_str());
+  }
+
+  return exC;
+}
+
+EventSet ExtensionSetCalculator::partially_extend_CommTest(const Configuration& C, Unfolding* U,
+                                                           std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+
+  const auto test_action   = std::static_pointer_cast<CommTestTransition>(action);
+  const auto test_comm     = test_action->get_comm();
+  const auto test_aid      = test_action->aid_;
+  const auto pre_event_a_C = C.pre_event(test_action->aid_);
+
+  // Add the previous event as a dependency (if it's there)
+  if (pre_event_a_C.has_value()) {
+    const auto e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), test_action);
+    exC.insert(e_prime);
+  }
+
+  // Determine the _issuer_ of the communication of the `CommTest` event
+  // in `C`. The issuer of the `CommTest` in `C` is the event in `C`
+  // whose transition is the `CommRecv` or `CommSend` whose resulting
+  // communication this `CommTest` tests on
+  const auto issuer = std::find_if(C.begin(), C.end(), [=](const UnfoldingEvent* e) {
+    if (const auto* e_issuer_receive = dynamic_cast<const CommRecvTransition*>(e->get_transition())) {
+      return e_issuer_receive->aid_ == test_aid && test_comm == e_issuer_receive->get_comm();
+    }
+
+    if (const auto* e_issuer_send = dynamic_cast<const CommSendTransition*>(e->get_transition())) {
+      return e_issuer_send->aid_ == test_aid && test_comm == e_issuer_send->get_comm();
+    }
+
+    return false;
+  });
+  xbt_assert(issuer != C.end(),
+             "An enabled `CommTest` transition (%s) is testing a communication"
+             "%u not created by a receive/send "
+             "transition. SimGrid cannot currently handle test actions "
+             "under which a test is performed on a communication that was "
+             "not directly created by a receive/send operation of the same actor.",
+             test_action->to_string(false).c_str(), test_action->get_comm());
+  const UnfoldingEvent* e_issuer = *issuer;
+  const History e_issuer_history(e_issuer);
+
+  // 3. foreach event e in C do
+  if (const auto* e_issuer_send = dynamic_cast<const CommSendTransition*>(e_issuer->get_transition())) {
+    for (const auto e : C) {
+      // If the provider of the communication for `CommTest` is a
+      // `CommSend(m)`, then we only care about `e` if `λ(e) == `CommRecv(m)`.
+      // All other actions would be independent with the test action (including
+      // another `CommSend` to the same mailbox: `CommTest` is testing the
+      // corresponding receive action)
+      if (e->get_transition()->type_ != Transition::Type::COMM_ASYNC_RECV) {
+        continue;
+      }
+
+      const auto issuer_mailbox = e_issuer_send->get_mailbox();
+
+      if (const auto* e_recv = dynamic_cast<const CommRecvTransition*>(e->get_transition());
+          e_recv->get_mailbox() != issuer_mailbox) {
+        continue;
+      }
+
+      // If the `issuer` is not in `config(K)`, this implies that
+      // `CommTest()` is always disabled in `config(K)`; hence, it
+      // is independent of any transition in `config(K)` (according
+      // to formal definition of independence)
+      auto K              = EventSet({e, pre_event_a_C.value_or(e)});
+      const auto config_K = History(K);
+      if (not config_K.contains(e_issuer)) {
+        continue;
+      }
+
+      // What send # is the issuer
+      const unsigned send_position =
+          std::count_if(e_issuer_history.begin(), e_issuer_history.end(), [=](const auto ev) {
+            const auto* e_send = dynamic_cast<const CommSendTransition*>(ev->get_transition());
+            return e_send && e_send->get_mailbox() == issuer_mailbox;
+          });
+
+      // What receive # is the event `e`?
+      const unsigned receive_position = std::count_if(config_K.begin(), config_K.end(), [=](const auto ev) {
+        const auto* e_receive = dynamic_cast<const CommRecvTransition*>(ev->get_transition());
+        return e_receive && e_receive->get_mailbox() == issuer_mailbox;
+      });
+
+      if (send_position == receive_position) {
+        exC.insert(U->discover_event(std::move(K), test_action));
+      }
+    }
+  } else if (const auto* e_issuer_recv = dynamic_cast<const CommRecvTransition*>(e_issuer->get_transition())) {
+    for (const auto e : C) {
+      // If the provider of the communication for `CommTest` is a
+      // `CommRecv(m)`, then we only care about `e` if `λ(e) == `CommSend(m)`.
+      // All other actions would be independent with the wait action (including
+      // another `CommRecv` to the same mailbox: `CommWait` is "waiting" for its
+      // corresponding send action)
+      if (e->get_transition()->type_ != Transition::Type::COMM_ASYNC_SEND) {
+        continue;
+      }
+
+      const auto issuer_mailbox        = e_issuer_recv->get_mailbox();
+      if (const auto* e_send = dynamic_cast<const CommSendTransition*>(e->get_transition());
+          e_send->get_mailbox() != issuer_mailbox) {
+        continue;
+      }
+
+      // If the `issuer` is not in `config(K)`, this implies that
+      // `WaitAny()` is always disabled in `config(K)`; hence, it
+      // is independent of any transition in `config(K)` (according
+      // to formal definition of independence)
+      auto K              = EventSet({e, pre_event_a_C.value_or(e)});
+      const auto config_K = History(K);
+      if (not config_K.contains(e_issuer)) {
+        continue;
+      }
+
+      // What receive # is the event `e`?
+      const unsigned send_position = std::count_if(config_K.begin(), config_K.end(), [=](const auto ev) {
+        const auto* e_send = dynamic_cast<const CommSendTransition*>(ev->get_transition());
+        return e_send && e_send->get_mailbox() == issuer_mailbox;
+      });
+
+      // What send # is the issuer
+      const unsigned receive_position =
+          std::count_if(e_issuer_history.begin(), e_issuer_history.end(), [=](const auto ev) {
+            const auto* e_receive = dynamic_cast<const CommRecvTransition*>(ev->get_transition());
+            return e_receive && e_receive->get_mailbox() == issuer_mailbox;
+          });
+
+      if (send_position == receive_position) {
+        exC.insert(U->discover_event(std::move(K), test_action));
+      }
+    }
+  } else {
+    xbt_die("The transition which created the communication on which `%s` waits "
+            "is neither an async send nor an async receive. The current UDPOR "
+            "implementation does not know how to check if `CommWait` is enabled in "
+            "this case. Was a new transition added?",
+            e_issuer->get_transition()->to_string().c_str());
+  }
+  return exC;
+}
+
+EventSet ExtensionSetCalculator::partially_extend_MutexAsyncLock(const Configuration& C, Unfolding* U,
+                                                                 std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+  const auto mutex_lock    = std::static_pointer_cast<MutexTransition>(action);
+  const auto pre_event_a_C = C.pre_event(mutex_lock->aid_);
+
+  // for each event e in C
+  // 1. If lambda(e) := pre(a) -> add it. Note that if
+  // pre_event_a_C.has_value() == false, this implies `C` is
+  // empty or which we treat as implicitly containing the bottom event
+  if (pre_event_a_C.has_value()) {
+    const auto e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), mutex_lock);
+    exC.insert(e_prime);
+  } else {
+    const auto e_prime = U->discover_event(EventSet(), mutex_lock);
+    exC.insert(e_prime);
+  }
+
+  // for each event e in C
+  for (const auto e : C) {
+    // Check for other locks on the same mutex
+    if (const auto* e_mutex = dynamic_cast<const MutexTransition*>(e->get_transition());
+        e_mutex->type_ == Transition::Type::MUTEX_ASYNC_LOCK && mutex_lock->get_mutex() == e_mutex->get_mutex()) {
+      auto K = EventSet({e, pre_event_a_C.value_or(e)});
+      exC.insert(U->discover_event(std::move(K), mutex_lock));
+    }
+  }
+  return exC;
+}
+
+EventSet ExtensionSetCalculator::partially_extend_MutexUnlock(const Configuration& C, Unfolding* U,
+                                                              std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+  const auto mutex_unlock  = std::static_pointer_cast<MutexTransition>(action);
+  const auto pre_event_a_C = C.pre_event(mutex_unlock->aid_);
+
+  // for each event e in C
+  // 1. If lambda(e) := pre(a) -> add it. Note that if
+  // pre_event_a_C.has_value() == false, this implies `C` is
+  // empty or which we treat as implicitly containing the bottom event
+  if (pre_event_a_C.has_value()) {
+    const auto e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), mutex_unlock);
+    exC.insert(e_prime);
+  } else {
+    const auto e_prime = U->discover_event(EventSet(), mutex_unlock);
+    exC.insert(e_prime);
+  }
+
+  // for each event e in C
+  for (const auto e : C) {
+    // Check for MutexTest
+    if (const auto* e_mutex = dynamic_cast<const MutexTransition*>(e->get_transition());
+        e_mutex->type_ == Transition::Type::MUTEX_TEST || e_mutex->type_ == Transition::Type::MUTEX_WAIT) {
+      // TODO: Check if dependent or not
+      // This entails getting information about
+      // the relative position of the mutex in the queue, which
+      // again means we need more context...
+      auto K = EventSet({e, pre_event_a_C.value_or(e)});
+      exC.insert(U->discover_event(std::move(K), mutex_unlock));
+    }
+  }
+  return exC;
+}
+
+EventSet ExtensionSetCalculator::partially_extend_MutexWait(const Configuration& C, Unfolding* U,
+                                                            std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+  const auto mutex_wait    = std::static_pointer_cast<MutexTransition>(action);
+  const auto pre_event_a_C = C.pre_event(mutex_wait->aid_);
+
+  // for each event e in C
+  // 1. If lambda(e) := pre(a) -> add it. In the case of MutexWait, we also check that the
+  // actor which is executing the MutexWait is the owner of the mutex
+  if (pre_event_a_C.has_value() && mutex_wait->get_owner() == mutex_wait->aid_) {
+    const auto e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), mutex_wait);
+    exC.insert(e_prime);
+  } else {
+    const auto e_prime = U->discover_event(EventSet(), mutex_wait);
+    exC.insert(e_prime);
+  }
+
+  // for each event e in C
+  for (const auto e : C) {
+    // Check for any unlocks
+    if (const auto* e_mutex = dynamic_cast<const MutexTransition*>(e->get_transition());
+        e_mutex != nullptr && e_mutex->type_ == Transition::Type::MUTEX_UNLOCK) {
+      // TODO: Check if dependent or not
+      // This entails getting information about
+      // the relative position of the mutex in the queue, which
+      // again means we need more context...
+      auto K = EventSet({e, pre_event_a_C.value_or(e)});
+      exC.insert(U->discover_event(std::move(K), mutex_wait));
+    }
+  }
+  return exC;
+}
+
+EventSet ExtensionSetCalculator::partially_extend_MutexTest(const Configuration& C, Unfolding* U,
+                                                            std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+  const auto mutex_test    = std::static_pointer_cast<MutexTransition>(action);
+  const auto pre_event_a_C = C.pre_event(mutex_test->aid_);
+
+  // for each event e in C
+  // 1. If lambda(e) := pre(a) -> add it. Note that if
+  // pre_event_a_C.has_value() == false, this implies `C` is
+  // empty or which we treat as implicitly containing the bottom event
+  if (pre_event_a_C.has_value()) {
+    const auto e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), mutex_test);
+    exC.insert(e_prime);
+  } else {
+    const auto e_prime = U->discover_event(EventSet(), mutex_test);
+    exC.insert(e_prime);
+  }
+
+  // for each event e in C
+  for (const auto e : C) {
+    // Check for any unlocks
+    if (const auto* e_mutex = dynamic_cast<const MutexTransition*>(e->get_transition());
+        e_mutex != nullptr && e_mutex->type_ == Transition::Type::MUTEX_UNLOCK) {
+      // TODO: Check if dependent or not
+      // This entails getting information about
+      // the relative position of the mutex in the queue, which
+      // again means we need more context...
+      auto K = EventSet({e, pre_event_a_C.value_or(e)});
+      exC.insert(U->discover_event(std::move(K), mutex_test));
+    }
+  }
+  return exC;
+}
+
+EventSet ExtensionSetCalculator::partially_extend_ActorJoin(const Configuration& C, Unfolding* U,
+                                                            std::shared_ptr<Transition> action)
+{
+  EventSet exC;
+
+  const auto join_action = std::static_pointer_cast<ActorJoinTransition>(action);
+
+  // Handling ActorJoin is very simple: it is independent with all
+  // other transitions. Thus the only event it could possibly depend
+  // on is pre(a, C) or the root
+  if (const auto pre_event_a_C = C.pre_event(join_action->aid_); pre_event_a_C.has_value()) {
+    const auto e_prime = U->discover_event(EventSet({pre_event_a_C.value()}), join_action);
+    exC.insert(e_prime);
+  } else {
+    const auto e_prime = U->discover_event(EventSet(), join_action);
+    exC.insert(e_prime);
+  }
+
+  return exC;
+}
+
+} // namespace simgrid::mc::udpor
diff --git a/src/mc/explo/udpor/ExtensionSetCalculator.hpp b/src/mc/explo/udpor/ExtensionSetCalculator.hpp
new file mode 100644 (file)
index 0000000..cd68c9c
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_UDPOR_EVENTSETCALCULATOR_HPP
+#define SIMGRID_MC_UDPOR_EVENTSETCALCULATOR_HPP
+
+#include "src/mc/explo/udpor/EventSet.hpp"
+#include "src/mc/explo/udpor/udpor_forward.hpp"
+#include "src/mc/transition/Transition.hpp"
+#include "src/mc/transition/TransitionActor.hpp"
+#include "src/mc/transition/TransitionAny.hpp"
+#include "src/mc/transition/TransitionComm.hpp"
+#include "src/mc/transition/TransitionObjectAccess.hpp"
+#include "src/mc/transition/TransitionRandom.hpp"
+#include "src/mc/transition/TransitionSynchro.hpp"
+
+#include <memory>
+
+namespace simgrid::mc::udpor {
+
+/**
+ * @brief Computes incrementally the portion of the extension set for a new configuration `C`
+ */
+struct ExtensionSetCalculator final {
+private:
+  static EventSet partially_extend_CommSend(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+  static EventSet partially_extend_CommRecv(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+  static EventSet partially_extend_CommWait(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+  static EventSet partially_extend_CommTest(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+
+  static EventSet partially_extend_MutexAsyncLock(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+  static EventSet partially_extend_MutexWait(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+  static EventSet partially_extend_MutexTest(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+  static EventSet partially_extend_MutexUnlock(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+
+  static EventSet partially_extend_ActorJoin(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+
+public:
+  static EventSet partially_extend(const Configuration&, Unfolding*, std::shared_ptr<Transition>);
+};
+
+} // namespace simgrid::mc::udpor
+#endif
diff --git a/src/mc/explo/udpor/ExtensionSet_test.cpp b/src/mc/explo/udpor/ExtensionSet_test.cpp
new file mode 100644 (file)
index 0000000..a3953ba
--- /dev/null
@@ -0,0 +1,295 @@
+/* Copyright (c) 2017-2023. The SimGrid Team. All rights reserved.               */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/3rd-party/catch.hpp"
+#include "src/mc/explo/udpor/Configuration.hpp"
+#include "src/mc/explo/udpor/ExtensionSetCalculator.hpp"
+#include "src/mc/explo/udpor/History.hpp"
+#include "src/mc/explo/udpor/Unfolding.hpp"
+
+using namespace simgrid::mc;
+using namespace simgrid::mc::udpor;
+
+TEST_CASE("simgrid::mc::udpor: Testing Computation with AsyncSend/AsyncReceive Only")
+{
+  // This test checks that the unfolding constructed for the very
+  // simple program described below is extended correctly. Each
+  // step of UDPOR is observed to ensure that computations are carried
+  // out correctly. The program described is simply:
+  //
+  //      1                 2
+  // AsyncSend(m)      AsyncRecv(m)
+  //
+  // The unfolding of the simple program is as follows:
+  //
+  //                         ⊥
+  //                  /            /
+  //       (a) 1: AsyncSend(m)  (b) 2: AsyncRecv(m)
+
+  const int times_considered = 0;
+  const int tag              = 0;
+  const unsigned mbox        = 0;
+  const uintptr_t comm       = 0;
+
+  Unfolding U;
+
+  SECTION("Computing ex({⊥}) with 1: AsyncSend")
+  {
+    // Consider the extension with `1: AsyncSend(m)`
+    Configuration C;
+    aid_t issuer = 1;
+
+    const auto async_send      = std::make_shared<CommSendTransition>(issuer, times_considered, comm, mbox, tag);
+    const auto incremental_exC = ExtensionSetCalculator::partially_extend(C, &U, async_send);
+
+    // Check that the events have been added to `U`
+    REQUIRE(U.size() == 1);
+
+    // Make assertions about the contents of ex(C)
+    UnfoldingEvent e(EventSet(), async_send);
+    REQUIRE(incremental_exC.contains_equivalent_to(&e));
+  }
+
+  SECTION("Computing ex({⊥}) with 2: AsyncRecv")
+  {
+    // Consider the extension with `2: AsyncRecv(m)`
+    Configuration C;
+    aid_t issuer = 2;
+
+    const auto async_recv      = std::make_shared<CommRecvTransition>(issuer, times_considered, comm, mbox, tag);
+    const auto incremental_exC = ExtensionSetCalculator::partially_extend(C, &U, async_recv);
+
+    // Check that the events have been added to `U`
+    REQUIRE(U.size() == 1);
+
+    // Make assertions about the contents of ex(C)
+    UnfoldingEvent e(EventSet(), async_recv);
+    REQUIRE(incremental_exC.contains_equivalent_to(&e));
+  }
+
+  SECTION("Computing ex({⊥}) fully")
+  {
+    // Consider the extension with `1: AsyncSend(m)`
+    Configuration C;
+
+    const auto async_send           = std::make_shared<CommSendTransition>(1, times_considered, comm, mbox, tag);
+    const auto incremental_exC_send = ExtensionSetCalculator::partially_extend(C, &U, async_send);
+
+    // Check that the events have been added to `U`
+    REQUIRE(U.size() == 1);
+
+    // Make assertions about the contents of ex(C)
+    UnfoldingEvent e_send(EventSet(), async_send);
+    REQUIRE(incremental_exC_send.contains_equivalent_to(&e_send));
+
+    // Consider the extension with `2: AsyncRecv(m)`
+    const auto async_recv           = std::make_shared<CommRecvTransition>(2, times_considered, comm, mbox, tag);
+    const auto incremental_exC_recv = ExtensionSetCalculator::partially_extend(C, &U, async_recv);
+
+    // Check that the events have been added to `U`
+    REQUIRE(U.size() == 2);
+
+    // Make assertions about the contents of ex(C)
+    UnfoldingEvent e_recv(EventSet(), async_recv);
+    REQUIRE(incremental_exC_recv.contains_equivalent_to(&e_recv));
+  }
+
+  SECTION("Computing the full sequence of extensions")
+  {
+    Configuration C;
+
+    // Consider the extension with `1: AsyncSend(m)`
+    const auto async_send           = std::make_shared<CommSendTransition>(1, times_considered, comm, mbox, tag);
+    const auto incremental_exC_send = ExtensionSetCalculator::partially_extend(C, &U, async_send);
+
+    // Check that event `a` has been added to `U`
+    REQUIRE(U.size() == 1);
+    UnfoldingEvent e_send(EventSet(), async_send);
+    REQUIRE(incremental_exC_send.contains_equivalent_to(&e_send));
+
+    // Consider the extension with `2: AsyncRecv(m)`
+    const auto async_recv           = std::make_shared<CommRecvTransition>(2, times_considered, comm, mbox, tag);
+    const auto incremental_exC_recv = ExtensionSetCalculator::partially_extend(C, &U, async_recv);
+
+    // Check that event `b` has been added to `U`
+    REQUIRE(U.size() == 2);
+    UnfoldingEvent e_recv(EventSet(), async_recv);
+    REQUIRE(incremental_exC_recv.contains_equivalent_to(&e_recv));
+
+    // At this point, UDPOR will pick one of the two events equivalent to
+    // `e_recv` and e`_send`
+
+    // Suppose it picks the event labeled `a` in the graph above first
+    // (ultimately, UDPOR will choose to search both directions since
+    // {⊥, b} will be an alternative to {⊥, a})
+
+    const auto* e_a = *incremental_exC_send.begin();
+    const auto* e_b = *incremental_exC_recv.begin();
+
+    SECTION("Pick `a` first (ex({⊥, a}))")
+    {
+      // After picking `a`, we need only consider the extensions
+      // possible with `2: AsyncRecv(m)` since actor 1 no longer
+      // has any actions to run
+      Configuration C_with_send{e_a};
+      const auto incremental_exC_with_send = ExtensionSetCalculator::partially_extend(C_with_send, &U, async_recv);
+
+      // Check that event `b` has not been duplicated
+      REQUIRE(U.size() == 2);
+
+      // Indeed, in this case we assert that the SAME identity has been
+      // supplied by the unfolding (it should note that `ex({⊥, a})`
+      // and `ex({⊥})` have an overlapping event `b`)
+      REQUIRE(incremental_exC_with_send.contains(e_b));
+    }
+
+    SECTION("Pick `b` first (ex({⊥, b}))")
+    {
+      // After picking `b`, we need only consider the extensions
+      // possible with `1: AsyncSend(m)` since actor 2 no longer
+      // has any actions to run
+      Configuration C_with_recv{e_b};
+      const auto incremental_exC_with_recv = ExtensionSetCalculator::partially_extend(C_with_recv, &U, async_send);
+
+      // Check that event `a` has not been duplicated
+      REQUIRE(U.size() == 2);
+
+      // Indeed, in this case we assert that the SAME identity has been
+      // supplied by the unfolding (it should note that `ex({⊥, b})`
+      // and `ex({⊥})` have an overlapping event `a`)
+      REQUIRE(incremental_exC_with_recv.contains(e_a));
+    }
+  }
+}
+
+TEST_CASE("simgrid::mc::udpor: Testing Waits, Receives, and Sends")
+{
+  // We're going to follow UDPOR down one path of computation
+  // in a relatively simple program (although the unfolding quickly
+  // becomes quite complex)
+  //
+  //      1                 2
+  // AsyncSend(m)      AsyncRecv(m)
+  // Wait(m)           Wait(m)
+  //
+  // The unfolding of the simple program is as follows:
+  //                         ⊥
+  //                  /            /
+  //       (a) 1: AsyncSend(m)  (b) 2: AsyncRecv(m)
+  //                |   \        /        |
+  //                |      \  /          |
+  //               |      /   \          |
+  //               |    /      \         |
+  //       (c) 1: Wait(m)       (d) 2: Wait(m)
+  const int times_considered = 0;
+  const int tag              = 0;
+  const unsigned mbox        = 0;
+  const uintptr_t comm       = 0x800;
+  const bool timeout         = false;
+
+  Unfolding U;
+  const auto comm_send   = std::make_shared<CommSendTransition>(1, times_considered, comm, mbox, tag);
+  const auto comm_recv   = std::make_shared<CommRecvTransition>(2, times_considered, comm, mbox, tag);
+  const auto comm_wait_1 = std::make_shared<CommWaitTransition>(1, times_considered, timeout, comm, 1, 2, mbox);
+  const auto comm_wait_2 = std::make_shared<CommWaitTransition>(2, times_considered, timeout, comm, 1, 2, mbox);
+
+  // 1. UDPOR will attempt to expand first ex({⊥})
+
+  // --- ex({⊥}) ---
+  const auto incremental_exC_send = ExtensionSetCalculator::partially_extend(Configuration(), &U, comm_send);
+  // Assert that event `a` has been added
+  UnfoldingEvent e_send(EventSet(), comm_send);
+  REQUIRE(incremental_exC_send.size() == 1);
+  REQUIRE(incremental_exC_send.contains_equivalent_to(&e_send));
+  REQUIRE(U.size() == 1);
+
+  const auto incremental_exC_recv = ExtensionSetCalculator::partially_extend(Configuration(), &U, comm_recv);
+  // Assert that event `b` has been added
+  UnfoldingEvent e_recv(EventSet(), comm_recv);
+  REQUIRE(incremental_exC_recv.size() == 1);
+  REQUIRE(incremental_exC_recv.contains_equivalent_to(&e_recv));
+  REQUIRE(U.size() == 2);
+  // --- ex({⊥}) ---
+
+  // 2. UDPOR will then attempt to expand ex({⊥, a}) or ex({⊥, b}). Both have
+  // parallel effects and should simply return events already added to ex(C)
+  //
+  // NOTE: Note that only once actor is enabled in both cases, meaning that
+  // we need only consider one incremental expansion for each
+
+  const auto* e_a = *incremental_exC_send.begin();
+  const auto* e_b = *incremental_exC_recv.begin();
+
+  // --- ex({⊥, a}) ---
+  const auto incremental_exC_recv2 = ExtensionSetCalculator::partially_extend(Configuration({e_a}), &U, comm_recv);
+  // Assert that no event has been added and that
+  // e_b is contained in the extension set
+  REQUIRE(incremental_exC_recv2.size() == 1);
+  REQUIRE(incremental_exC_recv2.contains(e_b));
+
+  // Here, `e_a` shouldn't be added again
+  REQUIRE(U.size() == 2);
+  // --- ex({⊥, a}) ---
+
+  // --- ex({⊥, b}) ---
+  const auto incremental_exC_send2 = ExtensionSetCalculator::partially_extend(Configuration({e_b}), &U, comm_send);
+  // Assert that no event has been added and that
+  // e_a is contained in the extension set
+  REQUIRE(incremental_exC_send2.size() == 1);
+  REQUIRE(incremental_exC_send2.contains(e_a));
+
+  // Here, `e_b` shouldn't be added again
+  REQUIRE(U.size() == 2);
+  // --- ex({⊥, b}) ---
+
+  // 3. Expanding from ex({⊥, a, b}) brings in both `CommWait` events since they
+  // become enabled as soon as the communication has been paired
+
+  // --- ex({⊥, a, b}) ---
+  const auto incremental_exC_wait_actor_1 =
+      ExtensionSetCalculator::partially_extend(Configuration({e_a, e_b}), &U, comm_wait_1);
+  // Assert that events `c` has been added
+  UnfoldingEvent e_wait_1(EventSet({e_a, e_b}), comm_wait_1);
+  REQUIRE(incremental_exC_wait_actor_1.size() == 1);
+  REQUIRE(incremental_exC_wait_actor_1.contains_equivalent_to(&e_wait_1));
+  REQUIRE(U.size() == 3);
+
+  const auto incremental_exC_wait_actor_2 =
+      ExtensionSetCalculator::partially_extend(Configuration({e_a, e_b}), &U, comm_wait_2);
+  // Assert that events `d` has been added
+  UnfoldingEvent e_wait_2(EventSet({e_a, e_b}), comm_wait_2);
+  REQUIRE(incremental_exC_wait_actor_2.size() == 1);
+  REQUIRE(incremental_exC_wait_actor_2.contains_equivalent_to(&e_wait_2));
+  REQUIRE(U.size() == 4);
+  // --- ex({⊥, a, b}) ---
+
+  // 4. Expanding from either wait action should simply yield the other event
+  // with a wait action associated with it.
+  // This is analogous to the scenario before with send and receive
+  // ex({⊥, a, b, c}) or ex({⊥, a, b, d})
+
+  const auto* e_c = *incremental_exC_wait_actor_1.begin();
+  const auto* e_d = *incremental_exC_wait_actor_2.begin();
+
+  // --- ex({⊥, a, b, d}) ---
+  const auto incremental_exC_wait_actor_1_2 =
+      ExtensionSetCalculator::partially_extend(Configuration({e_a, e_b, e_d}), &U, comm_wait_1);
+  // Assert that no event has been added and that
+  // `e_c` is contained in the extension set
+  REQUIRE(incremental_exC_wait_actor_1_2.size() == 1);
+  REQUIRE(incremental_exC_wait_actor_1_2.contains(e_c));
+  REQUIRE(U.size() == 4);
+  // --- ex({⊥, a, b, d}) ---
+
+  // --- ex({⊥, a, b, c}) ---
+  const auto incremental_exC_wait_actor_2_2 =
+      ExtensionSetCalculator::partially_extend(Configuration({e_a, e_b, e_c}), &U, comm_wait_2);
+  // Assert that no event has been added and that
+  // `e_d` is contained in the extension set
+  REQUIRE(incremental_exC_wait_actor_2_2.size() == 1);
+  REQUIRE(incremental_exC_wait_actor_2_2.contains(e_d));
+  REQUIRE(U.size() == 4);
+  // --- ex({⊥, a, b, c}) ---
+}
index da35244..dc17c27 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <boost/iterator/iterator_facade.hpp>
 #include <functional>
+#include <initializer_list>
 #include <optional>
 
 namespace simgrid::mc::udpor {
@@ -54,8 +55,9 @@ public:
   History& operator=(History const&) = default;
   History(History&&)                 = default;
 
-  explicit History(EventSet event_set = EventSet()) : events_(std::move(event_set)) {}
   explicit History(const UnfoldingEvent* e) : events_({e}) {}
+  explicit History(EventSet event_set = EventSet()) : events_(std::move(event_set)) {}
+  explicit History(std::initializer_list<const UnfoldingEvent*> list) : events_(std::move(list)) {}
 
   auto begin() const { return Iterator(events_); }
   auto end() const { return Iterator(EventSet()); }
@@ -94,6 +96,17 @@ public:
    */
   EventSet get_all_maximal_events() const;
 
+  /**
+   * @brief Computes the set of events that are not contained
+   * in the given configuration
+   *
+   * A configuration is a causally-closed, conflict-free set
+   * of events. Thus, you can determine which events lie outside
+   * of a configuration during the search more efficiently: the moment
+   * you discover an event contained in the configuration, you
+   * do not need to search that event or any of its ancestors as
+   * they will all be contained in the configuration
+   */
   EventSet get_event_diff_with(const Configuration& config) const;
 
 private:
index 1b63328..587d4e9 100644 (file)
@@ -9,23 +9,23 @@
 
 namespace simgrid::mc::udpor {
 
-void Unfolding::remove(const EventSet& events)
+void Unfolding::mark_finished(const EventSet& events)
 {
-  for (const auto e : events) {
-    remove(e);
+  for (const auto* e : events) {
+    mark_finished(e);
   }
 }
 
-void Unfolding::remove(const UnfoldingEvent* e)
+void Unfolding::mark_finished(const UnfoldingEvent* e)
 {
   if (e == nullptr) {
     throw std::invalid_argument("Expected a non-null pointer to an event, but received NULL");
   }
-  this->global_events_.erase(e);
-  this->event_handles.remove(e);
+  this->U.remove(e);
+  this->G.insert(e);
 }
 
-void Unfolding::insert(std::unique_ptr<UnfoldingEvent> e)
+const UnfoldingEvent* Unfolding::insert(std::unique_ptr<UnfoldingEvent> e)
 {
   const UnfoldingEvent* handle = e.get();
   if (auto loc = this->global_events_.find(handle); loc != this->global_events_.end()) {
@@ -36,29 +36,39 @@ void Unfolding::insert(std::unique_ptr<UnfoldingEvent> e)
                                 "This will result in a  double free error and must be fixed.");
   }
 
-  // Map the handle to its owner
-  this->event_handles.insert(handle);
-  this->global_events_[handle] = std::move(e);
-}
+  // Attempt to search first for an event in `U`. If it exists, we use that event
+  // instead of `e` since it is semantically equivalent to `e` (i.e. `e` is
+  // effectively already contained in the unfolding)
+  if (auto loc = std::find_if(U.begin(), U.end(), [=](const auto e_i) { return *e_i == *handle; }); loc != U.end()) {
+    // Return the handle to that event and ignore adding in a duplicate event
+    return *loc;
+  }
 
-bool Unfolding::contains_event_equivalent_to(const UnfoldingEvent* e) const
-{
-  // Notice the use of `==` equality here. `e` may not be contained in the
-  // unfolding; but some event which is "equivalent" to it could be.
-  for (const auto event : *this) {
-    if (*event == *e) {
-      return true;
-    }
+  // Then look for `e` in `G`. It's possible `e` was already constructed
+  // in the past, in which case we can simply re-use it.
+  //
+  // Note, though, that in this case we must move the event in `G` into
+  // `U`: we've inserted `e` into the unfolding, so we expect it to be in `U`
+  if (auto loc = std::find_if(G.begin(), G.end(), [=](const auto e_i) { return *e_i == *handle; }); loc != G.end()) {
+    const auto* e_equiv = *loc;
+    G.remove(e_equiv);
+    U.insert(e_equiv);
+    return e_equiv;
   }
-  return false;
+
+  // Otherwise `e` is truly a "new" event
+  this->U.insert(handle);
+  this->event_handles.insert(handle);
+  this->global_events_[handle] = std::move(e);
+  return handle;
 }
 
 EventSet Unfolding::get_immediate_conflicts_of(const UnfoldingEvent* e) const
 {
   EventSet immediate_conflicts;
-  for (const auto event : *this) {
+  for (const auto* event : U) {
     if (event->immediately_conflicts_with(e)) {
-      immediate_conflicts.insert(e);
+      immediate_conflicts.insert(event);
     }
   }
   return immediate_conflicts;
index 0107692..3fa80f2 100644 (file)
 namespace simgrid::mc::udpor {
 
 class Unfolding {
+public:
+  Unfolding()                       = default;
+  Unfolding& operator=(Unfolding&&) = default;
+  Unfolding(Unfolding&&)            = default;
+
+  auto begin() const { return this->event_handles.begin(); }
+  auto end() const { return this->event_handles.end(); }
+  auto cbegin() const { return this->event_handles.cbegin(); }
+  auto cend() const { return this->event_handles.cend(); }
+  size_t size() const { return this->event_handles.size(); }
+  bool empty() const { return this->event_handles.empty(); }
+
+  /**
+   * @brief Moves an event from UDPOR's global set `U` to
+   * the global set `G`
+   */
+  void mark_finished(const UnfoldingEvent* e);
+
+  /**
+   * @brief Moves all events in a set from UDPOR's global
+   * set `U` to the global set `G`
+   */
+  void mark_finished(const EventSet& events);
+
+  /// @brief Adds a new event `e` to the Unfolding if that
+  /// event is not equivalent to any of those already contained
+  /// in the unfolding
+  const UnfoldingEvent* insert(std::unique_ptr<UnfoldingEvent> e);
+
+  /**
+   * @brief Informs the unfolding of a (potentially) new event
+   *
+   * The unfolding of a concurrent program is a well-defined
+   * structure. Given the labeled transition system (LTS) of
+   * a program, the unfolding of that program can be determined
+   * algorithmically. However, UDPOR does not a priori know the structure of the
+   * unfolding as it performs its exploration. Thus, events in the
+   * unfolding are "discovered" as they are encountered, specifically
+   * when computing the extension sets of the configurations that
+   * UDPOR decides to search.
+   *
+   * This lends itself to the following problem: the extension sets
+   * of two different configurations may overlap one another. That
+   * is, for two configurations C and C' explored by UDPOR where C != C',
+   *
+   * ex(C) - ex(C') != empty
+   *
+   * Hence, when extending both `C` and `C'`, any events contained in
+   * the intersection of ex(C) and ex(C') will be attempted to be added
+   * twice. The unfolding will notice that these events have already
+   * been added and simply return the event already added to the unfolding
+   *
+   * @tparam ...Args arguments passed to the `UnfoldingEvent` constructor
+   * @return the handle to either the newly created event OR
+   * to an equivalent event that was already noted by the unfolding
+   * at some point in the past
+   */
+  template <typename... Args> const UnfoldingEvent* discover_event(Args&&... args)
+  {
+    auto candidate_event = std::make_unique<UnfoldingEvent>(std::forward<Args>(args)...);
+    return insert(std::move(candidate_event));
+  }
+
+  /// @brief Computes "#ⁱ_U(e)" for the given event, where `U` is the set
+  /// of the events in this unfolding
+  EventSet get_immediate_conflicts_of(const UnfoldingEvent*) const;
+
 private:
   /**
    * @brief All of the events that are currently are a part of the unfolding
    *
    * @invariant Each unfolding event maps itself to the owner of that event,
-   * i.e. the unique pointer that owns the address. The Unfolding owns all
+   * i.e. the unique pointer that manages the data at the address. The Unfolding owns all
    * of the addresses that are referenced by EventSet instances and Configuration
    * instances. UDPOR guarantees that events are persisted for as long as necessary
    */
@@ -32,40 +99,24 @@ private:
    *
    * @invariant: All of the events in this set are elements of `global_events_`
    * and is kept updated at the same time as `global_events_`
+   *
+   * @note: This is for the convenience of iteration over the unfolding
    */
   EventSet event_handles;
 
+  /**
+   * @brief: The collection of events in the unfolding that are "important"
+   */
+  EventSet U;
+
   /**
    * @brief The "irrelevant" portions of the unfolding that do not need to be kept
    * around to ensure that UDPOR functions correctly
    *
    * The set `G` is another global variable maintained by the UDPOR algorithm which
    * is used to keep track of all events which used to be important to UDPOR.
-   *
-   * @note: The current implementation does not touch the set `G`. Its use is perhaps
-   * limited to debugging and/or model-checking acyclic state spaces
    */
   EventSet G;
-
-public:
-  Unfolding()                       = default;
-  Unfolding& operator=(Unfolding&&) = default;
-  Unfolding(Unfolding&&)            = default;
-
-  void remove(const UnfoldingEvent* e);
-  void remove(const EventSet& events);
-  void insert(std::unique_ptr<UnfoldingEvent> e);
-  bool contains_event_equivalent_to(const UnfoldingEvent* e) const;
-
-  auto begin() const { return this->event_handles.begin(); }
-  auto end() const { return this->event_handles.end(); }
-  auto cbegin() const { return this->event_handles.cbegin(); }
-  auto cend() const { return this->event_handles.cend(); }
-  size_t size() const { return this->global_events_.size(); }
-  bool empty() const { return this->global_events_.empty(); }
-
-  /// @brief Computes "#ⁱ_U(e)" for the given event
-  EventSet get_immediate_conflicts_of(const UnfoldingEvent*) const;
 };
 
 } // namespace simgrid::mc::udpor
index c51023b..8651a2a 100644 (file)
@@ -6,6 +6,10 @@
 #include "src/mc/explo/udpor/UnfoldingEvent.hpp"
 #include "src/mc/explo/udpor/History.hpp"
 
+#include <xbt/asserts.h>
+#include <xbt/log.h>
+#include <xbt/string.hpp>
+
 namespace simgrid::mc::udpor {
 
 UnfoldingEvent::UnfoldingEvent(std::initializer_list<const UnfoldingEvent*> init_list)
@@ -16,10 +20,16 @@ UnfoldingEvent::UnfoldingEvent(std::initializer_list<const UnfoldingEvent*> init
 UnfoldingEvent::UnfoldingEvent(EventSet immediate_causes, std::shared_ptr<Transition> transition)
     : associated_transition(std::move(transition)), immediate_causes(std::move(immediate_causes))
 {
+  static uint64_t event_id = 0;
+  this->id                 = ++event_id;
 }
 
 bool UnfoldingEvent::operator==(const UnfoldingEvent& other) const
 {
+  // Intrinsic identity check
+  if (this == &other) {
+    return true;
+  }
   // Two events are equivalent iff:
   // 1. they have the same action
   // 2. they have the same history
@@ -36,14 +46,38 @@ bool UnfoldingEvent::operator==(const UnfoldingEvent& other) const
          this->immediate_causes == other.immediate_causes;
 }
 
+std::string UnfoldingEvent::to_string() const
+{
+  std::string dependencies_string;
+
+  dependencies_string += "[";
+  for (const auto* e : immediate_causes) {
+    dependencies_string += " ";
+    dependencies_string += e->to_string();
+    dependencies_string += " and ";
+  }
+  dependencies_string += "]";
+
+  return xbt::string_printf("Event %lu, Actor %ld: %s (%lu dependencies: %s)", this->id, associated_transition->aid_,
+                            associated_transition->to_string().c_str(), immediate_causes.size(),
+                            dependencies_string.c_str());
+}
+
 EventSet UnfoldingEvent::get_history() const
+{
+  EventSet local_config = get_local_config();
+  local_config.remove(this);
+  return local_config;
+}
+
+EventSet UnfoldingEvent::get_local_config() const
 {
   return History(this).get_all_events();
 }
 
 bool UnfoldingEvent::related_to(const UnfoldingEvent* other) const
 {
-  return this->in_history_of(other) or other->in_history_of(this);
+  return this->in_history_of(other) || other->in_history_of(this);
 }
 
 bool UnfoldingEvent::in_history_of(const UnfoldingEvent* other) const
@@ -60,8 +94,8 @@ bool UnfoldingEvent::conflicts_with(const UnfoldingEvent* other) const
     return false;
   }
 
-  const EventSet my_history      = get_history();
-  const EventSet other_history   = other->get_history();
+  const EventSet my_history      = get_local_config();
+  const EventSet other_history   = other->get_local_config();
   const EventSet unique_to_me    = my_history.subtracting(other_history);
   const EventSet unique_to_other = other_history.subtracting(my_history);
 
@@ -69,19 +103,12 @@ bool UnfoldingEvent::conflicts_with(const UnfoldingEvent* other) const
                                                 [&](const UnfoldingEvent* e) { return e->is_dependent_with(other); });
   const bool conflicts_with_other = std::any_of(unique_to_other.begin(), unique_to_other.end(),
                                                 [&](const UnfoldingEvent* e) { return e->is_dependent_with(this); });
-  return conflicts_with_me or conflicts_with_other;
+  return conflicts_with_me || conflicts_with_other;
 }
 
-bool UnfoldingEvent::conflicts_with(const Configuration& config) const
+bool UnfoldingEvent::conflicts_with_any(const EventSet& events) const
 {
-  // A configuration is itself already conflict-free. Thus, it is
-  // simply a matter of testing whether or not the transition associated
-  // with the event is dependent with any already in `config` that are
-  // OUTSIDE this event's history (in an unfolding, events only conflict
-  // if they are not related)
-  const EventSet potential_conflicts = config.get_events().subtracting(get_history());
-  return std::any_of(potential_conflicts.cbegin(), potential_conflicts.cend(),
-                     [&](const UnfoldingEvent* e) { return this->is_dependent_with(e); });
+  return std::any_of(events.begin(), events.end(), [&](const auto e) { return e->conflicts_with(this); });
 }
 
 bool UnfoldingEvent::immediately_conflicts_with(const UnfoldingEvent* other) const
@@ -94,21 +121,15 @@ bool UnfoldingEvent::immediately_conflicts_with(const UnfoldingEvent* other) con
   auto combined_events = History(EventSet{this, other}).get_all_events();
 
   // See the definition of immediate conflicts in the original paper on UDPOR
-  {
-    combined_events.remove(this);
-    if (not combined_events.is_valid_configuration()) {
-      return false;
-    }
-    combined_events.insert(this);
-  }
+  combined_events.remove(this);
+  if (not combined_events.is_valid_configuration())
+    return false;
+  combined_events.insert(this);
 
-  {
-    combined_events.remove(other);
-    if (not combined_events.is_valid_configuration()) {
-      return false;
-    }
-    combined_events.insert(other);
-  }
+  combined_events.remove(other);
+  if (not combined_events.is_valid_configuration())
+    return false;
+  combined_events.insert(other);
 
   return true;
 }
index aeb4902..98f40ad 100644 (file)
@@ -27,7 +27,13 @@ public:
   UnfoldingEvent(UnfoldingEvent&&)                 = default;
 
   EventSet get_history() const;
+  EventSet get_local_config() const;
   bool in_history_of(const UnfoldingEvent* other) const;
+
+  /**
+   * @brief Whether or not the given event is a decendant
+   * of or an ancestor of the given event
+   */
   bool related_to(const UnfoldingEvent* other) const;
 
   /// @brief Whether or not this event is in conflict with
@@ -35,17 +41,23 @@ public:
   bool conflicts_with(const UnfoldingEvent* other) const;
 
   /// @brief Whether or not this event is in conflict with
-  /// any event in the given configuration
-  bool conflicts_with(const Configuration& config) const;
+  /// any event in the given set
+  bool conflicts_with_any(const EventSet& events) const;
 
   /// @brief Computes "this #ⁱ other"
   bool immediately_conflicts_with(const UnfoldingEvent* other) const;
   bool is_dependent_with(const Transition*) const;
   bool is_dependent_with(const UnfoldingEvent* other) const;
 
+  unsigned get_id() const { return this->id; }
+  aid_t get_actor() const { return get_transition()->aid_; }
   const EventSet& get_immediate_causes() const { return this->immediate_causes; }
   Transition* get_transition() const { return this->associated_transition.get(); }
 
+  void set_transition(std::shared_ptr<Transition> t) { this->associated_transition = std::move(t); }
+
+  std::string to_string() const;
+
   bool operator==(const UnfoldingEvent&) const;
   bool operator!=(const UnfoldingEvent& other) const { return not(*this == other); }
 
@@ -80,6 +92,12 @@ private:
    * so on.
    */
   EventSet immediate_causes;
+
+  /**
+   * @brief An identifier which is used to sort events
+   * deterministically
+   */
+  unsigned long id = 0;
 };
 
 } // namespace simgrid::mc::udpor
index a676c69..df316fd 100644 (file)
@@ -119,13 +119,13 @@ TEST_CASE("simgrid::mc::udpor::UnfoldingEvent: Dependency/Conflict Tests")
     //        e4  e5   e7
     //
     // e5 and e6 are in conflict, e5 and e7 are in conflict, e2 and e6, and e2 ands e7 are in conflict
-    UnfoldingEvent e1(EventSet(), std::make_shared<ConditionallyDependentAction>());
-    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<DependentAction>());
-    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e4(EventSet({&e3}), std::make_shared<ConditionallyDependentAction>());
-    UnfoldingEvent e5(EventSet({&e3}), std::make_shared<DependentAction>());
-    UnfoldingEvent e6(EventSet({&e1}), std::make_shared<ConditionallyDependentAction>());
-    UnfoldingEvent e7(EventSet({&e6, &e2}), std::make_shared<ConditionallyDependentAction>());
+    UnfoldingEvent e1(EventSet(), std::make_shared<ConditionallyDependentAction>(0));
+    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<DependentAction>(0));
+    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(0));
+    UnfoldingEvent e4(EventSet({&e3}), std::make_shared<ConditionallyDependentAction>(1));
+    UnfoldingEvent e5(EventSet({&e3}), std::make_shared<DependentAction>(1));
+    UnfoldingEvent e6(EventSet({&e1}), std::make_shared<ConditionallyDependentAction>(2));
+    UnfoldingEvent e7(EventSet({&e6, &e2}), std::make_shared<ConditionallyDependentAction>(3));
 
     SECTION("Dependency relation properties")
     {
@@ -180,7 +180,7 @@ TEST_CASE("simgrid::mc::udpor::UnfoldingEvent: Dependency/Conflict Tests")
     }
   }
 
-  SECTION("No conflicts whatsoever")
+  SECTION("Testing with no dependencies whatsoever")
   {
     // The following tests concern the given event structure:
     //                e1
@@ -190,19 +190,20 @@ TEST_CASE("simgrid::mc::udpor::UnfoldingEvent: Dependency/Conflict Tests")
     //          e3   /   /
     //         /  /    /
     //        e4  e5   e7
-    UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e6(EventSet({&e1}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e7(EventSet({&e6, &e2}), std::make_shared<IndependentAction>());
+    UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<IndependentAction>(1));
+    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+    UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>(3));
+    UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>(4));
+    UnfoldingEvent e6(EventSet({&e1}), std::make_shared<IndependentAction>(5));
+    UnfoldingEvent e7(EventSet({&e6, &e2}), std::make_shared<IndependentAction>(6));
 
     // Since everyone's actions are independent of one another, we expect
-    // that there are no conflicts between each pair of events
+    // that there are no conflicts between each pair of events (except with
+    // the same event itself)
     SECTION("Mutual dependencies")
     {
-      CHECK_FALSE(e1.is_dependent_with(&e1));
+      CHECK(e1.is_dependent_with(&e1));
       CHECK_FALSE(e1.is_dependent_with(&e2));
       CHECK_FALSE(e1.is_dependent_with(&e3));
       CHECK_FALSE(e1.is_dependent_with(&e4));
@@ -210,32 +211,32 @@ TEST_CASE("simgrid::mc::udpor::UnfoldingEvent: Dependency/Conflict Tests")
       CHECK_FALSE(e1.is_dependent_with(&e6));
       CHECK_FALSE(e1.is_dependent_with(&e7));
 
-      CHECK_FALSE(e2.is_dependent_with(&e2));
+      CHECK(e2.is_dependent_with(&e2));
       CHECK_FALSE(e2.is_dependent_with(&e3));
       CHECK_FALSE(e2.is_dependent_with(&e4));
       CHECK_FALSE(e2.is_dependent_with(&e5));
       CHECK_FALSE(e2.is_dependent_with(&e6));
       CHECK_FALSE(e2.is_dependent_with(&e7));
 
-      CHECK_FALSE(e3.is_dependent_with(&e3));
+      CHECK(e3.is_dependent_with(&e3));
       CHECK_FALSE(e3.is_dependent_with(&e4));
       CHECK_FALSE(e3.is_dependent_with(&e5));
       CHECK_FALSE(e3.is_dependent_with(&e6));
       CHECK_FALSE(e3.is_dependent_with(&e7));
 
-      CHECK_FALSE(e4.is_dependent_with(&e4));
+      CHECK(e4.is_dependent_with(&e4));
       CHECK_FALSE(e4.is_dependent_with(&e5));
       CHECK_FALSE(e4.is_dependent_with(&e6));
       CHECK_FALSE(e4.is_dependent_with(&e7));
 
-      CHECK_FALSE(e5.is_dependent_with(&e5));
+      CHECK(e5.is_dependent_with(&e5));
       CHECK_FALSE(e5.is_dependent_with(&e6));
       CHECK_FALSE(e5.is_dependent_with(&e7));
 
-      CHECK_FALSE(e6.is_dependent_with(&e6));
+      CHECK(e6.is_dependent_with(&e6));
       CHECK_FALSE(e6.is_dependent_with(&e7));
 
-      CHECK_FALSE(e7.is_dependent_with(&e7));
+      CHECK(e7.is_dependent_with(&e7));
     }
 
     SECTION("Mutual conflicts")
@@ -298,7 +299,7 @@ TEST_CASE("simgrid::mc::udpor::UnfoldingEvent: Dependency/Conflict Tests")
     }
   }
 
-  SECTION("General conflicts")
+  SECTION("Testing with some conflicts")
   {
     // The following tests concern the given event structure:
     //                e1
@@ -308,16 +309,17 @@ TEST_CASE("simgrid::mc::udpor::UnfoldingEvent: Dependency/Conflict Tests")
     //          e3   /   /
     //         /  /    /
     //        e4  e5   e7
-    UnfoldingEvent e1(EventSet(), std::make_shared<DependentAction>());
-    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<DependentAction>());
-    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e6(EventSet({&e1}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e7(EventSet({&e6, &e2}), std::make_shared<ConditionallyDependentAction>());
+    UnfoldingEvent e1(EventSet(), std::make_shared<DependentAction>(0));
+    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<DependentAction>(1));
+    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+    UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>(3));
+    UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>(4));
+    UnfoldingEvent e6(EventSet({&e1}), std::make_shared<IndependentAction>(5));
+    UnfoldingEvent e7(EventSet({&e6, &e2}), std::make_shared<ConditionallyDependentAction>(6));
 
     // Since everyone's actions are independent of one another, we expect
-    // that there are no conflicts between each pair of events
+    // that there are no conflicts between each pair of events (except the pair
+    // with the event and itself)
     SECTION("Mutual dependencies")
     {
       CHECK(e1.is_dependent_with(&e1));
@@ -335,25 +337,25 @@ TEST_CASE("simgrid::mc::udpor::UnfoldingEvent: Dependency/Conflict Tests")
       CHECK_FALSE(e2.is_dependent_with(&e6));
       CHECK(e2.is_dependent_with(&e7));
 
-      CHECK_FALSE(e3.is_dependent_with(&e3));
+      CHECK(e3.is_dependent_with(&e3));
       CHECK_FALSE(e3.is_dependent_with(&e4));
       CHECK_FALSE(e3.is_dependent_with(&e5));
       CHECK_FALSE(e3.is_dependent_with(&e6));
       CHECK_FALSE(e3.is_dependent_with(&e7));
 
-      CHECK_FALSE(e4.is_dependent_with(&e4));
+      CHECK(e4.is_dependent_with(&e4));
       CHECK_FALSE(e4.is_dependent_with(&e5));
       CHECK_FALSE(e4.is_dependent_with(&e6));
       CHECK_FALSE(e4.is_dependent_with(&e7));
 
-      CHECK_FALSE(e5.is_dependent_with(&e5));
+      CHECK(e5.is_dependent_with(&e5));
       CHECK_FALSE(e5.is_dependent_with(&e6));
       CHECK_FALSE(e5.is_dependent_with(&e7));
 
-      CHECK_FALSE(e6.is_dependent_with(&e6));
+      CHECK(e6.is_dependent_with(&e6));
       CHECK_FALSE(e6.is_dependent_with(&e7));
 
-      CHECK_FALSE(e7.is_dependent_with(&e7));
+      CHECK(e7.is_dependent_with(&e7));
     }
 
     SECTION("Mutual conflicts")
@@ -430,13 +432,13 @@ TEST_CASE("simgrid::mc::udpor::UnfoldingEvent: Dependency/Conflict Tests")
     //          e3      /
     //         /  /    e7
     //        e4  e5
-    UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>());
-    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<ConditionallyDependentAction>());
-    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>());
-    UnfoldingEvent e6(EventSet({&e1}), std::make_shared<DependentAction>());
-    UnfoldingEvent e7(EventSet({&e6}), std::make_shared<IndependentAction>());
+    UnfoldingEvent e1(EventSet(), std::make_shared<IndependentAction>(0));
+    UnfoldingEvent e2(EventSet({&e1}), std::make_shared<ConditionallyDependentAction>(1));
+    UnfoldingEvent e3(EventSet({&e2}), std::make_shared<IndependentAction>(2));
+    UnfoldingEvent e4(EventSet({&e3}), std::make_shared<IndependentAction>(3));
+    UnfoldingEvent e5(EventSet({&e3}), std::make_shared<IndependentAction>(4));
+    UnfoldingEvent e6(EventSet({&e1}), std::make_shared<DependentAction>(5));
+    UnfoldingEvent e7(EventSet({&e6}), std::make_shared<IndependentAction>(6));
 
     CHECK_FALSE(e1.conflicts_with(&e1));
     CHECK_FALSE(e1.conflicts_with(&e2));
index d75fb28..5ee5df2 100644 (file)
@@ -17,13 +17,15 @@ TEST_CASE("simgrid::mc::udpor::Unfolding: Creating an unfolding")
   REQUIRE(unfolding.empty());
 }
 
-TEST_CASE("simgrid::mc::udpor::Unfolding: Inserting and removing events with an unfolding")
+TEST_CASE("simgrid::mc::udpor::Unfolding: Inserting and marking events with an unfolding")
 {
   Unfolding unfolding;
-  auto e1              = std::make_unique<UnfoldingEvent>();
-  auto e2              = std::make_unique<UnfoldingEvent>();
-  const auto e1_handle = e1.get();
-  const auto e2_handle = e2.get();
+  auto e1 = std::make_unique<UnfoldingEvent>(
+      EventSet(), std::make_shared<ConditionallyDependentAction>(Transition::Type::UNKNOWN, 0));
+  auto e2 =
+      std::make_unique<UnfoldingEvent>(EventSet(), std::make_shared<DependentAction>(Transition::Type::UNKNOWN, 1));
+  const auto* e1_handle = e1.get();
+  const auto* e2_handle = e2.get();
 
   unfolding.insert(std::move(e1));
   REQUIRE(unfolding.size() == 1);
@@ -33,32 +35,13 @@ TEST_CASE("simgrid::mc::udpor::Unfolding: Inserting and removing events with an
   REQUIRE(unfolding.size() == 2);
   REQUIRE_FALSE(unfolding.empty());
 
-  unfolding.remove(e1_handle);
-  REQUIRE(unfolding.size() == 1);
+  unfolding.mark_finished(e1_handle);
+  REQUIRE(unfolding.size() == 2);
   REQUIRE_FALSE(unfolding.empty());
 
-  unfolding.remove(e2_handle);
-  REQUIRE(unfolding.size() == 0);
-  REQUIRE(unfolding.empty());
-}
-
-TEST_CASE("simgrid::mc::udpor::Unfolding: Checking for semantically equivalent events")
-{
-  Unfolding unfolding;
-  auto e1 = std::make_unique<UnfoldingEvent>(
-      EventSet(), std::make_shared<IndependentAction>(Transition::Type::BARRIER_ASYNC_LOCK, 6, 2));
-  auto e2 = std::make_unique<UnfoldingEvent>(
-      EventSet(), std::make_shared<IndependentAction>(Transition::Type::BARRIER_ASYNC_LOCK, 6, 2));
-
-  // e1 and e2 are equivalent
-  REQUIRE(*e1 == *e2);
-
-  const auto e1_handle = e1.get();
-  const auto e2_handle = e2.get();
-  unfolding.insert(std::move(e1));
-
-  REQUIRE(unfolding.contains_event_equivalent_to(e1_handle));
-  REQUIRE(unfolding.contains_event_equivalent_to(e2_handle));
+  unfolding.mark_finished(e2_handle);
+  REQUIRE(unfolding.size() == 2);
+  REQUIRE_FALSE(unfolding.empty());
 }
 
-TEST_CASE("simgrid::mc::udpor::Unfolding: Checking all immediate conflicts restricted to an unfolding") {}
\ No newline at end of file
+TEST_CASE("simgrid::mc::udpor::Unfolding: Checking all immediate conflicts restricted to an unfolding") {}
index d6ed988..6c2dee3 100644 (file)
@@ -6,11 +6,12 @@
 
 namespace simgrid::mc::udpor {
 
-maximal_subsets_iterator::maximal_subsets_iterator(const EventSet& events, std::optional<node_filter_function> filter,
+maximal_subsets_iterator::maximal_subsets_iterator(const EventSet& events,
+                                                   const std::optional<node_filter_function>& filter,
                                                    std::optional<size_t> maximum_subset_size)
     : maximum_subset_size(maximum_subset_size), current_maximal_set({EventSet()})
 {
-  const auto candidate_ordering = events.get_topological_ordering_of_reverse_graph();
+  auto candidate_ordering = events.get_topological_ordering_of_reverse_graph();
   if (filter.has_value()) {
     // Only store the events in the ordering that "matter" to us
     std::copy_if(std::move_iterator(candidate_ordering.begin()), std::move_iterator(candidate_ordering.end()),
@@ -34,7 +35,7 @@ void maximal_subsets_iterator::increment()
   }
 
   const auto next_event_ref = [&]() {
-    if (!has_started_searching) {
+    if (not has_started_searching) {
       has_started_searching = true;
       return bookkeeper.find_next_candidate_event(topological_ordering.begin(), topological_ordering.end());
     } else {
@@ -110,7 +111,7 @@ maximal_subsets_iterator::continue_traversal_of_maximal_events_tree()
   return topological_ordering.end();
 }
 
-bool maximal_subsets_iterator::bookkeeper::is_candidate_event(const UnfoldingEvent* e) const
+bool maximal_subsets_iterator::Bookkeeper::is_candidate_event(const UnfoldingEvent* e) const
 {
   if (const auto e_count = event_counts.find(e); e_count != event_counts.end()) {
     return e_count->second == 0;
@@ -153,24 +154,24 @@ bool maximal_subsets_iterator::can_grow_maximal_set() const
 }
 
 maximal_subsets_iterator::topological_order_position
-maximal_subsets_iterator::bookkeeper::find_next_candidate_event(topological_order_position first,
+maximal_subsets_iterator::Bookkeeper::find_next_candidate_event(topological_order_position first,
                                                                 topological_order_position last) const
 {
   return std::find_if(first, last, [&](const UnfoldingEvent* e) { return is_candidate_event(e); });
 }
 
-void maximal_subsets_iterator::bookkeeper::mark_included_in_maximal_set(const UnfoldingEvent* e)
+void maximal_subsets_iterator::Bookkeeper::mark_included_in_maximal_set(const UnfoldingEvent* e)
 {
-  const auto e_history = e->get_history();
-  for (const auto e_hist : e_history) {
+  const auto e_local_config = e->get_local_config();
+  for (const auto* e_hist : e_local_config) {
     event_counts[e_hist]++;
   }
 }
 
-void maximal_subsets_iterator::bookkeeper::mark_removed_from_maximal_set(const UnfoldingEvent* e)
+void maximal_subsets_iterator::Bookkeeper::mark_removed_from_maximal_set(const UnfoldingEvent* e)
 {
-  const auto e_history = e->get_history();
-  for (const auto e_hist : e_history) {
+  const auto e_local_config = e->get_local_config();
+  for (const auto* e_hist : e_local_config) {
     xbt_assert(event_counts.find(e_hist) != event_counts.end(),
                "Invariant Violation: Attempted to remove an event which was not previously added");
     xbt_assert(event_counts[e_hist] > 0, "Invariant Violation: An event `e` had a count of `0` at this point "
@@ -182,4 +183,4 @@ void maximal_subsets_iterator::bookkeeper::mark_removed_from_maximal_set(const U
   }
 }
 
-} // namespace simgrid::mc::udpor
\ No newline at end of file
+} // namespace simgrid::mc::udpor
index 7d0ab46..49872d8 100644 (file)
@@ -38,15 +38,16 @@ public:
   using node_filter_function       = std::function<bool(const UnfoldingEvent*)>;
   using topological_order_position = std::vector<const UnfoldingEvent*>::const_iterator;
 
-  maximal_subsets_iterator() = default;
+  maximal_subsets_iterator()                                    = default;
   explicit maximal_subsets_iterator(const Configuration& config,
-                                    std::optional<node_filter_function> filter = std::nullopt,
-                                    std::optional<size_t> maximum_subset_size  = std::nullopt)
+                                    const std::optional<node_filter_function>& filter = std::nullopt,
+                                    std::optional<size_t> maximum_subset_size         = std::nullopt)
       : maximal_subsets_iterator(config.get_events(), filter, maximum_subset_size)
   {
   }
-  explicit maximal_subsets_iterator(const EventSet& events, std::optional<node_filter_function> filter = std::nullopt,
-                                    std::optional<size_t> maximum_subset_size = std::nullopt);
+  explicit maximal_subsets_iterator(const EventSet& events,
+                                    const std::optional<node_filter_function>& filter = std::nullopt,
+                                    std::optional<size_t> maximum_subset_size         = std::nullopt);
 
 private:
   std::vector<const UnfoldingEvent*> topological_ordering;
@@ -58,7 +59,7 @@ private:
   bool has_started_searching                              = false;
   std::optional<size_t> maximum_subset_size               = std::nullopt;
   std::optional<EventSet> current_maximal_set             = std::nullopt;
-  std::stack<topological_order_position> backtrack_points = std::stack<topological_order_position>();
+  std::stack<topological_order_position, std::vector<topological_order_position>> backtrack_points;
 
   /**
    * @brief A small class which provides functionality for managing
@@ -70,7 +71,7 @@ private:
    * with events that are its current maximal event set (i.e.
    * its `current_maximal_set`)
    */
-  struct bookkeeper {
+  struct Bookkeeper {
   public:
     using topological_order_position = maximal_subsets_iterator::topological_order_position;
 
@@ -86,7 +87,8 @@ private:
     /// bookkeeping that has been done thus far, can be added to the
     /// current candidate maximal set
     bool is_candidate_event(const UnfoldingEvent*) const;
-  } bookkeeper;
+  };
+  Bookkeeper bookkeeper;
 
   void add_element_to_current_maximal_set(const UnfoldingEvent*);
   void remove_element_from_current_maximal_set(const UnfoldingEvent*);
@@ -137,7 +139,7 @@ private:
   bool equal(const maximal_subsets_iterator& other) const { return current_maximal_set == other.current_maximal_set; }
   const EventSet& dereference() const
   {
-    static const EventSet empty_set = EventSet();
+    static const EventSet empty_set;
     if (current_maximal_set.has_value()) {
       return current_maximal_set.value();
     }
index 1cbdb2e..a279b8f 100644 (file)
 #ifndef SIMGRID_MC_UDPOR_FORWARD_HPP
 #define SIMGRID_MC_UDPOR_FORWARD_HPP
 
+#include "src/mc/mc_forward.hpp"
+#include <simgrid/forward.h>
+
 namespace simgrid::mc::udpor {
 
+class Comb;
+struct ExtensionSetCalculator;
 class EventSet;
 class Configuration;
 class History;
 class Unfolding;
 class UnfoldingEvent;
-class maximal_subsets_iterator;
+struct maximal_subsets_iterator;
 
 } // namespace simgrid::mc::udpor
 
index 276edfc..de2ed37 100644 (file)
@@ -18,33 +18,59 @@ namespace simgrid::mc::udpor {
 
 struct IndependentAction : public Transition {
   IndependentAction() = default;
-  IndependentAction(Type type, aid_t issuer, int times_considered) : Transition(type, issuer, times_considered) {}
+  IndependentAction(Type type, aid_t issuer, int times_considered = 0) : Transition(type, issuer, times_considered) {}
+  IndependentAction(aid_t issuer, int times_considered = 0)
+      : IndependentAction(simgrid::mc::Transition::Type::UNKNOWN, issuer, times_considered)
+  {
+  }
 
-  // Independent with everyone else
-  bool depends(const Transition* other) const override { return false; }
+  // Independent with everyone else (even if run by the same actor). NOTE: This is
+  // only for the convenience of testing: in general, transitions are dependent with
+  // one another if run by the same actor
+  bool depends(const Transition* other) const override
+  {
+    if (aid_ == other->aid_) {
+      return true;
+    }
+    return false;
+  }
 };
 
 struct DependentAction : public Transition {
   DependentAction() = default;
-  DependentAction(Type type, aid_t issuer, int times_considered) : Transition(type, issuer, times_considered) {}
+  DependentAction(Type type, aid_t issuer, int times_considered = 0) : Transition(type, issuer, times_considered) {}
+  DependentAction(aid_t issuer, int times_considered = 0)
+      : DependentAction(simgrid::mc::Transition::Type::UNKNOWN, issuer, times_considered)
+  {
+  }
 
   // Dependent with everyone else (except IndependentAction)
   bool depends(const Transition* other) const override
   {
+    if (aid_ == other->aid_) {
+      return true;
+    }
     return dynamic_cast<const IndependentAction*>(other) == nullptr;
   }
 };
 
 struct ConditionallyDependentAction : public Transition {
   ConditionallyDependentAction() = default;
-  ConditionallyDependentAction(Type type, aid_t issuer, int times_considered)
+  ConditionallyDependentAction(Type type, aid_t issuer, int times_considered = 0)
       : Transition(type, issuer, times_considered)
   {
   }
+  ConditionallyDependentAction(aid_t issuer, int times_considered = 0)
+      : ConditionallyDependentAction(simgrid::mc::Transition::Type::UNKNOWN, issuer, times_considered)
+  {
+  }
 
   // Dependent only with DependentAction (i.e. not itself)
   bool depends(const Transition* other) const override
   {
+    if (aid_ == other->aid_) {
+      return true;
+    }
     return dynamic_cast<const DependentAction*>(other) != nullptr;
   }
 };
diff --git a/src/mc/inspect/DwarfExpression.cpp b/src/mc/inspect/DwarfExpression.cpp
deleted file mode 100644 (file)
index 2e74410..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <cstddef>
-#include <cstdint>
-#include <unordered_set>
-
-#include "src/mc/AddressSpace.hpp"
-#include "src/mc/inspect/DwarfExpression.hpp"
-#include "src/mc/inspect/Frame.hpp"
-#include "src/mc/inspect/LocationList.hpp"
-#include "src/mc/inspect/ObjectInformation.hpp"
-#include "src/mc/inspect/mc_dwarf.hpp"
-#include "src/mc/mc_private.hpp"
-
-namespace simgrid::dwarf {
-
-void execute(const Dwarf_Op* ops, std::size_t n, const ExpressionContext& context, ExpressionStack& stack)
-{
-  for (size_t i = 0; i != n; ++i) {
-    const Dwarf_Op* op = ops + i;
-    std::uint8_t atom  = op->atom;
-    intptr_t first;
-    intptr_t second;
-
-    switch (atom) {
-        // Push the CFA (Canonical Frame Address):
-      case DW_OP_call_frame_cfa:
-        /* See 6.4 of DWARF4 (http://dwarfstd.org/doc/DWARF4.pdf#page=140):
-         *
-         * > Typically, the CFA is defined to be the value of the stack
-         * > pointer at the call site in the previous frame (which may be
-         * > different from its value on entry to the current frame).
-         *
-         * We need to unwind the frame in order to get the SP of the parent
-         * frame.
-         *
-         * Warning: the CFA returned by libunwind (UNW_X86_64_RSP, etc.)
-         * is the SP of the *current* frame. */
-        if (context.cursor) {
-          // Get frame:
-          unw_cursor_t cursor = *(context.cursor);
-          unw_step(&cursor);
-
-          unw_word_t res;
-          unw_get_reg(&cursor, UNW_REG_SP, &res);
-          stack.push(res);
-          break;
-        }
-        throw evaluation_error("Missing cursor");
-
-        // Frame base:
-      case DW_OP_fbreg:
-        stack.push((std::uintptr_t)context.frame_base + op->number);
-        break;
-
-        // Address from the base address of this ELF object.
-        // Push the address on the stack (base_address + argument).
-      case DW_OP_addr:
-        if (context.object_info) {
-          Dwarf_Off addr = (Dwarf_Off)(std::uintptr_t)context.object_info->base_address() + op->number;
-          stack.push(addr);
-          break;
-        }
-        throw evaluation_error("No base address");
-
-        // ***** Stack manipulation:
-
-        // Push another copy/duplicate the value at the top of the stack:
-      case DW_OP_dup:
-        stack.dup();
-        break;
-
-        // Pop/drop the top of the stack:
-      case DW_OP_drop:
-        (void)stack.pop();
-        break;
-
-      case DW_OP_swap:
-        stack.swap();
-        break;
-
-        // Duplicate the value under the top of the stack:
-      case DW_OP_over:
-        stack.push(stack.top(1));
-        break;
-
-        // ***** Operations:
-        // Those usually take the top of the stack and the next value as argument
-        // and replace the top of the stack with the computed value
-        // (stack.top() += stack.before_top()).
-
-      case DW_OP_plus:
-        first  = stack.pop();
-        second = stack.pop();
-        stack.push(first + second);
-        break;
-
-      case DW_OP_mul:
-        first  = stack.pop();
-        second = stack.pop();
-        stack.push(first * second);
-        break;
-
-      case DW_OP_plus_uconst:
-        stack.top() += op->number;
-        break;
-
-      case DW_OP_not:
-        stack.top() = ~stack.top();
-        break;
-
-      case DW_OP_neg:
-        stack.top() = -(intptr_t)stack.top();
-        break;
-
-      case DW_OP_minus:
-        first  = stack.pop();
-        second = stack.pop();
-        stack.push(second - first);
-        break;
-
-      case DW_OP_and:
-        first  = stack.pop();
-        second = stack.pop();
-        stack.push(first & second);
-        break;
-
-      case DW_OP_or:
-        first  = stack.pop();
-        second = stack.pop();
-        stack.push(first | second);
-        break;
-
-      case DW_OP_xor:
-        first  = stack.pop();
-        second = stack.pop();
-        stack.push(first ^ second);
-        break;
-
-      case DW_OP_nop:
-        break;
-
-        // ***** Deference (memory fetch)
-
-      case DW_OP_deref_size:
-        throw evaluation_error("Unsupported operation");
-
-      case DW_OP_deref:
-        // Computed address:
-        if (not context.address_space)
-          throw evaluation_error("Missing address space");
-        context.address_space->read_bytes(&stack.top(), sizeof(uintptr_t), mc::remote(stack.top()));
-        break;
-
-      default:
-
-        // Registers:
-        if (static const std::unordered_set<uint8_t> registers =
-                {DW_OP_breg0,  DW_OP_breg1,  DW_OP_breg2,  DW_OP_breg3,  DW_OP_breg4,  DW_OP_breg5,  DW_OP_breg6,
-                 DW_OP_breg7,  DW_OP_breg8,  DW_OP_breg9,  DW_OP_breg10, DW_OP_breg11, DW_OP_breg12, DW_OP_breg13,
-                 DW_OP_breg14, DW_OP_breg15, DW_OP_breg16, DW_OP_breg17, DW_OP_breg18, DW_OP_breg19, DW_OP_breg20,
-                 DW_OP_breg21, DW_OP_breg22, DW_OP_breg23, DW_OP_breg24, DW_OP_breg25, DW_OP_breg26, DW_OP_breg27,
-                 DW_OP_breg28, DW_OP_breg29, DW_OP_breg30, DW_OP_breg31};
-            registers.count(atom) > 0) {
-          // Push register + constant:
-          int register_id = dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
-          unw_word_t res;
-          if (not context.cursor)
-            throw evaluation_error("Missing stack context");
-          unw_get_reg(context.cursor, register_id, &res);
-          stack.push(res + op->number);
-          break;
-        }
-
-        // ***** Constants:
-
-        // Short constant literals:
-        if (static const std::unordered_set<uint8_t> literals = {DW_OP_lit0,  DW_OP_lit1,  DW_OP_lit2,  DW_OP_lit3,
-                                                                 DW_OP_lit4,  DW_OP_lit5,  DW_OP_lit6,  DW_OP_lit7,
-                                                                 DW_OP_lit8,  DW_OP_lit9,  DW_OP_lit10, DW_OP_lit11,
-                                                                 DW_OP_lit12, DW_OP_lit13, DW_OP_lit14, DW_OP_lit15,
-                                                                 DW_OP_lit16, DW_OP_lit17, DW_OP_lit18, DW_OP_lit19,
-                                                                 DW_OP_lit20, DW_OP_lit21, DW_OP_lit22, DW_OP_lit23,
-                                                                 DW_OP_lit24, DW_OP_lit25, DW_OP_lit26, DW_OP_lit27,
-                                                                 DW_OP_lit28, DW_OP_lit29, DW_OP_lit30, DW_OP_lit31};
-            literals.count(atom) > 0) {
-          // Push a literal/constant on the stack:
-          stack.push(atom - DW_OP_lit0);
-          break;
-        }
-
-        // General constants:
-        if (static const std::unordered_set<uint8_t> constants = {DW_OP_const1u, DW_OP_const2u, DW_OP_const4u,
-                                                                  DW_OP_const8u, DW_OP_const1s, DW_OP_const2s,
-                                                                  DW_OP_const4s, DW_OP_const8s, DW_OP_constu,
-                                                                  DW_OP_consts};
-            constants.count(atom) > 0) {
-          // Push the constant argument on the stack.
-          stack.push(op->number);
-          break;
-        }
-
-        // Not handled:
-        throw evaluation_error("Unsupported operation");
-    }
-  }
-}
-
-} // namespace simgrid::dwarf
diff --git a/src/mc/inspect/DwarfExpression.hpp b/src/mc/inspect/DwarfExpression.hpp
deleted file mode 100644 (file)
index 2e8de12..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_DWARF_EXPRESSION_HPP
-#define SIMGRID_MC_DWARF_EXPRESSION_HPP
-
-#include <cstdint>
-#include <cstdlib>
-
-#include <array>
-#include <stdexcept> // runtime_error
-#include <utility>
-#include <vector>
-
-#include <elfutils/libdw.h>
-#include <libunwind.h>
-
-#include "src/mc/inspect/mc_dwarf.hpp"
-#include "src/mc/mc_forward.hpp"
-
-/** @file DwarfExpression.hpp
- *
- *  Evaluation of DWARF location expressions.
- */
-
-namespace simgrid::dwarf {
-
-/** A DWARF expression
- *
- *  DWARF defines a simple stack-based VM for evaluating expressions
- *  (such as locations of variables, etc.): a DWARF expression is
- *  just a sequence of dwarf instructions. We currently directly use
- *  `Dwarf_Op` from `dwarf.h` for dwarf instructions.
- */
-using DwarfExpression = std::vector<Dwarf_Op>;
-
-/** Context of evaluation of a DWARF expression
- *
- *  Some DWARF instructions need to read the CPU registers,
- *  the process memory, etc. All those information are gathered in
- *  the evaluation context.
- */
-struct ExpressionContext {
-  /** CPU state (registers) */
-  unw_cursor_t* cursor                  = nullptr;
-  void* frame_base                      = nullptr;
-  const mc::AddressSpace* address_space = nullptr; /** Address space used to read memory */
-  mc::ObjectInformation* object_info    = nullptr;
-};
-
-/** When an error happens in the execution of a DWARF expression */
-class evaluation_error : public std::runtime_error {
-public:
-  using std::runtime_error::runtime_error;
-};
-
-/** A stack for evaluating a DWARF expression
- *
- *  DWARF expressions work by manipulating a stack of integer values.
- */
-class ExpressionStack {
-public:
-  using value_type                      = std::uintptr_t;
-  static constexpr std::size_t MAX_SIZE = 64;
-
-private:
-  // Values of the stack (the top is stack_[size_ - 1]):
-  std::array<uintptr_t, MAX_SIZE> stack_{{0}};
-  size_t size_ = 0;
-
-public:
-  // Access:
-  std::size_t size() const { return size_; }
-  bool empty() const { return size_ == 0; }
-  void clear() { size_ = 0; }
-  uintptr_t& operator[](int i) { return stack_[i]; }
-  uintptr_t const& operator[](int i) const { return stack_[i]; }
-
-  /** Top of the stack */
-  value_type& top()
-  {
-    if (size_ == 0)
-      throw evaluation_error("Empty stack");
-    return stack_[size_ - 1];
-  }
-
-  /** Access the i-th element from the top of the stack */
-  value_type& top(unsigned i)
-  {
-    if (size_ < i)
-      throw evaluation_error("Invalid element");
-    return stack_[size_ - 1 - i];
-  }
-
-  /** Push a value on the top of the stack */
-  void push(value_type value)
-  {
-    if (size_ == stack_.size())
-      throw evaluation_error("DWARF stack overflow");
-    stack_[size_] = value;
-    size_++;
-  }
-
-  /* Pop a value from the top of the stack */
-  value_type pop()
-  {
-    if (size_ == 0)
-      throw evaluation_error("DWARF stack underflow");
-    --size_;
-    return stack_[size_];
-  }
-
-  // These are DWARF operations (DW_OP_foo):
-
-  /* Push a copy of the top-value (DW_OP_dup) */
-  void dup() { push(top()); }
-
-  /* Swap the two top-most values */
-  void swap() { std::swap(top(), top(1)); }
-};
-
-/** Executes a DWARF expression
- *
- *  @param ops     DWARF expression instructions
- *  @param n       number of instructions
- *  @param context evaluation context (registers, memory, etc.)
- *  @param stack   DWARf stack where the operations are executed
- */
-void execute(const Dwarf_Op* ops, std::size_t n, ExpressionContext const& context, ExpressionStack& stack);
-
-/** Executes/evaluates a DWARF expression
- *
- *  @param expression DWARF expression to execute
- *  @param context    evaluation context (registers, memory, etc.)
- *  @param stack      DWARf stack where the operations are executed
- */
-inline void execute(simgrid::dwarf::DwarfExpression const& expression, ExpressionContext const& context,
-                    ExpressionStack& stack)
-{
-  execute(expression.data(), expression.size(), context, stack);
-}
-
-} // namespace simgrid::dwarf
-
-#endif
diff --git a/src/mc/inspect/Frame.cpp b/src/mc/inspect/Frame.cpp
deleted file mode 100644 (file)
index 9d80454..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <libunwind.h>
-
-#include "xbt/sysdep.h"
-
-#include "src/mc/inspect/Frame.hpp"
-
-namespace simgrid::mc {
-
-void* Frame::frame_base(unw_cursor_t& unw_cursor) const
-{
-  simgrid::dwarf::Location location =
-      simgrid::dwarf::resolve(frame_base_location, object_info, &unw_cursor, nullptr, nullptr);
-  if (location.in_memory())
-    return location.address();
-  else if (location.in_register()) {
-    // This is a special case.
-    // The register is not the location of the frame base
-    // (a frame base cannot be located in a register).
-    // Instead, DWARF defines this to mean that the register
-    // contains the address of the frame base.
-    unw_word_t word;
-    unw_get_reg(&unw_cursor, location.register_id(), &word);
-    return (void*)word;
-  } else
-    xbt_die("Unexpected location type");
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/inspect/Frame.hpp b/src/mc/inspect/Frame.hpp
deleted file mode 100644 (file)
index d02e25e..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_FRAME_HPP
-#define SIMGRID_MC_FRAME_HPP
-
-#include <cstdint>
-#include <string>
-
-#include "xbt/base.h"
-#include "xbt/range.hpp"
-
-#include "src/mc/inspect/LocationList.hpp"
-#include "src/mc/inspect/Variable.hpp"
-#include "src/mc/mc_forward.hpp"
-
-namespace simgrid::mc {
-
-/** Debug information about a given function or scope within a function */
-class Frame {
-public:
-  /** Kind of scope (DW_TAG_subprogram, DW_TAG_inlined_subroutine, etc.) */
-  int tag = DW_TAG_invalid;
-
-  /** Name of the function (if it is a function) */
-  std::string name;
-
-  /** Range of instruction addresses for which this scope is valid */
-  simgrid::xbt::Range<std::uint64_t> range{0, 0};
-
-  simgrid::dwarf::LocationList frame_base_location;
-
-  /** List of the variables (sorted by name) */
-  std::vector<Variable> variables;
-
-  /* Unique identifier for this scope (in the object_info)
-   *
-   * This is the global DWARF offset of the DIE. */
-  unsigned long int id = 0;
-
-  std::vector<Frame> scopes;
-
-  /** Value of `DW_AT_abstract_origin`
-   *
-   *  For inlined subprograms, this is the ID of the
-   *  parent function.
-   */
-  unsigned long int abstract_origin_id = 0;
-
-  simgrid::mc::ObjectInformation* object_info = nullptr;
-
-  void* frame_base(unw_cursor_t& unw_cursor) const;
-  void remove_variable(char* name);
-};
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/inspect/LocationList.cpp b/src/mc/inspect/LocationList.cpp
deleted file mode 100644 (file)
index 18a585d..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* Copyright (c) 2004-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/inspect/LocationList.hpp"
-#include "src/mc/inspect/ObjectInformation.hpp"
-#include "src/mc/inspect/mc_dwarf.hpp"
-
-#include "xbt/asserts.h"
-#include "xbt/log.h"
-#include "xbt/sysdep.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <libunwind.h>
-#include <utility>
-
-XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(mc_dwarf);
-
-namespace simgrid::dwarf {
-
-/** Resolve a location expression */
-Location resolve(simgrid::dwarf::DwarfExpression const& expression, simgrid::mc::ObjectInformation* object_info,
-                 unw_cursor_t* c, void* frame_pointer_address, const simgrid::mc::AddressSpace* address_space)
-{
-  simgrid::dwarf::ExpressionContext context;
-  context.frame_base    = frame_pointer_address;
-  context.cursor        = c;
-  context.address_space = address_space;
-  context.object_info   = object_info;
-
-  if (not expression.empty() && expression[0].atom >= DW_OP_reg0 && expression[0].atom <= DW_OP_reg31) {
-    int dwarf_register = expression[0].atom - DW_OP_reg0;
-    xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i", dwarf_register);
-    return Location(dwarf_register_to_libunwind(dwarf_register));
-  }
-
-  simgrid::dwarf::ExpressionStack stack;
-  simgrid::dwarf::execute(expression, context, stack);
-  return Location((void*)stack.top());
-}
-
-// TODO, move this in a method of LocationList
-static simgrid::dwarf::DwarfExpression const* find_expression(simgrid::dwarf::LocationList const& locations,
-                                                              unw_word_t ip)
-{
-  for (simgrid::dwarf::LocationListEntry const& entry : locations)
-    if (entry.valid_for_ip(ip))
-      return &entry.expression();
-  return nullptr;
-}
-
-Location resolve(simgrid::dwarf::LocationList const& locations, simgrid::mc::ObjectInformation* object_info,
-                 unw_cursor_t* c, void* frame_pointer_address, const simgrid::mc::AddressSpace* address_space)
-{
-  unw_word_t ip = 0;
-  if (c)
-    xbt_assert(unw_get_reg(c, UNW_REG_IP, &ip) == 0, "Could not resolve IP");
-  simgrid::dwarf::DwarfExpression const* expression = find_expression(locations, ip);
-  xbt_assert(expression != nullptr, "Could not resolve location");
-  return simgrid::dwarf::resolve(*expression, object_info, c, frame_pointer_address, address_space);
-}
-
-LocationList location_list(const simgrid::mc::ObjectInformation& info, Dwarf_Attribute& attr)
-{
-  LocationList locations;
-  std::ptrdiff_t offset = 0;
-  while (true) {
-    Dwarf_Addr base;
-    Dwarf_Addr start;
-    Dwarf_Addr end;
-    Dwarf_Op* ops;
-    std::size_t len;
-
-    offset = dwarf_getlocations(&attr, offset, &base, &start, &end, &ops, &len);
-
-    if (offset == -1)
-      XBT_WARN("Error while loading location list: %s", dwarf_errmsg(-1));
-    if (offset <= 0)
-      break;
-
-    auto base_address = reinterpret_cast<std::uint64_t>(info.base_address());
-
-    LocationListEntry::range_type range;
-    if (start == 0)
-      // If start == 0, this is not a location list:
-      range = {0, UINT64_MAX};
-    else
-      range = {base_address + start, base_address + end};
-
-    locations.emplace_back(DwarfExpression(ops, ops + len), range);
-  }
-
-  return locations;
-}
-} // namespace simgrid::dwarf
diff --git a/src/mc/inspect/LocationList.hpp b/src/mc/inspect/LocationList.hpp
deleted file mode 100644 (file)
index 9504a98..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Copyright (c) 2004-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_OBJECT_LOCATION_H
-#define SIMGRID_MC_OBJECT_LOCATION_H
-
-#include "xbt/base.h"
-#include "xbt/range.hpp"
-
-#include "src/mc/inspect/DwarfExpression.hpp"
-#include "src/mc/mc_base.hpp"
-#include "src/mc/mc_forward.hpp"
-
-#include <cstdint>
-#include <vector>
-
-namespace simgrid::dwarf {
-
-/** A DWARF expression with optional validity constraints */
-class LocationListEntry {
-public:
-  using range_type = simgrid::xbt::Range<std::uint64_t>;
-
-private:
-  DwarfExpression expression_;
-  // By default, the expression is always valid:
-  range_type range_ = {0, UINT64_MAX};
-
-public:
-  LocationListEntry() = default;
-  LocationListEntry(DwarfExpression expression, range_type range) : expression_(std::move(expression)), range_(range) {}
-  explicit LocationListEntry(DwarfExpression expression) : expression_(std::move(expression)) {}
-
-  DwarfExpression& expression() { return expression_; }
-  DwarfExpression const& expression() const { return expression_; }
-  bool valid_for_ip(unw_word_t ip) const { return range_.contain(ip); }
-};
-
-using LocationList = std::vector<LocationListEntry>;
-
-/** Location of some variable in memory
- *
- *  The variable is located either in memory of a register.
- */
-class Location {
-private:
-  void* memory_    = nullptr;
-  int register_id_ = 0;
-
-public:
-  explicit Location(void* x) : memory_(x) {}
-  explicit Location(int register_id) : register_id_(register_id) {}
-  // Type of location:
-  bool in_register() const { return memory_ == nullptr; }
-  bool in_memory() const { return memory_ != nullptr; }
-
-  // Get the location:
-  void* address() const { return memory_; }
-  int register_id() const { return register_id_; }
-};
-
-XBT_PRIVATE
-Location resolve(simgrid::dwarf::DwarfExpression const& expression, simgrid::mc::ObjectInformation* object_info,
-                 unw_cursor_t* c, void* frame_pointer_address, const simgrid::mc::AddressSpace* address_space);
-
-Location resolve(simgrid::dwarf::LocationList const& locations, simgrid::mc::ObjectInformation* object_info,
-                 unw_cursor_t* c, void* frame_pointer_address, const simgrid::mc::AddressSpace* address_space);
-
-XBT_PRIVATE
-simgrid::dwarf::LocationList location_list(const simgrid::mc::ObjectInformation& info, Dwarf_Attribute& attr);
-
-} // namespace simgrid::dwarf
-
-#endif
diff --git a/src/mc/inspect/ObjectInformation.cpp b/src/mc/inspect/ObjectInformation.cpp
deleted file mode 100644 (file)
index 479dd7f..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <algorithm>
-#include <cstdint>
-#include <sys/mman.h> // PROT_READ and friends
-#include <vector>
-
-#include "src/mc/inspect/Frame.hpp"
-#include "src/mc/inspect/ObjectInformation.hpp"
-#include "src/mc/inspect/Variable.hpp"
-#include "src/mc/mc_private.hpp"
-#include "xbt/file.hpp"
-
-namespace simgrid::mc {
-
-/* For an executable object, addresses are virtual address (there is no offset) i.e.
- *  \f$\text{virtual address} = \{dwarf address}\f$
- *
- * For a shared object, the addresses are offset from the beginning of the shared object (the base address of the
- * mapped shared object must be used as offset
- * i.e. \f$\text{virtual address} = \text{shared object base address}
- *             + \text{dwarf address}\f$.
- */
-void* ObjectInformation::base_address() const
-{
-  // For an executable (more precisely for an ET_EXEC) the base it 0:
-  if (this->executable())
-    return nullptr;
-
-  // For an a shared-object (ET_DYN, including position-independent executables) the base address is its lowest address:
-  void* result = this->start_exec;
-  if (this->start_rw != nullptr && result > (void*)this->start_rw)
-    result = this->start_rw;
-  if (this->start_ro != nullptr && result > (void*)this->start_ro)
-    result = this->start_ro;
-  return result;
-}
-
-Frame* ObjectInformation::find_function(const void* ip)
-{
-  ensure_dwarf_loaded();
-
-  /* This is implemented by binary search on a sorted array.
-   *
-   * We do quite a lot of those so we want this to be cache efficient.
-   * We pack the only information we need in the index entries in order
-   * to successfully do the binary search. We do not need the high_pc
-   * during the binary search (only at the end) so it is not included
-   * in the index entry. We could use parallel arrays as well.
-   *
-   * Note the usage of reverse iterators to match the correct interval.
-   */
-  auto pos = std::lower_bound(this->functions_index.rbegin(), this->functions_index.rend(), ip,
-                              [](auto const& func, auto const* addr) { return func.low_pc > addr; });
-
-  /* At this point, the search is over.
-   * Either we have found the correct function or we do not know
-   * any function corresponding to this instruction address.
-   * Only at the point do we dereference the function pointer. */
-  return (pos != this->functions_index.rend() && reinterpret_cast<std::uint64_t>(ip) < pos->function->range.end())
-             ? pos->function
-             : nullptr;
-}
-
-const Variable* ObjectInformation::find_variable(const char* var_name)
-{
-  ensure_dwarf_loaded();
-
-  auto pos = std::lower_bound(this->global_variables.begin(), this->global_variables.end(), var_name,
-                              [](auto const& var, const char* name) { return var.name < name; });
-  return (pos != this->global_variables.end() && pos->name == var_name) ? &(*pos) : nullptr;
-}
-
-void ObjectInformation::remove_global_variable(const char* var_name)
-{
-  // Binary search:
-  auto pos1 = std::lower_bound(this->global_variables.begin(), this->global_variables.end(), var_name,
-                               [](auto const& var, const char* name) { return var.name < name; });
-  // Find the whole range:
-  auto pos2 = std::upper_bound(pos1, this->global_variables.end(), var_name,
-                               [](const char* name, auto const& var) { return name < var.name; });
-  // Remove the whole range:
-  this->global_variables.erase(pos1, pos2);
-}
-
-/** Ignore a local variable in a scope
- *
- *  Ignore all instances of variables with a given name in any (possibly inlined) subprogram with a given namespaced
- *  name.
- *
- *  @param var_name        Name of the local variable to ignore
- *  @param subprogram_name Name of the subprogram to ignore (nullptr for any)
- *  @param subprogram      (possibly inlined) Subprogram of the scope current scope
- *  @param scope           Current scope
- */
-static void remove_local_variable(Frame& scope, const char* var_name, const char* subprogram_name,
-                                  Frame const& subprogram)
-{
-  // If the current subprogram matches the given name:
-  if (subprogram_name == nullptr || (not subprogram.name.empty() && subprogram.name == subprogram_name)) {
-    // Try to find the variable and remove it:
-
-    // Binary search:
-    auto pos = std::lower_bound(scope.variables.begin(), scope.variables.end(), var_name,
-                                [](auto const& var, const char* name) { return var.name < name; });
-    if (pos != scope.variables.end() && pos->name == var_name) {
-      // Variable found, remove it:
-      scope.variables.erase(pos);
-    }
-  }
-
-  // And recursive processing in nested scopes:
-  for (Frame& nested_scope : scope.scopes) {
-    // The new scope may be an inlined subroutine, in this case we want to use its
-    // namespaced name in recursive calls:
-    Frame const& nested_subprogram = nested_scope.tag == DW_TAG_inlined_subroutine ? nested_scope : subprogram;
-    remove_local_variable(nested_scope, var_name, subprogram_name, nested_subprogram);
-  }
-}
-
-void ObjectInformation::remove_local_variable(const char* var_name, const char* subprogram_name)
-{
-  for (auto& [_, entry] : this->subprograms)
-    mc::remove_local_variable(entry, var_name, subprogram_name, entry);
-}
-
-/** @brief Fills the position of the segments (executable, read-only, read/write) */
-// TODO, use the ELF segment information for more robustness
-void find_object_address(std::vector<xbt::VmMap> const& maps, ObjectInformation* result)
-{
-  const int PROT_RW = PROT_READ | PROT_WRITE;
-  const int PROT_RX = PROT_READ | PROT_EXEC;
-
-  std::string name = xbt::Path(result->file_name).get_base_name();
-
-  for (size_t i = 0; i < maps.size(); ++i) {
-    simgrid::xbt::VmMap const& reg = maps[i];
-    if (reg.pathname.empty() || name != simgrid::xbt::Path(reg.pathname).get_base_name())
-      continue;
-
-    // This is the non-GNU_RELRO-part of the data segment:
-    if (reg.prot == PROT_RW) {
-      xbt_assert(not result->start_rw, "Multiple read-write segments for %s, not supported", maps[i].pathname.c_str());
-      result->start_rw = (char*)reg.start_addr;
-      result->end_rw   = (char*)reg.end_addr;
-
-      // The next VMA might be end of the data segment:
-      if (i + 1 < maps.size() && maps[i + 1].pathname.empty() && maps[i + 1].prot == PROT_RW &&
-          maps[i + 1].start_addr == reg.end_addr)
-        result->end_rw = (char*)maps[i + 1].end_addr;
-    }
-
-    // This is the text segment:
-    else if (reg.prot == PROT_RX) {
-      xbt_assert(not result->start_exec, "Multiple executable segments for %s, not supported",
-                 maps[i].pathname.c_str());
-      result->start_exec = (char*)reg.start_addr;
-      result->end_exec   = (char*)reg.end_addr;
-
-      // The next VMA might be end of the data segment:
-      if (i + 1 < maps.size() && maps[i + 1].pathname.empty() && maps[i + 1].prot == PROT_RW &&
-          maps[i + 1].start_addr == reg.end_addr) {
-        result->start_rw = (char*)maps[i + 1].start_addr;
-        result->end_rw   = (char*)maps[i + 1].end_addr;
-      }
-    }
-
-    // This is the GNU_RELRO-part of the data segment:
-    else if (reg.prot == PROT_READ) {
-      xbt_assert(not result->start_ro,
-                 "Multiple read-only segments for %s, not supported. Compiling with the following may help: "
-                 "-g -Wl,-znorelro -Wl,-znoseparate-code",
-                 maps[i].pathname.c_str());
-      result->start_ro = (char*)reg.start_addr;
-      result->end_ro   = (char*)reg.end_addr;
-    }
-  }
-
-  result->start = result->start_rw;
-  if ((const void*)result->start_ro < result->start)
-    result->start = result->start_ro;
-  if ((const void*)result->start_exec < result->start)
-    result->start = result->start_exec;
-
-  result->end = result->end_rw;
-  if (result->end_ro && (const void*)result->end_ro > result->end)
-    result->end = result->end_ro;
-  if (result->end_exec && (const void*)result->end_exec > result->end)
-    result->end = result->end_exec;
-
-  xbt_assert(result->start_exec || result->start_rw || result->start_ro);
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/inspect/ObjectInformation.hpp b/src/mc/inspect/ObjectInformation.hpp
deleted file mode 100644 (file)
index 7d1dfa1..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_OBJECT_INFORMATION_HPP
-#define SIMGRID_MC_OBJECT_INFORMATION_HPP
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include "src/mc/inspect/Frame.hpp"
-#include "src/mc/inspect/Type.hpp"
-#include "src/mc/mc_forward.hpp"
-#include "src/xbt/memory_map.hpp"
-
-#include "src/smpi/include/private.hpp"
-
-namespace simgrid::mc {
-
-/** An entry in the functions index
- *
- *  See the code of ObjectInformation::find_function.
- */
-struct FunctionIndexEntry {
-  void* low_pc;
-  simgrid::mc::Frame* function;
-};
-
-/** Information about an ELF module (executable or shared object)
- *
- *  This contains all the information we need about an executable or
- *  shared-object in the model-checked process:
- *
- *  - where it is located in the virtual address space;
- *
- *  - where are located its different memory mappings in the the
- *    virtual address space;
- *
- *  - all the debugging (DWARF) information
- *    - types,
- *    - location of the functions and their local variables,
- *    - global variables,
- *
- *  - etc.
- */
-class ObjectInformation {
-  bool dwarf_loaded = false; // Lazily loads the dwarf info
-
-public:
-  void ensure_dwarf_loaded(); // Used by functions that need the dwarf
-  ObjectInformation() = default;
-
-  // Not copiable:
-  ObjectInformation(ObjectInformation const&) = delete;
-  ObjectInformation& operator=(ObjectInformation const&) = delete;
-
-  // Flag:
-  static const int Executable = 1;
-
-  /** Bitfield of flags */
-  int flags = 0;
-  std::string file_name;
-  const void* start = nullptr;
-  const void* end   = nullptr;
-  // Location of its text segment:
-  char* start_exec = nullptr;
-  char* end_exec   = nullptr;
-  // Location of the read-only part of its data segment:
-  char* start_rw = nullptr;
-  char* end_rw   = nullptr;
-  // Location of the read/write part of its data segment:
-  char* start_ro = nullptr;
-  char* end_ro   = nullptr;
-
-  /** All of its subprograms indexed by their address */
-  std::unordered_map<std::uint64_t, simgrid::mc::Frame> subprograms;
-
-  /** Index of functions by instruction address
-   *
-   * We need to efficiently find the function from any given instruction
-   * address inside its range. This index is sorted by low_pc
-   *
-   * The entries are sorted by low_pc and a binary search can be used to look
-   * them up. In order to have a better cache locality, we only keep the
-   * information we need for the lookup in this vector. We could probably
-   * replace subprograms by an ordered vector of Frame and replace this one b
-   * a parallel `std::vector<void*>`.
-   */
-  std::vector<FunctionIndexEntry> functions_index;
-
-  std::vector<simgrid::mc::Variable> global_variables;
-
-  /** Types indexed by DWARF ID */
-  std::unordered_map<std::uint64_t, simgrid::mc::Type> types;
-
-  /** Types indexed by name
-   *
-   *  Different compilation units have their separate type definitions
-   *  (for the same type). When we find an opaque type in one compilation unit,
-   *  we use this in order to try to find its definition in another compilation
-   *  unit.
-   */
-  std::unordered_map<std::string, simgrid::mc::Type*> full_types_by_name;
-
-  /** Whether this module is an executable
-   *
-   *  More precisely we check if this is an ET_EXE ELF. These ELF files
-   *  use fixed addresses instead of base-address relative addresses.
-   *  Position independent executables are in fact ET_DYN.
-   */
-  bool executable() const { return this->flags & simgrid::mc::ObjectInformation::Executable; }
-
-  /** Base address of the module
-   *
-   *  All the location information in ELF and DWARF are expressed as an offsets
-   *  from this base address:
-   *
-   *  - location of the functions and global variables
-   *
-   *  - the DWARF instruction `OP_addr` pushes this on the DWARF stack.
-   **/
-  void* base_address() const;
-
-  /** Find a function by instruction address
-   *
-   *  Loads the dwarf information on need.
-   *
-   *  @param ip instruction address
-   *  @return corresponding function (if any) or nullptr
-   */
-  simgrid::mc::Frame* find_function(const void* ip);
-
-  /** Find a global variable by name
-   *
-   *  Loads the dwarf information on need.
-   *
-   *  This is used to ignore global variables and to find well-known variables
-   *  (`__mmalloc_default_mdp`).
-   *
-   *  @param name scopes name of the global variable (`myproject::Foo::count`)
-   *  @return corresponding variable (if any) or nullptr
-   */
-  const simgrid::mc::Variable* find_variable(const char* name);
-
-  /** Remove a global variable (in order to ignore it)
-   *
-   *  This is used to ignore a global variable for the snapshot comparison.
-   */
-  void remove_global_variable(const char* name);
-
-  /** Remove a local variables (in order to ignore it)
-   *
-   *  @param name Name of the local variable
-   *  @param scope scopes name name of the function (myproject::Foo::count) or null for all functions
-   */
-  void remove_local_variable(const char* name, const char* scope);
-};
-
-XBT_PRIVATE std::shared_ptr<ObjectInformation> createObjectInformation(std::vector<simgrid::xbt::VmMap> const& maps,
-                                                                       const char* name);
-
-/** Augment the current module with information about the other ones */
-XBT_PRIVATE void postProcessObjectInformation(const simgrid::mc::RemoteProcessMemory* process,
-                                              simgrid::mc::ObjectInformation* info);
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/inspect/Type.hpp b/src/mc/inspect/Type.hpp
deleted file mode 100644 (file)
index 3c225a1..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_TYPE_HPP
-#define SIMGRID_MC_TYPE_HPP
-
-#include <cstddef>
-
-#include <string>
-#include <vector>
-
-#include <dwarf.h>
-
-#include "xbt/asserts.h"
-#include "xbt/base.h"
-
-#include "src/mc/inspect/LocationList.hpp"
-#include "src/mc/mc_forward.hpp"
-
-namespace simgrid::mc {
-
-/** A member of a structure, union
- *
- *  Inheritance is seen as a special member as well.
- */
-class Member {
-public:
-  using flags_type                                 = int;
-  static constexpr flags_type INHERITANCE_FLAG     = 1;
-  static constexpr flags_type VIRTUAL_POINTER_FLAG = 2;
-
-  Member() = default;
-
-  /** Whether this member represent some inherited part of the object */
-  flags_type flags = 0;
-
-  /** Name of the member (if any) */
-  std::string name;
-
-  /** DWARF location expression for locating the location of the member */
-  simgrid::dwarf::DwarfExpression location_expression;
-
-  std::size_t byte_size = 0; // Do we really need this?
-
-  unsigned type_id        = 0;
-  simgrid::mc::Type* type = nullptr;
-
-  bool isInheritance() const { return this->flags & INHERITANCE_FLAG; }
-  bool isVirtualPointer() const { return this->flags & VIRTUAL_POINTER_FLAG; }
-
-  /** Whether the member is at a fixed offset from the base address */
-  bool has_offset_location() const
-  {
-    // Recognize the expression `DW_OP_plus_uconst(offset)`:
-    return location_expression.size() == 1 && location_expression[0].atom == DW_OP_plus_uconst;
-  }
-
-  /** Get the offset of the member
-   *
-   *  This is only valid is the member is at a fixed offset from the base.
-   *  This is often the case (for C types, C++ type without virtual
-   *  inheritance).
-   *
-   *  If the location is more complex, the location expression has
-   *  to be evaluated (which might need accessing the memory).
-   */
-  int offset() const
-  {
-    xbt_assert(this->has_offset_location());
-    return this->location_expression[0].number;
-  }
-
-  /** Set the location of the member as a fixed offset */
-  void offset(int new_offset)
-  {
-    // Set the expression to be `DW_OP_plus_uconst(offset)`:
-    Dwarf_Op op;
-    op.atom                   = DW_OP_plus_uconst;
-    op.number                 = new_offset;
-    this->location_expression = {op};
-  }
-};
-
-/** A type in the model-checked program */
-class Type {
-public:
-  Type() = default;
-
-  /** The DWARF TAG of the type (e.g. DW_TAG_array_type) */
-  int type    = 0;
-  unsigned id = 0;             /* Offset in the section (in hexadecimal form) */
-  std::string name;            /* Name of the type */
-  int byte_size     = 0;       /* Size in bytes */
-  int element_count = 0;       /* Number of elements for array type */
-  unsigned type_id  = 0;       /* DW_AT_type id */
-  std::vector<Member> members; /* if DW_TAG_structure_type, DW_TAG_class_type, DW_TAG_union_type*/
-
-  simgrid::mc::Type* subtype   = nullptr; // DW_AT_type
-  simgrid::mc::Type* full_type = nullptr; // The same (but more complete) type
-};
-
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/inspect/Variable.hpp b/src/mc/inspect/Variable.hpp
deleted file mode 100644 (file)
index f2cae32..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_VARIABLE_HPP
-#define SIMGRID_MC_VARIABLE_HPP
-
-#include <cstddef>
-
-#include <string>
-
-#include "src/mc/inspect/LocationList.hpp"
-#include "src/mc/mc_forward.hpp"
-
-namespace simgrid::mc {
-
-/** A variable (global or local) in the model-checked program */
-class Variable {
-public:
-  Variable()       = default;
-  std::uint32_t id = 0;
-  bool global      = false;
-  std::string name;
-  unsigned type_id        = 0;
-  simgrid::mc::Type* type = nullptr;
-
-  /** Address of the variable (if it is fixed) */
-  void* address = nullptr;
-
-  /** Description of the location of the variable (if it's not fixed) */
-  simgrid::dwarf::LocationList location_list;
-
-  /** Offset of validity of the variable (DW_AT_start_scope)
-   *
-   *  This is an offset from the variable scope beginning. This variable
-   *  is only valid starting from this offset.
-   */
-  std::size_t start_scope = 0;
-
-  simgrid::mc::ObjectInformation* object_info = nullptr;
-};
-
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/inspect/mc_dwarf.cpp b/src/mc/inspect/mc_dwarf.cpp
deleted file mode 100644 (file)
index 094635d..0000000
+++ /dev/null
@@ -1,1207 +0,0 @@
-/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/simgrid/util.hpp"
-#include "xbt/log.h"
-#include "xbt/string.hpp"
-#include "xbt/sysdep.h"
-#include <simgrid/config.h>
-
-#include "src/mc/inspect/ObjectInformation.hpp"
-#include "src/mc/inspect/Variable.hpp"
-#include "src/mc/inspect/mc_dwarf.hpp"
-#include "src/mc/mc_private.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-
-#include <algorithm>
-#include <array>
-#include <cerrno>
-#include <cinttypes>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <fcntl.h>
-#include <memory>
-#include <unordered_map>
-#include <utility>
-
-#include <boost/range/algorithm.hpp>
-
-#include <elfutils/libdw.h>
-#include <elfutils/version.h>
-
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dwarf, mc, "DWARF processing");
-
-/** @brief The default DW_TAG_lower_bound for a given DW_AT_language.
- *
- *  The default for a given language is defined in the DWARF spec.
- *
- *  @param language constant as defined by the DWARf spec
- */
-static uint64_t MC_dwarf_default_lower_bound(int lang);
-
-/** @brief Computes the the element_count of a DW_TAG_enumeration_type DIE
- *
- * This is the number of elements in a given array dimension.
- *
- * A reference of the compilation unit (DW_TAG_compile_unit) is
- * needed because the default lower bound (when there is no DW_AT_lower_bound)
- * depends of the language of the compilation unit (DW_AT_language).
- *
- * @param die  DIE for the DW_TAG_enumeration_type or DW_TAG_subrange_type
- * @param unit DIE of the DW_TAG_compile_unit
- */
-static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit);
-
-/** @brief Computes the number of elements of a given DW_TAG_array_type.
- *
- * @param die DIE for the DW_TAG_array_type
- */
-static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit);
-
-/** @brief Process a DIE
- *
- *  @param info the resulting object for the library/binary file (output)
- *  @param die  the current DIE
- *  @param unit the DIE of the compile unit of the current DIE
- *  @param frame containing frame if any
- */
-static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                simgrid::mc::Frame* frame, const char* ns);
-
-/** @brief Process a type DIE
- */
-static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                     simgrid::mc::Frame* frame, const char* ns);
-
-/** @brief Calls MC_dwarf_handle_die on all children of the given die
- *
- *  @param info the resulting object for the library/binary file (output)
- *  @param die  the current DIE
- *  @param unit the DIE of the compile unit of the current DIE
- *  @param frame containing frame if any
- */
-static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                     simgrid::mc::Frame* frame, const char* ns);
-
-/** @brief Handle a variable (DW_TAG_variable or other)
- *
- *  @param info the resulting object for the library/binary file (output)
- *  @param die  the current DIE
- *  @param unit the DIE of the compile unit of the current DIE
- *  @param frame containing frame if any
- */
-static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, const Dwarf_Die* unit,
-                                         simgrid::mc::Frame* frame, const char* ns);
-
-/** @brief Get the DW_TAG_type of the DIE
- *
- *  @param die DIE
- *  @return DW_TAG_type attribute as a new string (nullptr if none)
- */
-static std::uint64_t MC_dwarf_at_type(Dwarf_Die* die);
-
-namespace simgrid::dwarf {
-
-enum class TagClass { Unknown, Type, Subprogram, Variable, Scope, Namespace };
-
-/*** Class of forms defined in the DWARF standard */
-enum class FormClass {
-  Unknown,
-  Address, // Location in the program's address space
-  Block,   // Arbitrary block of bytes
-  Constant,
-  String,
-  Flag,      // Boolean value
-  Reference, // Reference to another DIE
-  ExprLoc,   // DWARF expression/location description
-  LinePtr,
-  LocListPtr,
-  MacPtr,
-  RangeListPtr
-};
-
-static TagClass classify_tag(int tag)
-{
-  static const std::unordered_map<int, TagClass> map = {
-      {DW_TAG_array_type, TagClass::Type},            {DW_TAG_class_type, TagClass::Type},
-      {DW_TAG_enumeration_type, TagClass::Type},      {DW_TAG_typedef, TagClass::Type},
-      {DW_TAG_pointer_type, TagClass::Type},          {DW_TAG_reference_type, TagClass::Type},
-      {DW_TAG_rvalue_reference_type, TagClass::Type}, {DW_TAG_string_type, TagClass::Type},
-      {DW_TAG_structure_type, TagClass::Type},        {DW_TAG_subroutine_type, TagClass::Type},
-      {DW_TAG_union_type, TagClass::Type},            {DW_TAG_ptr_to_member_type, TagClass::Type},
-      {DW_TAG_set_type, TagClass::Type},              {DW_TAG_subrange_type, TagClass::Type},
-      {DW_TAG_base_type, TagClass::Type},             {DW_TAG_const_type, TagClass::Type},
-      {DW_TAG_file_type, TagClass::Type},             {DW_TAG_packed_type, TagClass::Type},
-      {DW_TAG_volatile_type, TagClass::Type},         {DW_TAG_restrict_type, TagClass::Type},
-      {DW_TAG_interface_type, TagClass::Type},        {DW_TAG_unspecified_type, TagClass::Type},
-      {DW_TAG_shared_type, TagClass::Type},
-
-      {DW_TAG_subprogram, TagClass::Subprogram},
-
-      {DW_TAG_variable, TagClass::Variable},          {DW_TAG_formal_parameter, TagClass::Variable},
-
-      {DW_TAG_lexical_block, TagClass::Scope},        {DW_TAG_try_block, TagClass::Scope},
-      {DW_TAG_catch_block, TagClass::Scope},          {DW_TAG_inlined_subroutine, TagClass::Scope},
-      {DW_TAG_with_stmt, TagClass::Scope},
-
-      {DW_TAG_namespace, TagClass::Namespace}};
-
-  auto res = map.find(tag);
-  return res != map.end() ? res->second : TagClass::Unknown;
-}
-
-/** @brief Find the DWARF data class for a given DWARF data form
- *
- *  This mapping is defined in the DWARF spec.
- *
- *  @param form The form (values taken from the DWARF spec)
- *  @return An internal representation for the corresponding class
- * */
-static FormClass classify_form(int form)
-{
-  static const std::unordered_map<int, FormClass> map = {
-      {DW_FORM_addr, FormClass::Address},
-
-      {DW_FORM_block2, FormClass::Block},           {DW_FORM_block4, FormClass::Block},
-      {DW_FORM_block, FormClass::Block},            {DW_FORM_block1, FormClass::Block},
-
-      {DW_FORM_data1, FormClass::Constant},         {DW_FORM_data2, FormClass::Constant},
-      {DW_FORM_data4, FormClass::Constant},         {DW_FORM_data8, FormClass::Constant},
-      {DW_FORM_udata, FormClass::Constant},         {DW_FORM_sdata, FormClass::Constant},
-#if _ELFUTILS_PREREQ(0, 171)
-      {DW_FORM_implicit_const, FormClass::Constant},
-#endif
-
-      {DW_FORM_string, FormClass::String},          {DW_FORM_strp, FormClass::String},
-
-      {DW_FORM_ref_addr, FormClass::Reference},     {DW_FORM_ref1, FormClass::Reference},
-      {DW_FORM_ref2, FormClass::Reference},         {DW_FORM_ref4, FormClass::Reference},
-      {DW_FORM_ref8, FormClass::Reference},         {DW_FORM_ref_udata, FormClass::Reference},
-
-      {DW_FORM_flag, FormClass::Flag},              {DW_FORM_flag_present, FormClass::Flag},
-
-      {DW_FORM_exprloc, FormClass::ExprLoc}
-
-      // TODO sec offset
-      // TODO indirect
-  };
-
-  auto res = map.find(form);
-  return res != map.end() ? res->second : FormClass::Unknown;
-}
-
-/** @brief Get the name of the tag of a given DIE
- *
- *  @param die DIE
- *  @return name of the tag of this DIE
- */
-inline XBT_PRIVATE const char* tagname(Dwarf_Die* die)
-{
-  return tagname(dwarf_tag(die));
-}
-
-} // namespace simgrid::dwarf
-
-// ***** Attributes
-
-/** @brief Get an attribute of a given DIE as a string
- *
- *  @param die       the DIE
- *  @param attribute attribute
- *  @return value of the given attribute of the given DIE
- */
-static const char* MC_dwarf_attr_integrate_string(Dwarf_Die* die, int attribute)
-{
-  Dwarf_Attribute attr;
-  if (not dwarf_attr_integrate(die, attribute, &attr))
-    return nullptr;
-  else
-    return dwarf_formstring(&attr);
-}
-
-static Dwarf_Off MC_dwarf_attr_integrate_dieoffset(Dwarf_Die* die, int attribute)
-{
-  Dwarf_Attribute attr;
-  if (dwarf_hasattr_integrate(die, attribute) == 0)
-    return 0;
-  dwarf_attr_integrate(die, attribute, &attr);
-  Dwarf_Die subtype_die;
-  xbt_assert(dwarf_formref_die(&attr, &subtype_die) != nullptr, "Could not find DIE");
-  return dwarf_dieoffset(&subtype_die);
-}
-
-/** @brief Find the type/subtype (DW_AT_type) for a DIE
- *
- *  @param die the DIE
- *  @return DW_AT_type reference as a global offset in hexadecimal (or nullptr)
- */
-static std::uint64_t MC_dwarf_at_type(Dwarf_Die* die)
-{
-  return MC_dwarf_attr_integrate_dieoffset(die, DW_AT_type);
-}
-
-static uint64_t MC_dwarf_attr_integrate_addr(Dwarf_Die* die, int attribute)
-{
-  Dwarf_Attribute attr;
-  if (dwarf_attr_integrate(die, attribute, &attr) == nullptr)
-    return 0;
-  Dwarf_Addr value;
-  if (dwarf_formaddr(&attr, &value) == 0)
-    return (uint64_t)value;
-  else
-    return 0;
-}
-
-static uint64_t MC_dwarf_attr_integrate_uint(Dwarf_Die* die, int attribute, uint64_t default_value)
-{
-  Dwarf_Attribute attr;
-  if (dwarf_attr_integrate(die, attribute, &attr) == nullptr)
-    return default_value;
-  Dwarf_Word value;
-  return dwarf_formudata(dwarf_attr_integrate(die, attribute, &attr), &value) == 0 ? (uint64_t)value : default_value;
-}
-
-static bool MC_dwarf_attr_flag(Dwarf_Die* die, int attribute, bool integrate)
-{
-  Dwarf_Attribute attr;
-  if ((integrate ? dwarf_attr_integrate(die, attribute, &attr) : dwarf_attr(die, attribute, &attr)) == nullptr)
-    return false;
-
-  bool result;
-  xbt_assert(not dwarf_formflag(&attr, &result), "Unexpected form for attribute %s",
-             simgrid::dwarf::attrname(attribute));
-  return result;
-}
-
-/** @brief Find the default lower bound for a given language
- *
- *  The default lower bound of an array (when DW_TAG_lower_bound
- *  is missing) depends on the language of the compilation unit.
- *
- *  @param lang Language of the compilation unit (values defined in the DWARF spec)
- *  @return     Default lower bound of an array in this compilation unit
- * */
-static uint64_t MC_dwarf_default_lower_bound(int lang)
-{
-  const std::unordered_map<int, unsigned> map = {
-      {DW_LANG_C, 0},           {DW_LANG_C89, 0},            {DW_LANG_C99, 0},            {DW_LANG_C11, 0},
-      {DW_LANG_C_plus_plus, 0}, {DW_LANG_C_plus_plus_11, 0}, {DW_LANG_C_plus_plus_14, 0}, {DW_LANG_D, 0},
-      {DW_LANG_Java, 0},        {DW_LANG_ObjC, 0},           {DW_LANG_ObjC_plus_plus, 0}, {DW_LANG_Python, 0},
-      {DW_LANG_UPC, 0},
-
-      {DW_LANG_Ada83, 1},       {DW_LANG_Ada95, 1},          {DW_LANG_Fortran77, 1},      {DW_LANG_Fortran90, 1},
-      {DW_LANG_Fortran95, 1},   {DW_LANG_Fortran03, 1},      {DW_LANG_Fortran08, 1},      {DW_LANG_Modula2, 1},
-      {DW_LANG_Pascal83, 1},    {DW_LANG_PL1, 1},            {DW_LANG_Cobol74, 1},        {DW_LANG_Cobol85, 1}};
-
-  auto res = map.find(lang);
-  xbt_assert(res != map.end(), "No default DW_TAG_lower_bound for language %i and none given", lang);
-  return res->second;
-}
-
-/** @brief Finds the number of elements in a DW_TAG_subrange_type or DW_TAG_enumeration_type DIE
- *
- *  @param die  the DIE
- *  @param unit DIE of the compilation unit
- *  @return     number of elements in the range
- * */
-static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit)
-{
-  xbt_assert(dwarf_tag(die) == DW_TAG_enumeration_type || dwarf_tag(die) == DW_TAG_subrange_type,
-             "MC_dwarf_subrange_element_count called with DIE of type %s", simgrid::dwarf::tagname(die));
-
-  // Use DW_TAG_count if present:
-  if (dwarf_hasattr_integrate(die, DW_AT_count))
-    return MC_dwarf_attr_integrate_uint(die, DW_AT_count, 0);
-  // Otherwise compute DW_TAG_upper_bound-DW_TAG_lower_bound + 1:
-
-  if (not dwarf_hasattr_integrate(die, DW_AT_upper_bound))
-    // This is not really 0, but the code expects this (we do not know):
-    return 0;
-
-  uint64_t upper_bound = MC_dwarf_attr_integrate_uint(die, DW_AT_upper_bound, static_cast<uint64_t>(-1));
-
-  uint64_t lower_bound = 0;
-  if (dwarf_hasattr_integrate(die, DW_AT_lower_bound))
-    lower_bound = MC_dwarf_attr_integrate_uint(die, DW_AT_lower_bound, static_cast<uint64_t>(-1));
-  else
-    lower_bound = MC_dwarf_default_lower_bound(dwarf_srclang(unit));
-  return upper_bound - lower_bound + 1;
-}
-
-/** @brief Finds the number of elements in an array type (DW_TAG_array_type)
- *
- *  The compilation unit might be needed because the default lower
- *  bound depends on the language of the compilation unit.
- *
- *  @param die the DIE of the DW_TAG_array_type
- *  @param unit the DIE of the compilation unit
- *  @return number of elements in this array type
- * */
-static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit)
-{
-  xbt_assert(dwarf_tag(die) == DW_TAG_array_type, "MC_dwarf_array_element_count called with DIE of type %s",
-             simgrid::dwarf::tagname(die));
-
-  int result = 1;
-  Dwarf_Die child;
-  for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) {
-    int child_tag = dwarf_tag(&child);
-    if (child_tag == DW_TAG_subrange_type || child_tag == DW_TAG_enumeration_type)
-      result *= MC_dwarf_subrange_element_count(&child, unit);
-  }
-  return result;
-}
-
-// ***** Variable
-
-/** Sort the variable by name and address.
- *
- *  We could use boost::container::flat_set instead.
- */
-static bool MC_compare_variable(simgrid::mc::Variable const& a, simgrid::mc::Variable const& b)
-{
-  int cmp = a.name.compare(b.name);
-  if (cmp < 0)
-    return true;
-  else if (cmp > 0)
-    return false;
-  else
-    return a.address < b.address;
-}
-
-// ***** simgrid::mc::Type*
-
-/** @brief Initialize the location of a member of a type
- * (DW_AT_data_member_location of a DW_TAG_member).
- *
- *  @param  type   a type (struct, class)
- *  @param  member the member of the type
- *  @param  child  DIE of the member (DW_TAG_member)
- */
-static void MC_dwarf_fill_member_location(const simgrid::mc::Type* type, simgrid::mc::Member* member, Dwarf_Die* child)
-{
-  xbt_assert(not dwarf_hasattr(child, DW_AT_data_bit_offset), "Can't groke DW_AT_data_bit_offset.");
-
-  if (not dwarf_hasattr_integrate(child, DW_AT_data_member_location)) {
-    xbt_assert(type->type == DW_TAG_union_type,
-               "Missing DW_AT_data_member_location field in DW_TAG_member %s of type <%" PRIx64 ">%s",
-               member->name.c_str(), (uint64_t)type->id, type->name.c_str());
-    return;
-  }
-
-  Dwarf_Attribute attr;
-  dwarf_attr_integrate(child, DW_AT_data_member_location, &attr);
-  int form                             = dwarf_whatform(&attr);
-  simgrid::dwarf::FormClass form_class = simgrid::dwarf::classify_form(form);
-  switch (form_class) {
-    case simgrid::dwarf::FormClass::ExprLoc:
-    case simgrid::dwarf::FormClass::Block:
-      // Location expression:
-      {
-        Dwarf_Op* expr;
-        size_t len;
-        xbt_assert(not dwarf_getlocation(&attr, &expr, &len),
-                   "Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%" PRIx64
-                   ">%s",
-                   MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t)type->id, type->name.c_str());
-        member->location_expression = simgrid::dwarf::DwarfExpression(expr, expr + len);
-        break;
-      }
-    case simgrid::dwarf::FormClass::Constant:
-      // Offset from the base address of the object:
-      {
-        Dwarf_Word offset;
-        xbt_assert(not dwarf_formudata(&attr, &offset), "Cannot get %s location <%" PRIx64 ">%s",
-                   MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t)type->id, type->name.c_str());
-        member->offset(offset);
-        break;
-      }
-
-    default:
-      // includes FormClass::LocListPtr (reference to a location list: TODO) and FormClass::Reference (it's supposed to
-      // be possible in DWARF2 but I couldn't find its semantic in the spec)
-      xbt_die("Can't handle form class (%d) / form 0x%x as DW_AT_member_location", (int)form_class, (unsigned)form);
-  }
-}
-
-/** @brief Populate the list of members of a type
- *
- *  @param info ELF object containing the type DIE
- *  @param die  DIE of the type
- *  @param unit DIE of the compilation unit containing the type DIE
- *  @param type the type
- */
-static void MC_dwarf_add_members(const simgrid::mc::ObjectInformation* /*info*/, Dwarf_Die* die,
-                                 const Dwarf_Die* /*unit*/, simgrid::mc::Type* type)
-{
-  Dwarf_Die child;
-  xbt_assert(type->members.empty());
-  for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) {
-    int tag = dwarf_tag(&child);
-    if (tag == DW_TAG_member || tag == DW_TAG_inheritance) {
-      // Skip declarations:
-      if (MC_dwarf_attr_flag(&child, DW_AT_declaration, false))
-        continue;
-
-      // Skip compile time constants:
-      if (dwarf_hasattr(&child, DW_AT_const_value))
-        continue;
-
-      // TODO, we should use another type (because is is not a type but a member)
-      simgrid::mc::Member member;
-      if (tag == DW_TAG_inheritance)
-        member.flags |= simgrid::mc::Member::INHERITANCE_FLAG;
-
-      const char* name = MC_dwarf_attr_integrate_string(&child, DW_AT_name);
-      if (name)
-        member.name = name;
-      // Those base names are used by GCC and clang for virtual table pointers
-      // respectively ("__vptr$ClassName", "__vptr.ClassName"):
-      if (member.name.rfind("__vptr$", 0) == 0 || member.name.rfind("__vptr.", 0) == 0)
-        member.flags |= simgrid::mc::Member::VIRTUAL_POINTER_FLAG;
-      // A cleaner solution would be to check against the type:
-      // ---
-      // tag: DW_TAG_member
-      // name: "_vptr$Foo"
-      // type:
-      //   # Type for a pointer to a vtable
-      //   tag: DW_TAG_pointer_type
-      //   type:
-      //     # Type for a vtable:
-      //     tag: DW_TAG_pointer_type
-      //     name: "__vtbl_ptr_type"
-      //     type:
-      //       tag: DW_TAG_subroutine_type
-      //       type:
-      //         tag: DW_TAG_base_type
-      //         name: "int"
-      // ---
-
-      member.byte_size = MC_dwarf_attr_integrate_uint(&child, DW_AT_byte_size, 0);
-      member.type_id   = MC_dwarf_at_type(&child);
-
-      if (dwarf_hasattr(&child, DW_AT_data_bit_offset)) {
-        XBT_WARN("Can't groke DW_AT_data_bit_offset for %s", name);
-        continue;
-      }
-
-      MC_dwarf_fill_member_location(type, &member, &child);
-
-      xbt_assert(member.type_id, "Missing type for member %s of <%" PRIx64 ">%s", member.name.c_str(),
-                 (uint64_t)type->id, type->name.c_str());
-
-      type->members.push_back(std::move(member));
-    }
-  }
-}
-
-/** @brief Create a MC type object from a DIE
- *
- *  @param info current object info object
- *  @param die DIE (for a given type)
- *  @param unit compilation unit of the current DIE
- *  @return MC representation of the type
- */
-static simgrid::mc::Type MC_dwarf_die_to_type(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                              simgrid::mc::Frame* frame, const char* ns)
-{
-  simgrid::mc::Type type;
-  type.type          = dwarf_tag(die);
-  type.name          = "";
-  type.element_count = -1;
-
-  // Global Offset
-  type.id = dwarf_dieoffset(die);
-
-  const char* prefix;
-  switch (type.type) {
-    case DW_TAG_structure_type:
-      prefix = "struct ";
-      break;
-    case DW_TAG_union_type:
-      prefix = "union ";
-      break;
-    case DW_TAG_class_type:
-      prefix = "class ";
-      break;
-    default:
-      prefix = "";
-  }
-
-  const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
-  if (name != nullptr) {
-    if (ns)
-      type.name = simgrid::xbt::string_printf("%s%s::%s", prefix, ns, name);
-    else
-      type.name = simgrid::xbt::string_printf("%s%s", prefix, name);
-  }
-
-  type.type_id = MC_dwarf_at_type(die);
-
-  // Some compilers do not emit DW_AT_byte_size for pointer_type,
-  // so we fill this. We currently assume that the model-checked process is in
-  // the same architecture..
-  if (type.type == DW_TAG_pointer_type)
-    type.byte_size = sizeof(void*);
-
-  // Computation of the byte_size
-  if (dwarf_hasattr_integrate(die, DW_AT_byte_size))
-    type.byte_size = MC_dwarf_attr_integrate_uint(die, DW_AT_byte_size, 0);
-  else if (type.type == DW_TAG_array_type || type.type == DW_TAG_structure_type || type.type == DW_TAG_class_type) {
-    Dwarf_Word size;
-    if (dwarf_aggregate_size(die, &size) == 0)
-      type.byte_size = size;
-  }
-
-  switch (type.type) {
-    case DW_TAG_array_type:
-      type.element_count = MC_dwarf_array_element_count(die, unit);
-      // TODO, handle DW_byte_stride and (not) DW_bit_stride
-      break;
-
-    case DW_TAG_pointer_type:
-    case DW_TAG_reference_type:
-    case DW_TAG_rvalue_reference_type:
-      break;
-
-    case DW_TAG_structure_type:
-    case DW_TAG_union_type:
-    case DW_TAG_class_type:
-      MC_dwarf_add_members(info, die, unit, &type);
-      MC_dwarf_handle_children(info, die, unit, frame,
-                               ns ? simgrid::xbt::string_printf("%s::%s", ns, name).c_str() : type.name.c_str());
-      break;
-
-    default:
-      XBT_DEBUG("Unhandled type: %d (%s)", type.type, simgrid::dwarf::tagname(type.type));
-      break;
-  }
-
-  return type;
-}
-
-static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                     simgrid::mc::Frame* frame, const char* ns)
-{
-  simgrid::mc::Type type = MC_dwarf_die_to_type(info, die, unit, frame, ns);
-  auto& t                = (info->types[type.id] = std::move(type));
-  if (not t.name.empty() && type.byte_size != 0)
-    info->full_types_by_name[t.name] = &t;
-}
-
-static std::unique_ptr<simgrid::mc::Variable> MC_die_to_variable(simgrid::mc::ObjectInformation* info, Dwarf_Die* die,
-                                                                 const Dwarf_Die* /*unit*/,
-                                                                 const simgrid::mc::Frame* frame, const char* ns)
-{
-  // Skip declarations:
-  if (MC_dwarf_attr_flag(die, DW_AT_declaration, false))
-    return nullptr;
-
-  // Skip compile time constants:
-  if (dwarf_hasattr(die, DW_AT_const_value))
-    return nullptr;
-
-  Dwarf_Attribute attr_location;
-  if (dwarf_attr(die, DW_AT_location, &attr_location) == nullptr)
-    // No location: do not add it ?
-    return nullptr;
-
-  auto variable         = std::make_unique<simgrid::mc::Variable>();
-  variable->id          = dwarf_dieoffset(die);
-  variable->global      = frame == nullptr; // Can be override base on DW_AT_location
-  variable->object_info = info;
-
-  const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
-  if (name)
-    variable->name = name;
-  variable->type_id = MC_dwarf_at_type(die);
-
-  int form = dwarf_whatform(&attr_location);
-  simgrid::dwarf::FormClass form_class;
-  if (form == DW_FORM_sec_offset)
-    form_class = simgrid::dwarf::FormClass::Constant;
-  else
-    form_class = simgrid::dwarf::classify_form(form);
-  switch (form_class) {
-    case simgrid::dwarf::FormClass::ExprLoc:
-    case simgrid::dwarf::FormClass::Block:
-      // Location expression:
-      {
-        Dwarf_Op* expr;
-        size_t len;
-        xbt_assert(not dwarf_getlocation(&attr_location, &expr, &len),
-                   "Could not read location expression in DW_AT_location "
-                   "of variable <%" PRIx64 ">%s",
-                   (uint64_t)variable->id, variable->name.c_str());
-
-        if (len == 1 && expr[0].atom == DW_OP_addr) {
-          variable->global  = true;
-          auto offset       = static_cast<uintptr_t>(expr[0].number);
-          auto base         = reinterpret_cast<uintptr_t>(info->base_address());
-          variable->address = reinterpret_cast<void*>(base + offset);
-        } else
-          variable->location_list = {
-              simgrid::dwarf::LocationListEntry(simgrid::dwarf::DwarfExpression(expr, expr + len))};
-
-        break;
-      }
-
-    case simgrid::dwarf::FormClass::LocListPtr:
-    case simgrid::dwarf::FormClass::Constant:
-      // Reference to location list:
-      variable->location_list = simgrid::dwarf::location_list(*info, attr_location);
-      break;
-
-    default:
-      xbt_die("Unexpected form 0x%x (%i), class 0x%x (%i) list for location in <%" PRIx64 ">%s", (unsigned)form, form,
-              (unsigned)form_class, (int)form_class, (uint64_t)variable->id, variable->name.c_str());
-  }
-
-  // Handle start_scope:
-  if (dwarf_hasattr(die, DW_AT_start_scope)) {
-    Dwarf_Attribute attr;
-    dwarf_attr(die, DW_AT_start_scope, &attr);
-    form       = dwarf_whatform(&attr);
-    form_class = simgrid::dwarf::classify_form(form);
-    if (form_class == simgrid::dwarf::FormClass::Constant) {
-      Dwarf_Word value;
-      variable->start_scope = dwarf_formudata(&attr, &value) == 0 ? (size_t)value : 0;
-    } else {
-      // TODO: FormClass::RangeListPtr
-      xbt_die("Unhandled form 0x%x, class 0x%X for DW_AT_start_scope of variable %s", (unsigned)form,
-              (unsigned)form_class, name == nullptr ? "?" : name);
-    }
-  }
-
-  if (ns && variable->global)
-    variable->name.insert(0, std::string(ns) + "::");
-
-  // The current code needs a variable name,
-  // generate a fake one:
-  static int mc_anonymous_variable_index = 0;
-  if (variable->name.empty()) {
-    variable->name = "@anonymous#" + std::to_string(mc_anonymous_variable_index);
-    mc_anonymous_variable_index++;
-  }
-  return variable;
-}
-
-static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, const Dwarf_Die* unit,
-                                         simgrid::mc::Frame* frame, const char* ns)
-{
-  std::unique_ptr<simgrid::mc::Variable> variable = MC_die_to_variable(info, die, unit, frame, ns);
-  if (not variable)
-    return;
-  // Those arrays are sorted later:
-  if (variable->global)
-    info->global_variables.push_back(std::move(*variable));
-  else if (frame != nullptr)
-    frame->variables.push_back(std::move(*variable));
-  else
-    xbt_die("No frame for this local variable");
-}
-
-static void MC_dwarf_handle_scope_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                      simgrid::mc::Frame* parent_frame, const char* ns)
-{
-  // TODO, handle DW_TAG_type/DW_TAG_location for DW_TAG_with_stmt
-  int tag                        = dwarf_tag(die);
-  simgrid::dwarf::TagClass klass = simgrid::dwarf::classify_tag(tag);
-
-  // (Template) Subprogram declaration:
-  if (klass == simgrid::dwarf::TagClass::Subprogram && MC_dwarf_attr_flag(die, DW_AT_declaration, false))
-    return;
-
-  if (klass == simgrid::dwarf::TagClass::Scope)
-    xbt_assert(parent_frame, "No parent scope for this scope");
-
-  simgrid::mc::Frame frame;
-  frame.tag         = tag;
-  frame.id          = dwarf_dieoffset(die);
-  frame.object_info = info;
-
-  if (klass == simgrid::dwarf::TagClass::Subprogram) {
-    const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
-    if (name && ns)
-      frame.name = std::string(ns) + "::" + name;
-    else if (name)
-      frame.name = name;
-  }
-
-  frame.abstract_origin_id = MC_dwarf_attr_integrate_dieoffset(die, DW_AT_abstract_origin);
-
-  // This is the base address for DWARF addresses.
-  // Relocated addresses are offset from this base address.
-  // See DWARF4 spec 7.5
-  auto base = reinterpret_cast<std::uint64_t>(info->base_address());
-
-  // TODO, support DW_AT_ranges
-  uint64_t low_pc     = MC_dwarf_attr_integrate_addr(die, DW_AT_low_pc);
-  frame.range.begin() = low_pc ? base + low_pc : 0;
-  if (low_pc) {
-    // DW_AT_high_pc:
-    Dwarf_Attribute attr;
-    xbt_assert(dwarf_attr_integrate(die, DW_AT_high_pc, &attr), "Missing DW_AT_high_pc matching with DW_AT_low_pc");
-
-    Dwarf_Sword offset;
-    Dwarf_Addr high_pc;
-
-    switch (simgrid::dwarf::classify_form(dwarf_whatform(&attr))) {
-      // DW_AT_high_pc if an offset from the low_pc:
-      case simgrid::dwarf::FormClass::Constant:
-
-        xbt_assert(dwarf_formsdata(&attr, &offset) == 0, "Could not read constant");
-        frame.range.end() = frame.range.begin() + offset;
-        break;
-
-        // DW_AT_high_pc is a relocatable address:
-      case simgrid::dwarf::FormClass::Address:
-        xbt_assert(dwarf_formaddr(&attr, &high_pc) == 0, "Could not read address");
-        frame.range.end() = base + high_pc;
-        break;
-
-      default:
-        xbt_die("Unexpected class for DW_AT_high_pc");
-    }
-  }
-
-  if (klass == simgrid::dwarf::TagClass::Subprogram) {
-    Dwarf_Attribute attr_frame_base;
-    if (dwarf_attr_integrate(die, DW_AT_frame_base, &attr_frame_base))
-      frame.frame_base_location = simgrid::dwarf::location_list(*info, attr_frame_base);
-  }
-
-  // Handle children:
-  MC_dwarf_handle_children(info, die, unit, &frame, ns);
-
-  // We sort them in order to have an (somewhat) efficient by name
-  // lookup:
-  boost::range::sort(frame.variables, MC_compare_variable);
-
-  // Register it:
-  if (klass == simgrid::dwarf::TagClass::Subprogram)
-    info->subprograms[frame.id] = std::move(frame);
-  else if (klass == simgrid::dwarf::TagClass::Scope)
-    parent_frame->scopes.push_back(std::move(frame));
-}
-
-static void mc_dwarf_handle_namespace_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                          simgrid::mc::Frame* frame, const char* ns)
-{
-  const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
-  xbt_assert(not frame, "Unexpected namespace in a subprogram");
-  char* new_ns = ns == nullptr ? xbt_strdup(name) : bprintf("%s::%s", ns, name);
-  MC_dwarf_handle_children(info, die, unit, frame, new_ns);
-  xbt_free(new_ns);
-}
-
-static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                     simgrid::mc::Frame* frame, const char* ns)
-{
-  // For each child DIE:
-  Dwarf_Die child;
-  for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child))
-    MC_dwarf_handle_die(info, &child, unit, frame, ns);
-}
-
-static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit,
-                                simgrid::mc::Frame* frame, const char* ns)
-{
-  int tag                        = dwarf_tag(die);
-  simgrid::dwarf::TagClass klass = simgrid::dwarf::classify_tag(tag);
-  switch (klass) {
-    // Type:
-    case simgrid::dwarf::TagClass::Type:
-      MC_dwarf_handle_type_die(info, die, unit, frame, ns);
-      break;
-
-      // Subprogram or scope:
-    case simgrid::dwarf::TagClass::Subprogram:
-    case simgrid::dwarf::TagClass::Scope:
-      MC_dwarf_handle_scope_die(info, die, unit, frame, ns);
-      return;
-
-      // Variable:
-    case simgrid::dwarf::TagClass::Variable:
-      MC_dwarf_handle_variable_die(info, die, unit, frame, ns);
-      break;
-
-    case simgrid::dwarf::TagClass::Namespace:
-      mc_dwarf_handle_namespace_die(info, die, unit, frame, ns);
-      break;
-
-    default:
-      break;
-  }
-}
-
-static Elf64_Half get_type(Elf* elf)
-{
-  if (const Elf64_Ehdr* ehdr64 = elf64_getehdr(elf))
-    return ehdr64->e_type;
-  if (const Elf32_Ehdr* ehdr32 = elf32_getehdr(elf))
-    return ehdr32->e_type;
-  xbt_die("Could not get ELF heeader");
-}
-
-static void read_dwarf_info(simgrid::mc::ObjectInformation* info, Dwarf* dwarf)
-{
-  // For each compilation unit:
-  Dwarf_Off offset      = 0;
-  Dwarf_Off next_offset = 0;
-  size_t length;
-
-  while (dwarf_nextcu(dwarf, offset, &next_offset, &length, nullptr, nullptr, nullptr) == 0) {
-    if (Dwarf_Die unit_die; dwarf_offdie(dwarf, offset + length, &unit_die) != nullptr)
-      MC_dwarf_handle_children(info, &unit_die, &unit_die, nullptr, nullptr);
-    offset = next_offset;
-  }
-}
-
-/** Get the build-id (NT_GNU_BUILD_ID) from the ELF file
- *
- *  This build-id may is used to locate an external debug (DWARF) file
- *  for this ELF file.
- *
- *  @param  elf libelf handle for an ELF file
- *  @return build-id for this ELF file (or an empty vector if none is found)
- */
-static std::vector<std::byte> get_build_id(Elf* elf)
-{
-#ifdef __linux
-  // Summary: the GNU build ID is stored in a ("GNU, NT_GNU_BUILD_ID) note
-  // found in a PT_NOTE entry in the program header table.
-
-  size_t phnum;
-  xbt_assert(elf_getphdrnum(elf, &phnum) == 0, "Could not read program headers");
-
-  // Iterate over the program headers and find the PT_NOTE ones:
-  for (size_t i = 0; i < phnum; ++i) {
-    GElf_Phdr phdr_temp;
-    const GElf_Phdr* phdr = gelf_getphdr(elf, i, &phdr_temp);
-    if (phdr->p_type != PT_NOTE)
-      continue;
-
-    Elf_Data* data = elf_getdata_rawchunk(elf, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR);
-
-    // Iterate over the notes and find the NT_GNU_BUILD_ID one:
-    size_t pos = 0;
-    while (pos < data->d_size) {
-      GElf_Nhdr nhdr;
-      // Location of the name within Elf_Data:
-      size_t name_pos;
-      size_t desc_pos;
-      pos = gelf_getnote(data, pos, &nhdr, &name_pos, &desc_pos);
-      // A build ID note is identified by the pair ("GNU", NT_GNU_BUILD_ID)
-      // (a namespace and a type within this namespace):
-      if (nhdr.n_type == NT_GNU_BUILD_ID && nhdr.n_namesz == sizeof("GNU") &&
-          memcmp(static_cast<std::byte*>(data->d_buf) + name_pos, "GNU", sizeof("GNU")) == 0) {
-        XBT_DEBUG("Found GNU/NT_GNU_BUILD_ID note");
-        std::byte* start = static_cast<std::byte*>(data->d_buf) + desc_pos;
-        std::byte* end   = start + nhdr.n_descsz;
-        return std::vector<std::byte>(start, end);
-      }
-    }
-  }
-#endif
-  return std::vector<std::byte>();
-}
-
-/** Binary data to hexadecimal */
-static inline std::array<char, 2> to_hex(std::byte byte)
-{
-  constexpr std::array<char, 16> hexdigits{
-      {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}};
-  return {hexdigits[std::to_integer<unsigned>(byte >> 4)], hexdigits[std::to_integer<unsigned>(byte & std::byte{0xF})]};
-}
-
-/** Binary data to hexadecimal */
-static std::string to_hex(const std::byte* data, std::size_t count)
-{
-  std::string res;
-  res.resize(2 * count);
-  for (std::size_t i = 0; i < count; i++)
-    std::copy_n(cbegin(to_hex(data[i])), 2, &res[2 * i]);
-  return res;
-}
-
-/** Binary data to hexadecimal */
-static std::string to_hex(std::vector<std::byte> const& data)
-{
-  return to_hex(data.data(), data.size());
-}
-
-/** Base directories for external debug files */
-static constexpr auto debug_paths = {
-    "/usr/lib/debug/",
-    "/usr/local/lib/debug/",
-};
-
-/** Locate an external debug file from the NT_GNU_BUILD_ID
- *
- *  This is one of the mechanisms used for
- *  [separate debug files](https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html).
- */
-// Example:
-// /usr/lib/debug/.build-id/0b/dc77f1c29aea2b14ff5acd9a19ab3175ffdeae.debug
-static int find_by_build_id(std::vector<std::byte> id)
-{
-  std::string filename;
-  std::string hex = to_hex(id);
-  for (const char* const& debug_path : debug_paths) {
-    // Example:
-    filename = std::string(debug_path) + ".build-id/" + to_hex(id.data(), 1) + '/' +
-               to_hex(id.data() + 1, id.size() - 1) + ".debug";
-    XBT_DEBUG("Checking debug file: %s", filename.c_str());
-    if (int fd = open(filename.c_str(), O_RDONLY); fd != -1) {
-      XBT_DEBUG("Found debug file: %s\n", hex.c_str());
-      return fd;
-    }
-    xbt_assert(errno != ENOENT, "Could not open file: %s", strerror(errno));
-  }
-  XBT_DEBUG("No debug info found for build ID %s\n", hex.data());
-  return -1;
-}
-
-/** @brief Populate the debugging information of the given ELF object
- *
- *  Read the DWARF information of the ELF object and populate the
- *  lists of types, variables, functions.
- */
-static void MC_load_dwarf(simgrid::mc::ObjectInformation* info)
-{
-  xbt_assert(elf_version(EV_CURRENT) != EV_NONE, "libelf initialization error");
-
-  // Open the ELF file:
-  int fd = open(info->file_name.c_str(), O_RDONLY);
-  xbt_assert(fd >= 0, "Could not open file %s", info->file_name.c_str());
-  Elf* elf = elf_begin(fd, ELF_C_READ, nullptr);
-  xbt_assert(elf != nullptr && elf_kind(elf) == ELF_K_ELF, "%s is not an ELF file", info->file_name.c_str());
-
-  // Remember if this is a `ET_EXEC` (fixed location) or `ET_DYN`:
-  if (get_type(elf) == ET_EXEC)
-    info->flags |= simgrid::mc::ObjectInformation::Executable;
-
-  // Read DWARF debug information in the file:
-  if (Dwarf* dwarf = dwarf_begin_elf(elf, DWARF_C_READ, nullptr)) {
-    read_dwarf_info(info, dwarf);
-    dwarf_end(dwarf);
-    elf_end(elf);
-    close(fd);
-    return;
-  }
-
-  // If there was no DWARF in the file, try to find it in a separate file.
-  // Different methods might be used to store the DWARF information:
-  //  * GNU NT_GNU_BUILD_ID
-  //  * .gnu_debuglink
-  // See https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
-  // for reference of what we are doing.
-
-  // Try with NT_GNU_BUILD_ID: we find the build ID in the ELF file and then
-  // use this ID to find the file in some known locations in the filesystem.
-  if (std::vector<std::byte> build_id = get_build_id(elf); not build_id.empty()) {
-    elf_end(elf);
-    close(fd);
-
-    // Find the debug file using the build id:
-    fd = find_by_build_id(build_id);
-    xbt_assert(fd != -1,
-               "Missing debug info for %s with build-id %s\n"
-               "You might want to install the suitable debugging package.\n",
-               info->file_name.c_str(), to_hex(build_id).c_str());
-
-    // Load the DWARF info from this file:
-    XBT_DEBUG("Load DWARF for %s", info->file_name.c_str());
-    Dwarf* dwarf = dwarf_begin(fd, DWARF_C_READ);
-    xbt_assert(dwarf != nullptr, "No DWARF info for %s", info->file_name.c_str());
-    read_dwarf_info(info, dwarf);
-    dwarf_end(dwarf);
-    close(fd);
-    return;
-  }
-
-  // TODO, try to find DWARF info using .gnu_debuglink.
-
-  elf_end(elf);
-  close(fd);
-  xbt_die("Debugging information not found for %s\n"
-          "Try recompiling with -g\n",
-          info->file_name.c_str());
-}
-
-// ***** Functions index
-
-static void MC_make_functions_index(simgrid::mc::ObjectInformation* info)
-{
-  info->functions_index.clear();
-
-  for (auto& [_, e] : info->subprograms) {
-    if (e.range.begin() == 0)
-      continue;
-    simgrid::mc::FunctionIndexEntry entry;
-    entry.low_pc   = (void*)e.range.begin();
-    entry.function = &e;
-    info->functions_index.push_back(entry);
-  }
-
-  info->functions_index.shrink_to_fit();
-
-  // Sort the array by low_pc:
-  boost::range::sort(info->functions_index,
-                     [](simgrid::mc::FunctionIndexEntry const& a, simgrid::mc::FunctionIndexEntry const& b) {
-                       return a.low_pc < b.low_pc;
-                     });
-}
-
-static void MC_post_process_variables(simgrid::mc::ObjectInformation* info)
-{
-  // Someone needs this to be sorted but who?
-  boost::range::sort(info->global_variables, MC_compare_variable);
-
-  for (simgrid::mc::Variable& variable : info->global_variables)
-    if (variable.type_id)
-      variable.type = simgrid::util::find_map_ptr(info->types, variable.type_id);
-}
-
-static void mc_post_process_scope(simgrid::mc::ObjectInformation* info, simgrid::mc::Frame* scope)
-{
-  if (scope->tag == DW_TAG_inlined_subroutine) {
-    // Attach correct namespaced name in inlined subroutine:
-    auto i = info->subprograms.find(scope->abstract_origin_id);
-    xbt_assert(i != info->subprograms.end(), "Could not lookup abstract origin %" PRIx64,
-               (std::uint64_t)scope->abstract_origin_id);
-    scope->name = i->second.name;
-  }
-
-  // Direct:
-  for (simgrid::mc::Variable& variable : scope->variables)
-    if (variable.type_id)
-      variable.type = simgrid::util::find_map_ptr(info->types, variable.type_id);
-
-  // Recursive post-processing of nested-scopes:
-  for (simgrid::mc::Frame& nested_scope : scope->scopes)
-    mc_post_process_scope(info, &nested_scope);
-}
-
-static simgrid::mc::Type* MC_resolve_type(simgrid::mc::ObjectInformation* info, unsigned type_id)
-{
-  if (not type_id)
-    return nullptr;
-  simgrid::mc::Type* type = simgrid::util::find_map_ptr(info->types, type_id);
-  if (type == nullptr)
-    return nullptr;
-
-  // We already have the information on the type:
-  if (type->byte_size != 0)
-    return type;
-
-  // Don't have a name, we can't find a more complete version:
-  if (type->name.empty())
-    return type;
-
-  // Try to find a more complete description of the type:
-  // We need to fix in order to support C++.
-  if (simgrid::mc::Type** subtype = simgrid::util::find_map_ptr(info->full_types_by_name, type->name))
-    type = *subtype;
-  return type;
-}
-
-static void MC_post_process_types(simgrid::mc::ObjectInformation* info)
-{
-  // Lookup "subtype" field:
-  for (auto& [_, i] : info->types) {
-    i.subtype = MC_resolve_type(info, i.type_id);
-    for (simgrid::mc::Member& member : i.members)
-      member.type = MC_resolve_type(info, member.type_id);
-  }
-}
-
-namespace simgrid::mc {
-
-void ObjectInformation::ensure_dwarf_loaded()
-{
-  if (dwarf_loaded)
-    return;
-  dwarf_loaded = true;
-
-  MC_load_dwarf(this);
-  MC_post_process_variables(this);
-  MC_post_process_types(this);
-  for (auto& [_, entry] : this->subprograms)
-    mc_post_process_scope(this, &entry);
-  MC_make_functions_index(this);
-}
-
-/** @brief Finds information about a given shared object/executable */
-std::shared_ptr<ObjectInformation> createObjectInformation(std::vector<xbt::VmMap> const& maps, const char* name)
-{
-  auto result       = std::make_shared<ObjectInformation>();
-  result->file_name = name;
-  simgrid::mc::find_object_address(maps, result.get());
-  return result;
-}
-
-/*************************************************************************/
-
-void postProcessObjectInformation(const RemoteProcessMemory* process, ObjectInformation* info)
-{
-  for (auto& [_, t] : info->types) {
-    Type* type    = &t;
-    Type* subtype = type;
-    while (subtype->type == DW_TAG_typedef || subtype->type == DW_TAG_volatile_type ||
-           subtype->type == DW_TAG_const_type)
-      if (subtype->subtype)
-        subtype = subtype->subtype;
-      else
-        break;
-
-    // Resolve full_type:
-    if (not subtype->name.empty() && subtype->byte_size == 0)
-      for (auto const& object_info : process->object_infos) {
-        auto i = object_info->full_types_by_name.find(subtype->name);
-        if (i != object_info->full_types_by_name.end() && not i->second->name.empty() && i->second->byte_size) {
-          type->full_type = i->second;
-          break;
-        }
-      }
-    else
-      type->full_type = subtype;
-  }
-}
-
-} // namespace simgrid::mc
-
-namespace simgrid::dwarf {
-
-/** Convert a DWARF register into a libunwind register
- *
- *  DWARF and libunwind does not use the same convention for numbering the
- *  registers on some architectures. The function makes the necessary
- *  conversion.
- */
-int dwarf_register_to_libunwind(int dwarf_register)
-{
-#if defined(__x86_64__) || defined(__aarch64__)
-  // It seems for this arch, DWARF and libunwind agree in the numbering:
-  return dwarf_register;
-#elif defined(__i386__)
-  // Couldn't find the authoritative source of information for this.
-  // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517.
-  constexpr std::array<int, 24> regs{
-      {/*  0 */ UNW_X86_EAX, /*  1 */ UNW_X86_ECX,    /*  2 */ UNW_X86_EDX, /*  3 */ UNW_X86_EBX,
-       /*  4 */ UNW_X86_ESP, /*  5 */ UNW_X86_EBP,    /*  6 */ UNW_X86_ESI, /*  7 */ UNW_X86_EDI,
-       /*  8 */ UNW_X86_EIP, /*  9 */ UNW_X86_EFLAGS, /* 10 */ UNW_X86_CS,  /* 11 */ UNW_X86_SS,
-       /* 12 */ UNW_X86_DS,  /* 13 */ UNW_X86_ES,     /* 14 */ UNW_X86_FS,  /* 15 */ UNW_X86_GS,
-       /* 16 */ UNW_X86_ST0, /* 17 */ UNW_X86_ST1,    /* 18 */ UNW_X86_ST2, /* 19 */ UNW_X86_ST3,
-       /* 20 */ UNW_X86_ST4, /* 21 */ UNW_X86_ST5,    /* 22 */ UNW_X86_ST6, /* 23 */ UNW_X86_ST7}};
-  return regs.at(dwarf_register);
-#else
-#error This architecture is not supported yet for DWARF expression evaluation.
-#endif
-}
-
-} // namespace simgrid::dwarf
diff --git a/src/mc/inspect/mc_dwarf.hpp b/src/mc/inspect/mc_dwarf.hpp
deleted file mode 100644 (file)
index 7575e1d..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_DWARF_HPP
-#define SIMGRID_MC_DWARF_HPP
-
-#include "xbt/base.h"
-
-#include "src/mc/mc_forward.hpp"
-
-namespace simgrid::dwarf {
-
-XBT_PRIVATE const char* attrname(int attr);
-XBT_PRIVATE const char* tagname(int tag);
-
-XBT_PRIVATE void* resolve_member(const void* base, const simgrid::mc::Type* type, const simgrid::mc::Member* member,
-                                 const simgrid::mc::AddressSpace* snapshot);
-
-XBT_PRIVATE
-int dwarf_register_to_libunwind(int dwarf_register);
-
-} // namespace simgrid::dwarf
-
-#endif
diff --git a/src/mc/inspect/mc_dwarf_attrnames.cpp b/src/mc/inspect/mc_dwarf_attrnames.cpp
deleted file mode 100644 (file)
index e050f46..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Warning: autogenerated, do not edit! */
-
-#include "src/mc/inspect/mc_dwarf.hpp"
-
-#include <string>
-#include <unordered_map>
-
-namespace {
-const std::unordered_map<int, const char*> attrname_map = {
-    {0x01, "DW_AT_sibling"},
-    {0x02, "DW_AT_location"},
-    {0x03, "DW_AT_name"},
-    {0x09, "DW_AT_ordering"},
-    {0x0a, "DW_AT_subscr_data"},
-    {0x0b, "DW_AT_byte_size"},
-    {0x0c, "DW_AT_bit_offset"},
-    {0x0d, "DW_AT_bit_size"},
-    {0x0f, "DW_AT_element_list"},
-    {0x10, "DW_AT_stmt_list"},
-    {0x11, "DW_AT_low_pc"},
-    {0x12, "DW_AT_high_pc"},
-    {0x13, "DW_AT_language"},
-    {0x14, "DW_AT_member"},
-    {0x15, "DW_AT_discr"},
-    {0x16, "DW_AT_discr_value"},
-    {0x17, "DW_AT_visibility"},
-    {0x18, "DW_AT_import"},
-    {0x19, "DW_AT_string_length"},
-    {0x1a, "DW_AT_common_reference"},
-    {0x1b, "DW_AT_comp_dir"},
-    {0x1c, "DW_AT_const_value"},
-    {0x1d, "DW_AT_containing_type"},
-    {0x1e, "DW_AT_default_value"},
-    {0x20, "DW_AT_inline"},
-    {0x21, "DW_AT_is_optional"},
-    {0x22, "DW_AT_lower_bound"},
-    {0x25, "DW_AT_producer"},
-    {0x27, "DW_AT_prototyped"},
-    {0x2a, "DW_AT_return_addr"},
-    {0x2c, "DW_AT_start_scope"},
-    {0x2e, "DW_AT_bit_stride"},
-    {0x2f, "DW_AT_upper_bound"},
-    {0x31, "DW_AT_abstract_origin"},
-    {0x32, "DW_AT_accessibility"},
-    {0x33, "DW_AT_address_class"},
-    {0x34, "DW_AT_artificial"},
-    {0x35, "DW_AT_base_types"},
-    {0x36, "DW_AT_calling_convention"},
-    {0x37, "DW_AT_count"},
-    {0x38, "DW_AT_data_member_location"},
-    {0x39, "DW_AT_decl_column"},
-    {0x3a, "DW_AT_decl_file"},
-    {0x3b, "DW_AT_decl_line"},
-    {0x3c, "DW_AT_declaration"},
-    {0x3d, "DW_AT_discr_list"},
-    {0x3e, "DW_AT_encoding"},
-    {0x3f, "DW_AT_external"},
-    {0x40, "DW_AT_frame_base"},
-    {0x41, "DW_AT_friend"},
-    {0x42, "DW_AT_identifier_case"},
-    {0x43, "DW_AT_macro_info"},
-    {0x44, "DW_AT_namelist_item"},
-    {0x45, "DW_AT_priority"},
-    {0x46, "DW_AT_segment"},
-    {0x47, "DW_AT_specification"},
-    {0x48, "DW_AT_static_link"},
-    {0x49, "DW_AT_type"},
-    {0x4a, "DW_AT_use_location"},
-    {0x4b, "DW_AT_variable_parameter"},
-    {0x4c, "DW_AT_virtuality"},
-    {0x4d, "DW_AT_vtable_elem_location"},
-    {0x4e, "DW_AT_allocated"},
-    {0x4f, "DW_AT_associated"},
-    {0x50, "DW_AT_data_location"},
-    {0x51, "DW_AT_byte_stride"},
-    {0x52, "DW_AT_entry_pc"},
-    {0x53, "DW_AT_use_UTF8"},
-    {0x54, "DW_AT_extension"},
-    {0x55, "DW_AT_ranges"},
-    {0x56, "DW_AT_trampoline"},
-    {0x57, "DW_AT_call_column"},
-    {0x58, "DW_AT_call_file"},
-    {0x59, "DW_AT_call_line"},
-    {0x5a, "DW_AT_description"},
-    {0x5b, "DW_AT_binary_scale"},
-    {0x5c, "DW_AT_decimal_scale"},
-    {0x5d, "DW_AT_small"},
-    {0x5e, "DW_AT_decimal_sign"},
-    {0x5f, "DW_AT_digit_count"},
-    {0x60, "DW_AT_picture_string"},
-    {0x61, "DW_AT_mutable"},
-    {0x62, "DW_AT_threads_scaled"},
-    {0x63, "DW_AT_explicit"},
-    {0x64, "DW_AT_object_pointer"},
-    {0x65, "DW_AT_endianity"},
-    {0x66, "DW_AT_elemental"},
-    {0x67, "DW_AT_pure"},
-    {0x68, "DW_AT_recursive"},
-    {0x69, "DW_AT_signature"},
-    {0x6a, "DW_AT_main_subprogram"},
-    {0x6b, "DW_AT_data_bit_offset"},
-    {0x6c, "DW_AT_const_expr"},
-    {0x6d, "DW_AT_enum_class"},
-    {0x6e, "DW_AT_linkage_name"},
-    {0x87, "DW_AT_noreturn"},
-    {0x2000, "DW_AT_lo_user"},
-    {0x2001, "DW_AT_MIPS_fde"},
-    {0x2002, "DW_AT_MIPS_loop_begin"},
-    {0x2003, "DW_AT_MIPS_tail_loop_begin"},
-    {0x2004, "DW_AT_MIPS_epilog_begin"},
-    {0x2005, "DW_AT_MIPS_loop_unroll_factor"},
-    {0x2006, "DW_AT_MIPS_software_pipeline_depth"},
-    {0x2007, "DW_AT_MIPS_linkage_name"},
-    {0x2008, "DW_AT_MIPS_stride"},
-    {0x2009, "DW_AT_MIPS_abstract_name"},
-    {0x200a, "DW_AT_MIPS_clone_origin"},
-    {0x200b, "DW_AT_MIPS_has_inlines"},
-    {0x200c, "DW_AT_MIPS_stride_byte"},
-    {0x200d, "DW_AT_MIPS_stride_elem"},
-    {0x200e, "DW_AT_MIPS_ptr_dopetype"},
-    {0x200f, "DW_AT_MIPS_allocatable_dopetype"},
-    {0x2010, "DW_AT_MIPS_assumed_shape_dopetype"},
-    {0x2011, "DW_AT_MIPS_assumed_size"},
-    {0x2101, "DW_AT_sf_names"},
-    {0x2102, "DW_AT_src_info"},
-    {0x2103, "DW_AT_mac_info"},
-    {0x2104, "DW_AT_src_coords"},
-    {0x2105, "DW_AT_body_begin"},
-    {0x2106, "DW_AT_body_end"},
-    {0x2107, "DW_AT_GNU_vector"},
-    {0x2108, "DW_AT_GNU_guarded_by"},
-    {0x2109, "DW_AT_GNU_pt_guarded_by"},
-    {0x210a, "DW_AT_GNU_guarded"},
-    {0x210b, "DW_AT_GNU_pt_guarded"},
-    {0x210c, "DW_AT_GNU_locks_excluded"},
-    {0x210d, "DW_AT_GNU_exclusive_locks_required"},
-    {0x210e, "DW_AT_GNU_shared_locks_required"},
-    {0x210f, "DW_AT_GNU_odr_signature"},
-    {0x2110, "DW_AT_GNU_template_name"},
-    {0x2111, "DW_AT_GNU_call_site_value"},
-    {0x2112, "DW_AT_GNU_call_site_data_value"},
-    {0x2113, "DW_AT_GNU_call_site_target"},
-    {0x2114, "DW_AT_GNU_call_site_target_clobbered"},
-    {0x2115, "DW_AT_GNU_tail_call"},
-    {0x2116, "DW_AT_GNU_all_tail_call_sites"},
-    {0x2117, "DW_AT_GNU_all_call_sites"},
-    {0x2118, "DW_AT_GNU_all_source_call_sites"},
-    {0x2119, "DW_AT_GNU_macros"},
-    {0x211a, "DW_AT_GNU_deleted"},
-    {0x3fff, "DW_AT_hi_user"},
-};
-}
-
-namespace simgrid::dwarf {
-
-/** @brief Get the name of an attribute (DW_AT_*) from its code
- *
- *  @param attr attribute code (see the DWARF specification)
- *  @return name of the attribute
- */
-XBT_PRIVATE
-const char* attrname(int attr)
-{
-  auto name = attrname_map.find(attr);
-  return name == attrname_map.end() ? "DW_AT_unknown" : name->second;
-}
-
-} // namespace simgrid::dwarf
diff --git a/src/mc/inspect/mc_dwarf_tagnames.cpp b/src/mc/inspect/mc_dwarf_tagnames.cpp
deleted file mode 100644 (file)
index 0fcd49f..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Warning: autogenerated, do not edit! */
-
-#include "src/mc/inspect/mc_dwarf.hpp"
-
-#include <string>
-#include <unordered_map>
-
-namespace {
-const std::unordered_map<int, const char*> tagname_map = {
-    {0x00, "DW_TAG_invalid"},
-    {0x01, "DW_TAG_array_type"},
-    {0x02, "DW_TAG_class_type"},
-    {0x03, "DW_TAG_entry_point"},
-    {0x04, "DW_TAG_enumeration_type"},
-    {0x05, "DW_TAG_formal_parameter"},
-    {0x08, "DW_TAG_imported_declaration"},
-    {0x0a, "DW_TAG_label"},
-    {0x0b, "DW_TAG_lexical_block"},
-    {0x0d, "DW_TAG_member"},
-    {0x0f, "DW_TAG_pointer_type"},
-    {0x10, "DW_TAG_reference_type"},
-    {0x11, "DW_TAG_compile_unit"},
-    {0x12, "DW_TAG_string_type"},
-    {0x13, "DW_TAG_structure_type"},
-    {0x15, "DW_TAG_subroutine_type"},
-    {0x16, "DW_TAG_typedef"},
-    {0x17, "DW_TAG_union_type"},
-    {0x18, "DW_TAG_unspecified_parameters"},
-    {0x19, "DW_TAG_variant"},
-    {0x1a, "DW_TAG_common_block"},
-    {0x1b, "DW_TAG_common_inclusion"},
-    {0x1c, "DW_TAG_inheritance"},
-    {0x1d, "DW_TAG_inlined_subroutine"},
-    {0x1e, "DW_TAG_module"},
-    {0x1f, "DW_TAG_ptr_to_member_type"},
-    {0x20, "DW_TAG_set_type"},
-    {0x21, "DW_TAG_subrange_type"},
-    {0x22, "DW_TAG_with_stmt"},
-    {0x23, "DW_TAG_access_declaration"},
-    {0x24, "DW_TAG_base_type"},
-    {0x25, "DW_TAG_catch_block"},
-    {0x26, "DW_TAG_const_type"},
-    {0x27, "DW_TAG_constant"},
-    {0x28, "DW_TAG_enumerator"},
-    {0x29, "DW_TAG_file_type"},
-    {0x2a, "DW_TAG_friend"},
-    {0x2b, "DW_TAG_namelist"},
-    {0x2c, "DW_TAG_namelist_item"},
-    {0x2d, "DW_TAG_packed_type"},
-    {0x2e, "DW_TAG_subprogram"},
-    {0x2f, "DW_TAG_template_type_parameter"},
-    {0x30, "DW_TAG_template_value_parameter"},
-    {0x31, "DW_TAG_thrown_type"},
-    {0x32, "DW_TAG_try_block"},
-    {0x33, "DW_TAG_variant_part"},
-    {0x34, "DW_TAG_variable"},
-    {0x35, "DW_TAG_volatile_type"},
-    {0x36, "DW_TAG_dwarf_procedure"},
-    {0x37, "DW_TAG_restrict_type"},
-    {0x38, "DW_TAG_interface_type"},
-    {0x39, "DW_TAG_namespace"},
-    {0x3a, "DW_TAG_imported_module"},
-    {0x3b, "DW_TAG_unspecified_type"},
-    {0x3c, "DW_TAG_partial_unit"},
-    {0x3d, "DW_TAG_imported_unit"},
-    {0x3f, "DW_TAG_condition"},
-    {0x40, "DW_TAG_shared_type"},
-    {0x41, "DW_TAG_type_unit"},
-    {0x42, "DW_TAG_rvalue_reference_type"},
-    {0x43, "DW_TAG_template_alias"},
-    {0x47, "DW_TAG_atomic_type"},
-    {0x4080, "DW_TAG_lo_user"},
-    {0x4081, "DW_TAG_MIPS_loop"},
-    {0x4101, "DW_TAG_format_label"},
-    {0x4102, "DW_TAG_function_template"},
-    {0x4103, "DW_TAG_class_template"},
-    {0x4104, "DW_TAG_GNU_BINCL"},
-    {0x4105, "DW_TAG_GNU_EINCL"},
-    {0x4106, "DW_TAG_GNU_template_template_param"},
-    {0x4107, "DW_TAG_GNU_template_parameter_pack"},
-    {0x4108, "DW_TAG_GNU_formal_parameter_pack"},
-    {0x4109, "DW_TAG_GNU_call_site"},
-    {0x410a, "DW_TAG_GNU_call_site_parameter"},
-    {0xffff, "DW_TAG_hi_user"},
-};
-}
-
-namespace simgrid::dwarf {
-
-/** @brief Get the name of a dwarf tag (DW_TAG_*) from its code
- *
- *  @param tag tag code (see the DWARF specification)
- *  @return name of the tag
- */
-XBT_PRIVATE
-const char* tagname(int tag)
-{
-  auto name = tagname_map.find(tag);
-  return name == tagname_map.end() ? "DW_TAG_unknown" : name->second;
-}
-
-} // namespace simgrid::dwarf
diff --git a/src/mc/inspect/mc_member.cpp b/src/mc/inspect/mc_member.cpp
deleted file mode 100644 (file)
index 9e9af73..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/inspect/Type.hpp"
-#include "src/mc/inspect/mc_dwarf.hpp"
-#include "src/mc/mc_private.hpp"
-
-namespace simgrid::dwarf {
-
-/** Resolve snapshot in the process address space
- *
- * @param object   Process address of the struct/class
- * @param type     Type of the struct/class
- * @param member   Member description
- * @param snapshot Snapshot (or nullptr)
- * @return Process address of the given member of the 'object' struct/class
- */
-void* resolve_member(const void* base, const simgrid::mc::Type* /*type*/, const simgrid::mc::Member* member,
-                     const simgrid::mc::AddressSpace* address_space)
-{
-  ExpressionContext state;
-  state.address_space = address_space;
-
-  ExpressionStack stack;
-  stack.push((ExpressionStack::value_type)base);
-  simgrid::dwarf::execute(member->location_expression, state, stack);
-  return (void*)stack.top();
-}
-
-} // namespace simgrid::dwarf
diff --git a/src/mc/inspect/mc_unw.cpp b/src/mc/inspect/mc_unw.cpp
deleted file mode 100644 (file)
index d9882f0..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/** \file Libunwind support for mc_address_space objects. */
-
-// We need this for the register indices:
-// #define _GNU_SOURCE
-
-#include "src/mc/inspect/mc_unw.hpp"
-#include "src/mc/inspect/Frame.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-
-#include <cstring>
-
-// On x86_64, libunwind unw_context_t has the same layout as ucontext_t:
-#include <sys/types.h>
-#include <sys/ucontext.h>
-#ifdef __FreeBSD__
-typedef register_t greg_t;
-#endif
-
-#include <libunwind.h>
-
-namespace simgrid::mc {
-
-// ***** Implementation
-
-/** Get frame unwind information (libunwind method)
- *
- *  Delegates to the local/ptrace implementation.
- */
-int UnwindContext::find_proc_info(unw_addr_space_t /*as*/, unw_word_t ip, unw_proc_info_t* pip, int need_unwind_info,
-                                  void* arg) noexcept
-{
-  const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
-  return unw_get_accessors(context->process_->unw_underlying_addr_space)
-      ->find_proc_info(context->process_->unw_underlying_addr_space, ip, pip, need_unwind_info,
-                       context->process_->unw_underlying_context);
-}
-
-/** Release frame unwind information (libunwind method)
- *
- *  Delegates to the local/ptrace implementation.
- */
-void UnwindContext::put_unwind_info(unw_addr_space_t /*as*/, unw_proc_info_t* pip, void* arg) noexcept
-{
-  const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
-  return unw_get_accessors(context->process_->unw_underlying_addr_space)
-      ->put_unwind_info(context->process_->unw_underlying_addr_space, pip, context->process_->unw_underlying_context);
-}
-
-/** (libunwind method)
- *
- *  Not implemented.
- */
-int UnwindContext::get_dyn_info_list_addr(unw_addr_space_t /*as*/, unw_word_t* dilap, void* arg) noexcept
-{
-  const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
-  return unw_get_accessors(context->process_->unw_underlying_addr_space)
-      ->get_dyn_info_list_addr(context->process_->unw_underlying_addr_space, dilap,
-                               context->process_->unw_underlying_context);
-}
-
-/** Read from the target address space memory (libunwind method)
- *
- *  Delegates to the `simgrid::mc::Process*`.
- */
-int UnwindContext::access_mem(unw_addr_space_t /*as*/, unw_word_t addr, unw_word_t* valp, int write, void* arg) noexcept
-{
-  const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
-  if (write)
-    return -UNW_EREADONLYREG;
-  context->address_space_->read_bytes(valp, sizeof(unw_word_t), remote(addr));
-  return 0;
-}
-
-void* UnwindContext::get_reg(unw_context_t* context, unw_regnum_t regnum) noexcept
-{
-#ifdef __x86_64
-  mcontext_t* mcontext = &context->uc_mcontext;
-  switch (regnum) {
-#ifdef __linux__
-    case UNW_X86_64_RAX:
-      return &mcontext->gregs[REG_RAX];
-    case UNW_X86_64_RDX:
-      return &mcontext->gregs[REG_RDX];
-    case UNW_X86_64_RCX:
-      return &mcontext->gregs[REG_RCX];
-    case UNW_X86_64_RBX:
-      return &mcontext->gregs[REG_RBX];
-    case UNW_X86_64_RSI:
-      return &mcontext->gregs[REG_RSI];
-    case UNW_X86_64_RDI:
-      return &mcontext->gregs[REG_RDI];
-    case UNW_X86_64_RBP:
-      return &mcontext->gregs[REG_RBP];
-    case UNW_X86_64_RSP:
-      return &mcontext->gregs[REG_RSP];
-    case UNW_X86_64_R8:
-      return &mcontext->gregs[REG_R8];
-    case UNW_X86_64_R9:
-      return &mcontext->gregs[REG_R9];
-    case UNW_X86_64_R10:
-      return &mcontext->gregs[REG_R10];
-    case UNW_X86_64_R11:
-      return &mcontext->gregs[REG_R11];
-    case UNW_X86_64_R12:
-      return &mcontext->gregs[REG_R12];
-    case UNW_X86_64_R13:
-      return &mcontext->gregs[REG_R13];
-    case UNW_X86_64_R14:
-      return &mcontext->gregs[REG_R14];
-    case UNW_X86_64_R15:
-      return &mcontext->gregs[REG_R15];
-    case UNW_X86_64_RIP:
-      return &mcontext->gregs[REG_RIP];
-#elif defined __FreeBSD__
-    case UNW_X86_64_RAX:
-      return &mcontext->mc_rax;
-    case UNW_X86_64_RDX:
-      return &mcontext->mc_rdx;
-    case UNW_X86_64_RCX:
-      return &mcontext->mc_rcx;
-    case UNW_X86_64_RBX:
-      return &mcontext->mc_rbx;
-    case UNW_X86_64_RSI:
-      return &mcontext->mc_rsi;
-    case UNW_X86_64_RDI:
-      return &mcontext->mc_rdi;
-    case UNW_X86_64_RBP:
-      return &mcontext->mc_rbp;
-    case UNW_X86_64_RSP:
-      return &mcontext->mc_rsp;
-    case UNW_X86_64_R8:
-      return &mcontext->mc_r8;
-    case UNW_X86_64_R9:
-      return &mcontext->mc_r9;
-    case UNW_X86_64_R10:
-      return &mcontext->mc_r10;
-    case UNW_X86_64_R11:
-      return &mcontext->mc_r11;
-    case UNW_X86_64_R12:
-      return &mcontext->mc_r12;
-    case UNW_X86_64_R13:
-      return &mcontext->mc_r13;
-    case UNW_X86_64_R14:
-      return &mcontext->mc_r14;
-    case UNW_X86_64_R15:
-      return &mcontext->mc_r15;
-    case UNW_X86_64_RIP:
-      return &mcontext->mc_rip;
-#else
-#error "Unable to get register from ucontext, please add your case"
-#endif
-    default:
-      return nullptr;
-  }
-#else
-  return nullptr;
-#endif
-}
-
-/** Read a standard register (libunwind method)
- */
-int UnwindContext::access_reg(unw_addr_space_t /*as*/, unw_regnum_t regnum, unw_word_t* valp, int write,
-                              void* arg) noexcept
-{
-  auto* as_context       = static_cast<simgrid::mc::UnwindContext*>(arg);
-  unw_context_t* context = &as_context->unwind_context_;
-  if (write)
-    return -UNW_EREADONLYREG;
-  const greg_t* preg = (greg_t*)get_reg(context, regnum);
-  if (not preg)
-    return -UNW_EBADREG;
-  *valp = *preg;
-  return 0;
-}
-
-/** Find information about a function (libunwind method)
- */
-int UnwindContext::get_proc_name(unw_addr_space_t /*as*/, unw_word_t addr, char* bufp, size_t buf_len, unw_word_t* offp,
-                                 void* arg) noexcept
-{
-  const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg;
-  const simgrid::mc::Frame* frame           = context->process_->find_function(remote(addr));
-  if (not frame)
-    return -UNW_ENOINFO;
-  *offp = (unw_word_t)frame->range.begin() - addr;
-
-  strncpy(bufp, frame->name.c_str(), buf_len);
-  if (bufp[buf_len - 1]) {
-    bufp[buf_len - 1] = 0;
-    return -UNW_ENOMEM;
-  }
-
-  return 0;
-}
-
-// ***** Init
-
-unw_addr_space_t UnwindContext::createUnwindAddressSpace()
-{
-  /** Virtual table for our `libunwind` implementation
-   *
-   *  Stack unwinding on a `simgrid::mc::Process*` (for memory, unwinding information)
-   *  and `ucontext_t` (for processor registers).
-   *
-   * It works with the `simgrid::mc::UnwindContext` context.
-   *
-   * Use nullptr as access_fpreg and resume, as we don't need them.
-   */
-  unw_accessors_t accessors = {&find_proc_info, &put_unwind_info, &get_dyn_info_list_addr, &access_mem, &access_reg,
-                               nullptr,         nullptr,          &get_proc_name};
-  return unw_create_addr_space(&accessors, BYTE_ORDER);
-}
-
-void UnwindContext::initialize(simgrid::mc::RemoteProcessMemory& process_memory, unw_context_t* c)
-{
-  this->address_space_ = &process_memory;
-  this->process_       = &process_memory;
-
-  // Take a copy of the context for our own purpose:
-  this->unwind_context_ = *c;
-#if SIMGRID_PROCESSOR_x86_64 || SIMGRID_PROCESSOR_i686
-#ifdef __linux__
-  // On x86_64, ucontext_t contains a pointer to itself for FP registers.
-  // We don't really need support for FR registers as they are caller saved
-  // and probably never use those fields as libunwind-x86_64 does not read
-  // FP registers from the unw_context_t
-  // Let's ignore this and see what happens:
-  this->unwind_context_.uc_mcontext.fpregs = nullptr;
-#endif
-#elif SIMGRID_PROCESSOR_arm64
-#ifdef __linux__
-  // On ARM64, ucontext_t doesn't contain `fpregs` and the FP registers
-  // are instead held in the `__reserved` field of the struct. It doesn't
-  // appear anything needs to be done here, although this should be verified
-#endif
-#else
-  // Do we need to do any fixup like this?
-#error Target CPU type is not handled.
-#endif
-}
-
-unw_cursor_t UnwindContext::cursor()
-{
-  unw_cursor_t cursor;
-  xbt_assert(process_ != nullptr && address_space_ != nullptr &&
-                 unw_init_remote(&cursor, process_->unw_addr_space, this) == 0,
-             "UnwindContext not initialized");
-  return cursor;
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/inspect/mc_unw.hpp b/src/mc/inspect/mc_unw.hpp
deleted file mode 100644 (file)
index 7b9babb..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_UNW_HPP
-#define SIMGRID_MC_UNW_HPP
-
-/** @file
- *  Libunwind implementation for the model-checker
- *
- *  Libunwind provides a pluggable stack unwinding API: the way the current
- *  registers and memory is accessed, the way unwinding information is found
- *  is pluggable.
- *
- *  This component implements the libunwind API for he model-checker:
- *
- *    * reading memory from a simgrid::mc::AddressSpace*;
- *
- *    * reading stack registers from a saved snapshot (context).
- *
- *  Parts of the libunwind information fetching is currently handled by the
- *  standard `libunwind` implementations (either the local one or the ptrace one)
- *  because parsing `.eh_frame` section is not fun and `libdw` does not help
- *  much here.
- */
-
-#include "src/mc/mc_forward.hpp"
-#include "xbt/base.h"
-
-#include <cstdio>
-#include <libunwind.h>
-
-namespace simgrid::unw {
-
-XBT_PRIVATE unw_addr_space_t create_addr_space();
-XBT_PRIVATE void* create_context(unw_addr_space_t as, pid_t pid);
-} // namespace simgrid::unw
-
-namespace simgrid::mc {
-
-class UnwindContext {
-  simgrid::mc::AddressSpace* address_space_  = nullptr;
-  simgrid::mc::RemoteProcessMemory* process_ = nullptr;
-  unw_context_t unwind_context_              = {};
-
-public:
-  void initialize(simgrid::mc::RemoteProcessMemory& process, unw_context_t* c);
-  unw_cursor_t cursor();
-
-private: // Methods and virtual table for libunwind
-  static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t* pip, int need_unwind_info,
-                            void* arg) noexcept;
-  static void put_unwind_info(unw_addr_space_t as, unw_proc_info_t* pip, void* arg) noexcept;
-  static int get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t* dilap, void* arg) noexcept;
-  static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t* valp, int write, void* arg) noexcept;
-  static void* get_reg(unw_context_t* context, unw_regnum_t regnum) noexcept;
-  static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t* valp, int write, void* arg) noexcept;
-  static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char* bufp, size_t buf_len, unw_word_t* offp,
-                           void* arg) noexcept;
-
-public:
-  // Create a libunwind address space:
-  static unw_addr_space_t createUnwindAddressSpace();
-};
-
-void dumpStack(FILE* file, unw_cursor_t* cursor);
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/inspect/mc_unw_vmread.cpp b/src/mc/inspect/mc_unw_vmread.cpp
deleted file mode 100644 (file)
index 21fc478..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/** \file  Libunwind namespace implementation using process_vm_readv.       */
-
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/inspect/mc_unw.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include <fcntl.h>
-#include <libunwind-ptrace.h>
-#include <libunwind.h>
-
-
-/** Partial structure of libunwind-ptrace context in order to get the PID
- *
- *  HACK, The context type for libunwind-race is an opaque type.
- *  We need to get the PID which is the first field. This is a hack
- *  which might break if the libunwind-ptrace structure changes.
- */
-struct _UPT_info {
-  pid_t pid;
-  // Other things...
-};
-
-/** Read from the memory, avoid using `ptrace` (libunwind method) */
-static int access_mem(const unw_addr_space_t as, const unw_word_t addr, unw_word_t* const valp, const int write,
-                      void* const arg)
-{
-  if (write)
-    return -UNW_EINVAL;
-  pid_t pid   = static_cast<_UPT_info*>(arg)->pid;
-  size_t size = sizeof(unw_word_t);
-
-#if HAVE_PROCESS_VM_READV /* linux but not freebsd */
-  // process_vm_read implementation.
-  // This is only available since Linux 3.2.
-
-  struct iovec local  = {valp, size};
-  struct iovec remote = {(void*)addr, size};
-  if (ssize_t s = process_vm_readv(pid, &local, 1, &remote, 1, 0); s >= 0) {
-    if ((size_t)s != size)
-      return -UNW_EINVAL;
-    else
-      return 0;
-  } else if (errno != ENOSYS) {
-    return -UNW_EINVAL;
-  }
-#endif
-
-  // /proc/${pid}/mem implementation.
-  // On recent kernels, we do not need to ptrace the target process.
-  // On older kernels, it is necessary to ptrace the target process.
-  size_t count = size;
-  auto off     = static_cast<off_t>(addr);
-  auto* buf    = reinterpret_cast<std::byte*>(valp);
-  int fd       = simgrid::mc::open_vm(pid, O_RDONLY);
-  if (fd < 0)
-    return -UNW_EINVAL;
-
-  while (count > 0) {
-    ssize_t nread = pread(fd, buf, count, off);
-    if (nread == 0) {
-      close(fd);
-      return -UNW_EINVAL;
-    }
-    if (nread == -1)
-      // ptrace implementation.
-      // We need to have PTRACE_ATTACH-ed it before.
-      return _UPT_access_mem(as, addr, valp, write, arg);
-
-    count -= nread;
-    buf += nread;
-    off += nread;
-  }
-  close(fd);
-  return 0;
-}
-
-namespace simgrid::unw {
-
-unw_addr_space_t create_addr_space()
-{
-  /** Virtual table for our `libunwind-process_vm_readv` implementation.
-   *
-   *  This implementation reuse most the code of `libunwind-ptrace` but
-   *  does not use ptrace() to read the target process memory by
-   *  `process_vm_readv()` or `/dev/${pid}/mem` if possible.
-   *
-   *  Does not support any MC-specific behavior (privatization, snapshots)
-   *  and `ucontext_t`.
-   *
-   *  It works with `void*` contexts allocated with `_UPT_create(pid)`.
-   */
-  // TODO, we could get rid of this if we properly stop the model-checked
-  // process before reading the memory.
-  unw_accessors_t accessors = {&_UPT_find_proc_info, &_UPT_put_unwind_info, &_UPT_get_dyn_info_list_addr,
-                               &access_mem,          &_UPT_access_reg,      &_UPT_access_fpreg,
-                               &_UPT_resume,         &_UPT_get_proc_name};
-  return unw_create_addr_space(&accessors, BYTE_ORDER);
-}
-
-void* create_context(unw_addr_space_t /*as*/, pid_t pid)
-{
-  return _UPT_create(pid);
-}
-
-} // namespace simgrid::unw
index acd042d..9791f51 100644 (file)
@@ -8,16 +8,11 @@
 #include "src/kernel/activity/CommImpl.hpp"
 #include "src/kernel/activity/MutexImpl.hpp"
 #include "src/kernel/actor/SimcallObserver.hpp"
+
 #include "src/mc/mc.h"
 #include "src/mc/mc_config.hpp"
 #include "src/mc/mc_replay.hpp"
 
-#if SIMGRID_HAVE_MC
-#include "src/mc/api/RemoteApp.hpp"
-#include "src/mc/remote/AppSide.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-#endif
-
 XBT_LOG_NEW_DEFAULT_CATEGORY(mc, "All MC categories");
 bool simgrid_mc_replay_show_backtraces = false;
 
@@ -52,10 +47,8 @@ void execute_actors()
  */
 bool actor_is_enabled(kernel::actor::ActorImpl* actor)
 {
-#if SIMGRID_HAVE_MC
-  xbt_assert(simgrid::mc::model_checking_mode != simgrid::mc::ModelCheckingMode::CHECKER_SIDE,
+  xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE,
              "This should be called from the client side");
-#endif
 
   // Now, we are in the client app, no need for remote memory reading.
   kernel::actor::Simcall* req = &actor->simcall_;
@@ -75,10 +68,9 @@ bool actor_is_enabled(kernel::actor::ActorImpl* actor)
  */
 bool request_is_visible(const kernel::actor::Simcall* req)
 {
-#if SIMGRID_HAVE_MC
-  xbt_assert(simgrid::mc::model_checking_mode != simgrid::mc::ModelCheckingMode::CHECKER_SIDE,
+  xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE,
              "This should be called from the client side");
-#endif
+
   if (req->observer_ == nullptr)
     return false;
   return req->observer_->is_visible();
index c257a76..27e471d 100644 (file)
 #include "xbt/asserts.h"
 #include "xbt/random.hpp"
 
+using namespace simgrid::mc;
+
 /* Implementation of the user API from the App to the Checker (see modelchecker.h)  */
 
 int MC_random(int min, int max)
 {
-#if SIMGRID_HAVE_MC
-  xbt_assert(simgrid::mc::model_checking_mode != simgrid::mc::ModelCheckingMode::CHECKER_SIDE,
+  xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE,
              "This should be called from the client side");
-#endif
+
   if (not MC_is_active() && not MC_record_replay_is_active()) { // no need to do a simcall in this case
     static simgrid::xbt::random::XbtRandom prng;
     return prng.uniform_int(min, max);
@@ -32,12 +33,12 @@ int MC_random(int min, int max)
 void MC_assert(int prop)
 {
   // Cannot used xbt_assert here, or it would be an infinite recursion.
-#if SIMGRID_HAVE_MC
-  xbt_assert(simgrid::mc::model_checking_mode != simgrid::mc::ModelCheckingMode::CHECKER_SIDE,
+  xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE,
              "This should be called from the client side");
+#if SIMGRID_HAVE_MC
   if (not prop) {
     if (MC_is_active())
-      simgrid::mc::AppSide::get()->report_assertion_failure();
+      AppSide::get()->report_assertion_failure();
     if (MC_record_replay_is_active())
       xbt_die("MC assertion failed");
   }
@@ -49,42 +50,6 @@ void MC_assert(int prop)
 
 int MC_is_active()
 {
-  return simgrid::mc::model_checking_mode == simgrid::mc::ModelCheckingMode::APP_SIDE ||
-         simgrid::mc::model_checking_mode == simgrid::mc::ModelCheckingMode::CHECKER_SIDE;
-}
-
-void MC_automaton_new_propositional_symbol_pointer(const char *name, int* value)
-{
-#if SIMGRID_HAVE_MC
-  xbt_assert(simgrid::mc::model_checking_mode != simgrid::mc::ModelCheckingMode::CHECKER_SIDE,
-             "This should be called from the client side");
-  simgrid::mc::AppSide::get()->declare_symbol(name, value);
-#endif
-}
-
-void MC_ignore(void* addr, size_t size)
-{
-#if SIMGRID_HAVE_MC
-  xbt_assert(simgrid::mc::model_checking_mode != simgrid::mc::ModelCheckingMode::CHECKER_SIDE,
-             "This should be called from the client side");
-  simgrid::mc::AppSide::get()->ignore_memory(addr, size);
-#endif
-}
-
-void MC_ignore_heap(void *address, size_t size)
-{
-#if SIMGRID_HAVE_MC
-  xbt_assert(simgrid::mc::model_checking_mode != simgrid::mc::ModelCheckingMode::CHECKER_SIDE,
-             "This should be called from the client side");
-  simgrid::mc::AppSide::get()->ignore_heap(address, size);
-#endif
-}
-
-void MC_unignore_heap(void* address, size_t size)
-{
-#if SIMGRID_HAVE_MC
-  xbt_assert(simgrid::mc::model_checking_mode != simgrid::mc::ModelCheckingMode::CHECKER_SIDE,
-             "This should be called from the client side");
-  simgrid::mc::AppSide::get()->unignore_heap(address, size);
-#endif
+  return get_model_checking_mode() == ModelCheckingMode::APP_SIDE ||
+         get_model_checking_mode() == ModelCheckingMode::CHECKER_SIDE;
 }
index 3416d5c..25f3090 100644 (file)
@@ -8,77 +8,73 @@
 #include "src/simgrid/sg_config.hpp"
 #include <simgrid/modelchecker.h>
 
-#if SIMGRID_HAVE_MC
-#include <string_view>
-#endif
-
 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg);
 
-simgrid::mc::ModelCheckingMode simgrid::mc::model_checking_mode = simgrid::mc::ModelCheckingMode::NONE;
+static simgrid::mc::ModelCheckingMode model_checking_mode = simgrid::mc::ModelCheckingMode::NONE;
+simgrid::mc::ModelCheckingMode simgrid::mc::get_model_checking_mode()
+{
+  return model_checking_mode;
+}
+void simgrid::mc::set_model_checking_mode(simgrid::mc::ModelCheckingMode mode)
+{
+  model_checking_mode = mode;
+}
 
 static void _mc_cfg_cb_check(const char* spec, bool more_check = true)
 {
-#if SIMGRID_HAVE_MC
   xbt_assert(_sg_cfg_init_status == 0 || MC_is_active() || MC_record_replay_is_active() || not more_check,
              "Specifying a %s is only allowed within the model-checker. Please use simgrid-mc, or specify this option "
              "after the replay path.",
              spec);
-#else
-  xbt_die("Specifying a %s is only allowed within the model-checker. Please enable it before the compilation.", spec);
-#endif
 }
 
 /* Replay (this part is enabled even if MC it disabled) */
 simgrid::config::Flag<std::string> _sg_mc_record_path{
     "model-check/replay", "Model-check path to replay (as reported by SimGrid when a violation is reported)", "",
     [](std::string_view value) {
-      xbt_assert(simgrid::mc::model_checking_mode == simgrid::mc::ModelCheckingMode::NONE ||
-                     simgrid::mc::model_checking_mode == simgrid::mc::ModelCheckingMode::REPLAY,
+      if (value.empty()) // Ignore default value
+        return;
+      xbt_assert(simgrid::mc::get_model_checking_mode() == simgrid::mc::ModelCheckingMode::NONE ||
+                     simgrid::mc::get_model_checking_mode() == simgrid::mc::ModelCheckingMode::REPLAY,
                  "Specifying a MC replay path is not allowed when running the model-checker in mode %s. "
                  "Either remove the model-check/replay parameter, or execute your code out of simgrid-mc.",
-                 to_c_str(simgrid::mc::model_checking_mode));
-      simgrid::mc::model_checking_mode = simgrid::mc::ModelCheckingMode::REPLAY;
+                 to_c_str(simgrid::mc::get_model_checking_mode()));
+      simgrid::mc::set_model_checking_mode(simgrid::mc::ModelCheckingMode::REPLAY);
       MC_record_path()                 = value;
     }};
 
-#if SIMGRID_HAVE_MC
 simgrid::config::Flag<bool> _sg_mc_timeout{
     "model-check/timeout", "Whether to enable timeouts for wait requests", false, [](bool) {
       _mc_cfg_cb_check("value to enable/disable timeout for wait requests", not MC_record_replay_is_active());
     }};
 
-int _sg_mc_max_visited_states = 0;
-
 static simgrid::config::Flag<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");
+      if (value != "none" && value != "dpor" && value != "sdpor" && value != "odpor" && value != "udpor")
+        xbt_die("configuration option 'model-check/reduction' must be one of the following: "
+                " 'none', 'dpor', 'sdpor', 'odpor', or 'udpor'");
     }};
 
-simgrid::config::Flag<bool> _sg_mc_sleep_set{
-    "model-check/sleep-set", "Whether to enable the use of sleep-set in the reduction algorithm", false,
-    [](bool) { _mc_cfg_cb_check("value to enable/disable the use of sleep-set in the reduction algorithm"); }};
-
-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 "
-                              "step => faster verification, but huge memory consumption; higher values are good "
-                              "compromises between speed and memory consumption.",
-    0, [](int) { _mc_cfg_cb_check("checkpointing value"); }};
+simgrid::config::Flag<std::string> _sg_mc_strategy{
+    "model-check/strategy",
+    "Specify the the kind of heuristic to use for guided model-checking",
+    "none",
+    {{"none", "No specific strategy: simply pick the first available transition and act as a DFS."},
+     {"max_match_comm", "Try to minimize the number of in-fly communication by appairing matching send and receive."},
+     {"min_match_comm",
+      "Try to maximize the number of in-fly communication by not appairing matching send and receive."},
+     {"uniform", "No specific strategy: choices are made randomly based on a uniform sampling."}}};
 
-simgrid::config::Flag<std::string> _sg_mc_property_file{
-    "model-check/property", "Name of the file containing the property, as formatted by the ltl2ba program.", "",
-    [](const std::string&) { _mc_cfg_cb_check("property"); }};
+simgrid::config::Flag<int> _sg_mc_random_seed{"model-check/rand-seed",
+                                              "give a specific random seed to initialize the uniform distribution", 0,
+                                              [](int) { _mc_cfg_cb_check("Random seed"); }};
 
 simgrid::config::Flag<bool> _sg_mc_comms_determinism{
-    "model-check/communications-determinism",
-    "Whether to enable the detection of communication determinism",
-    false,
+    "model-check/communications-determinism", "Whether to enable the detection of communication determinism", false,
     [](bool) {
       _mc_cfg_cb_check("value to enable/disable the detection of determinism in the communications schemes");
     }};
-
 simgrid::config::Flag<bool> _sg_mc_send_determinism{
     "model-check/send-determinism",
     "Enable/disable the detection of send-determinism in the communications schemes",
@@ -106,28 +102,23 @@ simgrid::config::Flag<int> _sg_mc_max_depth{"model-check/max-depth",
                                             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: any branch leading to a state that is "
-    "already stored is cut.\n"
-    "If value=5, the last 5 visited states are stored. If value=0 (the default), no state is stored and this reduction "
-    "technique is disabled.",
-    0, [](int value) {
-      _mc_cfg_cb_check("number of stored visited states");
-      _sg_mc_max_visited_states = value;
-    }};
-
-simgrid::config::Flag<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()
+simgrid::mc::ReductionMode simgrid::mc::get_model_checking_reduction()
 {
-  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;
+  if (cfg_mc_reduction.get() == "none") {
+    return ReductionMode::none;
+  } else if (cfg_mc_reduction.get() == "dpor") {
+    return ReductionMode::dpor;
+  } else if (cfg_mc_reduction.get() == "sdpor") {
+    return ReductionMode::sdpor;
+  } else if (cfg_mc_reduction.get() == "odpor") {
+    return ReductionMode::odpor;
+  } else if (cfg_mc_reduction.get() == "udpor") {
+    XBT_INFO("No reduction will be used: "
+             "UDPOR has a dedicated invocation 'model-check/unfolding-checker' "
+             "but is not yet fully supported in SimGrid");
+    return ReductionMode::none;
+  } else {
+    XBT_INFO("Unknown reduction mode: defaulting to no reduction");
+    return ReductionMode::none;
   }
-  return cfg_mc_reduction.get() == "dpor";
 }
-
-#endif
index a900f7c..621e06f 100644 (file)
 
 /********************************** Configuration of MC **************************************/
 namespace simgrid::mc {
-bool cfg_use_DPOR(); // "model-check/reduction" == "DPOR"
+XBT_DECLARE_ENUM_CLASS(ReductionMode, none, dpor, sdpor, odpor);
 XBT_DECLARE_ENUM_CLASS(ModelCheckingMode, NONE, APP_SIDE, CHECKER_SIDE, REPLAY);
-extern XBT_PUBLIC ModelCheckingMode model_checking_mode;
-};
+ReductionMode get_model_checking_reduction(); // "model-check/reduction" == "DPOR"
+XBT_PUBLIC ModelCheckingMode get_model_checking_mode();
+XBT_PUBLIC void set_model_checking_mode(ModelCheckingMode mode);
+}; // namespace simgrid::mc
 
 extern XBT_PUBLIC simgrid::config::Flag<std::string> _sg_mc_buffering;
 extern XBT_PRIVATE simgrid::config::Flag<int> _sg_mc_checkpoint;
@@ -23,9 +25,8 @@ extern XBT_PUBLIC simgrid::config::Flag<bool> _sg_mc_send_determinism;
 extern XBT_PUBLIC simgrid::config::Flag<bool> _sg_mc_unfolding_checker;
 extern XBT_PRIVATE simgrid::config::Flag<bool> _sg_mc_timeout;
 extern XBT_PRIVATE simgrid::config::Flag<int> _sg_mc_max_depth;
-extern "C" XBT_PUBLIC int _sg_mc_max_visited_states;
+extern XBT_PRIVATE simgrid::config::Flag<int> _sg_mc_random_seed;
 extern XBT_PRIVATE simgrid::config::Flag<std::string> _sg_mc_dot_output_file;
-extern XBT_PRIVATE simgrid::config::Flag<bool> _sg_mc_termination;
-extern XBT_PUBLIC simgrid::config::Flag<bool> _sg_mc_sleep_set;
+extern XBT_PUBLIC simgrid::config::Flag<std::string> _sg_mc_strategy;
 
 #endif
diff --git a/src/mc/mc_environ.h b/src/mc/mc_environ.h
new file mode 100644 (file)
index 0000000..a8ff230
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.               */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef MC_ENVIRON_H
+#define MC_ENVIRON_H
+
+/* Define macros for the name of environment variables used by the MC.  Keep them in a separate file without any other
+ * includes, since it's also loaded from mmalloc.
+ */
+
+/** 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"
+
+/** Environment variable used to request additional system statistics.
+ */
+#define MC_ENV_SYSTEM_STATISTICS "SIMGRID_MC_SYSTEM_STATISTICS"
+
+#endif
index b5094ca..234ea14 100644 (file)
@@ -8,22 +8,22 @@
 #include "xbt/base.h"
 #include <exception>
 
-constexpr int SIMGRID_MC_EXIT_SUCCESS         = 0;
-constexpr int SIMGRID_MC_EXIT_SAFETY          = 1;
-constexpr int SIMGRID_MC_EXIT_LIVENESS        = 2;
-constexpr int SIMGRID_MC_EXIT_DEADLOCK        = 3;
-constexpr int SIMGRID_MC_EXIT_NON_TERMINATION = 4;
-constexpr int SIMGRID_MC_EXIT_NON_DETERMINISM = 5;
-constexpr int SIMGRID_MC_EXIT_PROGRAM_CRASH   = 6;
-
-constexpr int SIMGRID_MC_EXIT_ERROR           = 63;
-
 namespace simgrid::mc {
-class XBT_PUBLIC DeadlockError : public std::exception {
-};
-class XBT_PUBLIC TerminationError : public std::exception {
+
+enum class ExitStatus {
+  SUCCESS         = 0,
+  SAFETY          = 1,
+  LIVENESS        = 2,
+  DEADLOCK        = 3,
+  NON_TERMINATION = 4,
+  NON_DETERMINISM = 5,
+  PROGRAM_CRASH   = 6,
+  ERROR           = 63
 };
-class XBT_PUBLIC LivenessError : public std::exception {
+
+struct McError : public std::exception {
+  const ExitStatus value;
+  explicit McError(ExitStatus v = ExitStatus::ERROR) : value(v) {}
 };
 } // namespace simgrid::mc
 
index bc444ff..d7962fa 100644 (file)
@@ -6,22 +6,6 @@
 #include "src/kernel/actor/ActorImpl.hpp"
 #include "src/mc/mc.h"
 
-#if SIMGRID_HAVE_MC
-#include "src/mc/api/RemoteApp.hpp"
-#include "src/mc/explo/Exploration.hpp"
-#include "src/mc/inspect/mc_unw.hpp"
-#include "src/mc/mc_config.hpp"
-#include "src/mc/mc_private.hpp"
-#include "src/mc/remote/AppSide.hpp"
-#include "src/mc/sosp/Snapshot.hpp"
-
-#include <array>
-#include <boost/core/demangle.hpp>
-#include <cerrno>
-#include <cstring>
-#include <libunwind.h>
-#endif
-
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -34,41 +18,6 @@ std::vector<double> processes_time;
 
 }
 
-#if SIMGRID_HAVE_MC
-
-namespace simgrid::mc {
-
-/*******************************  Core of MC *******************************/
-/**************************************************************************/
-void dumpStack(FILE* file, unw_cursor_t* cursor)
-{
-  int nframe = 0;
-  std::array<char, 100> buffer;
-
-  unw_word_t off;
-  do {
-    const char* name = not unw_get_proc_name(cursor, buffer.data(), buffer.size(), &off) ? buffer.data() : "?";
-    // Unmangle C++ names:
-    std::string realname = boost::core::demangle(name);
-
-#if defined(__x86_64__)
-    unw_word_t rip = 0;
-    unw_word_t rsp = 0;
-    unw_get_reg(cursor, UNW_X86_64_RIP, &rip);
-    unw_get_reg(cursor, UNW_X86_64_RSP, &rsp);
-    fprintf(file, "  %i: %s (RIP=0x%" PRIx64 " RSP=0x%" PRIx64 ")\n", nframe, realname.c_str(), (std::uint64_t)rip,
-            (std::uint64_t)rsp);
-#else
-    fprintf(file, "  %i: %s\n", nframe, realname.c_str());
-#endif
-
-    ++nframe;
-  } while (unw_step(cursor));
-}
-
-} // namespace simgrid::mc
-#endif
-
 double MC_process_clock_get(const simgrid::kernel::actor::ActorImpl* process)
 {
   if (process) {
index facb90d..d4185f0 100644 (file)
@@ -7,7 +7,6 @@
 #define SIMGRID_MC_PRIVATE_HPP
 
 #include "src/mc/mc.h"
-#include "xbt/automaton.h"
 
 #include "src/mc/mc_forward.hpp"
 #include "src/xbt/memory_map.hpp"
index 6f1d32f..63d9fc0 100644 (file)
 #include "src/mc/mc_replay.hpp"
 #include "src/mc/transition/Transition.hpp"
 
-#if SIMGRID_HAVE_MC
-#include "src/mc/api/State.hpp"
-#include "src/mc/explo/Exploration.hpp"
-#include "src/mc/mc_private.hpp"
-#endif
-
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_record, mc, "Logging specific to MC record/replay facility");
 
 namespace simgrid::mc {
@@ -57,7 +51,7 @@ void RecordTrace::replay() const
   const auto& actor_list = engine->get_actor_list();
   if (actor_list.empty()) {
     XBT_INFO("The replay of the trace is complete. The application is terminating.");
-  } else if (std::none_of(begin(actor_list), end(actor_list),
+  } else if (std::none_of(std::begin(actor_list), std::end(actor_list),
                           [](const auto& kv) { return mc::actor_is_enabled(kv.second); })) {
     XBT_INFO("The replay of the trace is complete. DEADLOCK detected.");
     engine->display_all_actor_status();
@@ -100,12 +94,12 @@ simgrid::mc::RecordTrace::RecordTrace(const char* data)
   }
 }
 
-#if SIMGRID_HAVE_MC
-
 std::string simgrid::mc::RecordTrace::to_string() const
 {
   std::ostringstream stream;
   for (auto i = transitions_.begin(); i != transitions_.end(); ++i) {
+    if (*i == nullptr)
+      continue;
     if (i != transitions_.begin())
       stream << ';';
     stream << (*i)->aid_;
@@ -114,7 +108,4 @@ std::string simgrid::mc::RecordTrace::to_string() const
   }
   return stream.str();
 }
-
-#endif
-
 } // namespace simgrid::mc
index 2958780..32f78ef 100644 (file)
@@ -9,7 +9,7 @@
  *  The recorded path is written in the log output and can be replayed with MC disabled
  *  (even with a non-MC build) using `--cfg=model-check/replay:$replayPath`.
  *
- *  The same version of Simgrid should be used and the same arguments should be
+ *  The same version of SimGrid should be used and the same arguments should be
  *  passed to the application (without the MC specific arguments).
  */
 
 #include "src/mc/mc_forward.hpp"
 #include "xbt/base.h"
 
+#include <deque>
 #include <string>
-#include <vector>
 
 namespace simgrid::mc {
 
 class RecordTrace {
-  std::vector<Transition*> transitions_;
+  std::deque<Transition*> transitions_;
 
 public:
-  RecordTrace() = default;
+  // Use rule-of-three, and implicitely disable the move constructor which cannot be 'noexcept' (as required by C++ Core
+  // Guidelines), due to the std::deque member.
+  RecordTrace()                   = default;
+  RecordTrace(const RecordTrace&) = default;
+  ~RecordTrace()                  = default;
 
   /** Build a trace that can be replayed from a string representation */
   explicit RecordTrace(const char* data);
   /** Make a string representation that can later be used to create a new trace */
   std::string to_string() const;
 
+  void push_front(Transition* t) { transitions_.push_front(t); }
   void push_back(Transition* t) { transitions_.push_back(t); }
+  std::deque<Transition*>::const_iterator begin() const { return transitions_.begin(); }
+  std::deque<Transition*>::const_iterator end() const { return transitions_.end(); }
 
   /** Replay all transitions of a trace */
   void replay() const;
index be9826a..aabac00 100644 (file)
@@ -11,7 +11,7 @@
 #include "src/kernel/actor/SimcallObserver.hpp"
 #include "src/mc/mc_base.hpp"
 #include "src/mc/mc_config.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
+#include "src/mc/mc_environ.h"
 #if HAVE_SMPI
 #include "src/smpi/include/private.hpp"
 #endif
@@ -21,6 +21,7 @@
 #include <simgrid/modelchecker.h>
 
 #include <cerrno>
+#include <cinttypes>
 #include <cstdio> // setvbuf
 #include <cstdlib>
 #include <memory>
@@ -38,16 +39,18 @@ namespace simgrid::mc {
 
 std::unique_ptr<AppSide> AppSide::instance_;
 
-AppSide* AppSide::initialize()
+AppSide* AppSide::get()
 {
-  if (not std::getenv(MC_ENV_SOCKET_FD)) // We are not in MC mode: don't initialize the MC world
+  // Only initialize the MC world once
+  if (instance_ != nullptr)
+    return instance_.get();
+
+  if (std::getenv(MC_ENV_SOCKET_FD) == nullptr) // We are not in MC mode: don't initialize the MC world
     return nullptr;
 
-  // Do not break if we are called multiple times:
-  if (instance_)
-    return instance_.get();
+  XBT_DEBUG("Initialize the MC world.");
 
-  simgrid::mc::model_checking_mode = ModelCheckingMode::APP_SIDE;
+  simgrid::mc::set_model_checking_mode(ModelCheckingMode::APP_SIDE);
 
   setvbuf(stdout, nullptr, _IOLBF, 0);
 
@@ -56,30 +59,8 @@ AppSide* AppSide::initialize()
   int fd             = xbt_str_parse_int(fd_env, "Not a number in variable '" MC_ENV_SOCKET_FD "'");
   XBT_DEBUG("Model-checked application found socket FD %i", fd);
 
-  // Check the socket type/validity:
-  int type;
-  socklen_t socklen = sizeof(type);
-  xbt_assert(getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &socklen) == 0, "Could not check socket type");
-  xbt_assert(type == SOCK_SEQPACKET, "Unexpected socket type %i", type);
-  XBT_DEBUG("Model-checked application found expected socket type");
-
   instance_ = std::make_unique<simgrid::mc::AppSide>(fd);
 
-  // Wait for the model-checker:
-  if (getenv("MC_NEED_PTRACE") != nullptr) {
-    errno = 0;
-#if defined __linux__
-    ptrace(PTRACE_TRACEME, 0, nullptr, nullptr);
-#elif defined BSD
-    ptrace(PT_TRACE_ME, 0, nullptr, 0);
-#else
-    xbt_die("no ptrace equivalent coded for this platform, please don't use the liveness checker here.");
-#endif
-
-    xbt_assert(errno == 0 && raise(SIGSTOP) == 0, "Could not wait for the model-checker (errno = %d: %s)", errno,
-               strerror(errno));
-  }
-
   instance_->handle_messages();
   return instance_.get();
 }
@@ -102,17 +83,20 @@ void AppSide::handle_deadlock_check(const s_mc_message_t*) const
   s_mc_message_int_t answer = {};
   answer.type  = MessageType::DEADLOCK_CHECK_REPLY;
   answer.value = deadlock;
-  xbt_assert(channel_.send(answer) == 0, "Could not send response");
+  xbt_assert(channel_.send(answer) == 0, "Could not send response: %s", strerror(errno));
 }
 void AppSide::handle_simcall_execute(const s_mc_message_simcall_execute_t* message) const
 {
   kernel::actor::ActorImpl* actor = kernel::EngineImpl::get_instance()->get_actor_by_pid(message->aid_);
   xbt_assert(actor != nullptr, "Invalid pid %ld", message->aid_);
+  xbt_assert(actor->simcall_.observer_ == nullptr || actor->simcall_.observer_->is_enabled(),
+             "Please, model-checker, don't execute disabled transitions.");
 
   // The client may send some messages to the server while processing the transition
   actor->simcall_handle(message->times_considered_);
   // Say the server that the transition is over and that it should proceed
-  xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send MESSAGE_WAITING to model-checker");
+  xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send MESSAGE_WAITING to model-checker: %s",
+             strerror(errno));
 
   // Finish the RPC from the server: return a serialized observer, to build a Transition on Checker side
   s_mc_message_simcall_execute_answer_t answer = {};
@@ -130,7 +114,7 @@ void AppSide::handle_simcall_execute(const s_mc_message_simcall_execute_t* messa
   answer.buffer.back() = '\0';
 
   XBT_DEBUG("send SIMCALL_EXECUTE_ANSWER(%s) ~> '%s'", actor->get_cname(), str.c_str());
-  xbt_assert(channel_.send(answer) == 0, "Could not send response");
+  xbt_assert(channel_.send(answer) == 0, "Could not send response: %s", strerror(errno));
 }
 
 void AppSide::handle_finalize(const s_mc_message_int_t* msg) const
@@ -147,26 +131,37 @@ void AppSide::handle_finalize(const s_mc_message_int_t* msg) const
 #endif
   }
   coverage_checkpoint();
-  xbt_assert(channel_.send(MessageType::FINALIZE_REPLY) == 0, "Could not answer to FINALIZE");
+  xbt_assert(channel_.send(MessageType::FINALIZE_REPLY) == 0, "Could not answer to FINALIZE: %s", strerror(errno));
   std::fflush(stdout);
   if (terminate_asap)
     ::_Exit(0);
 }
-void AppSide::handle_fork(const s_mc_message_int_t* msg)
+void AppSide::handle_fork(const s_mc_message_fork_t* msg)
 {
-  int pid = fork();
+  int status;
+  int pid;
+  /* Reap any zombie child, saving its status for later use in AppSide::handle_wait_child() */
+  while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+    child_statuses_[pid] = status;
+
+  pid = fork();
   xbt_assert(pid >= 0, "Could not fork application sub-process: %s.", strerror(errno));
 
   if (pid == 0) { // Child
-    int sock = socket(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+    int sock = socket(AF_UNIX,
+#ifdef __APPLE__
+                      SOCK_STREAM, /* Mac OSX does not have AF_UNIX + SOCK_SEQPACKET, even if that's faster*/
+#else
+                      SOCK_SEQPACKET,
+#endif
+                      0);
 
     struct sockaddr_un addr = {};
-    addr.sun_family         = AF_LOCAL;
-    snprintf(addr.sun_path, 64, "/tmp/simgrid-mc-%lu", msg->value);
-    auto addr_size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path);
+    addr.sun_family         = AF_UNIX;
+    std::copy_n(begin(msg->socket_name), MC_SOCKET_NAME_LEN, addr.sun_path);
 
-    xbt_assert(connect(sock, (struct sockaddr*)&addr, addr_size) >= 0,
-               "Cannot connect to Checker on /tmp/simgrid-mc-%lu: %s.", msg->value, strerror(errno));
+    xbt_assert(connect(sock, (struct sockaddr*)&addr, sizeof addr) >= 0, "Cannot connect to Checker on %c%s: %s.",
+               (addr.sun_path[0] ? addr.sun_path[0] : '@'), addr.sun_path + 1, strerror(errno));
 
     channel_.reset_socket(sock);
 
@@ -174,13 +169,20 @@ void AppSide::handle_fork(const s_mc_message_int_t* msg)
     answer.type               = MessageType::FORK_REPLY;
     answer.value              = getpid();
     xbt_assert(channel_.send(answer) == 0, "Could not send response to WAIT_CHILD_REPLY: %s", strerror(errno));
+  } else {
+    XBT_VERB("App %d forks subprocess %d.", getpid(), pid);
   }
 }
 void AppSide::handle_wait_child(const s_mc_message_int_t* msg)
 {
   int status;
   errno = 0;
-  waitpid(msg->value, &status, 0);
+  if (auto search = child_statuses_.find(msg->value); search != child_statuses_.end()) {
+    status = search->second;
+    child_statuses_.erase(search); // We only need this info once
+  } else {
+    waitpid(msg->value, &status, 0);
+  }
   xbt_assert(errno == 0, "Cannot wait on behalf of the checker: %s.", strerror(errno));
 
   s_mc_message_int_t answer = {};
@@ -188,14 +190,6 @@ void AppSide::handle_wait_child(const s_mc_message_int_t* msg)
   answer.value              = status;
   xbt_assert(channel_.send(answer) == 0, "Could not send response to WAIT_CHILD: %s", strerror(errno));
 }
-void AppSide::handle_need_meminfo()
-{
-  this->need_memory_info_                  = true;
-  s_mc_message_need_meminfo_reply_t answer = {};
-  answer.type                              = MessageType::NEED_MEMINFO_REPLY;
-  answer.mmalloc_default_mdp               = mmalloc_get_current_heap();
-  xbt_assert(channel_.send(answer) == 0, "Could not send response to the request for meminfo.");
-}
 void AppSide::handle_actors_status() const
 {
   auto const& actor_list = kernel::EngineImpl::get_instance()->get_actor_list();
@@ -203,6 +197,9 @@ void AppSide::handle_actors_status() const
 
   std::vector<s_mc_message_actors_status_one_t> status;
   for (auto const& [aid, actor] : actor_list) {
+    xbt_assert(actor);
+    xbt_assert(actor->simcall_.observer_, "simcall %s in actor %s has no observer.", actor->simcall_.get_cname(),
+               actor->get_cname());
     s_mc_message_actors_status_one_t one = {};
     one.type                             = MessageType::ACTORS_STATUS_REPLY_TRANSITION;
     one.aid                              = aid;
@@ -213,20 +210,17 @@ void AppSide::handle_actors_status() const
 
   struct s_mc_message_actors_status_answer_t answer = {};
   answer.type                                       = MessageType::ACTORS_STATUS_REPLY_COUNT;
-  answer.count            = static_cast<int>(status.size());
+  answer.count                                      = static_cast<int>(status.size());
 
-  xbt_assert(channel_.send(answer) == 0, "Could not send ACTORS_STATUS_REPLY msg");
+  xbt_assert(channel_.send(answer) == 0, "Could not send ACTORS_STATUS_REPLY msg: %s", strerror(errno));
   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");
+    xbt_assert(channel_.send(status.data(), size) == 0, "Could not send ACTORS_STATUS_REPLY data: %s", strerror(errno));
   }
 
   // Serialize each transition to describe what each actor is doing
   XBT_DEBUG("Deliver ACTOR_TRANSITION_PROBE payload");
   for (const auto& actor_status : status) {
-    if (not actor_status.enabled)
-      continue;
-
     const auto& actor        = actor_list.at(actor_status.aid);
     const int max_considered = actor_status.max_considered;
 
@@ -248,7 +242,8 @@ void AppSide::handle_actors_status() const
       strncpy(probe.buffer.data(), str.c_str(), probe.buffer.size() - 1);
       probe.buffer.back() = '\0';
 
-      xbt_assert(channel_.send(probe) == 0, "Could not send ACTOR_TRANSITION_PROBE payload");
+      XBT_DEBUG("send ACTOR_TRANSITION_PROBE(%s) ~> '%s'", actor->get_cname(), str.c_str());
+      xbt_assert(channel_.send(probe) == 0, "Could not send ACTOR_TRANSITION_PROBE payload: %s", strerror(errno));
     }
     // NOTE: We do NOT need to reset `times_considered` for each actor's
     // simcall observer here to the "original" value (i.e. the value BEFORE
@@ -262,7 +257,7 @@ void AppSide::handle_actors_maxpid() const
   s_mc_message_int_t answer = {};
   answer.type               = MessageType::ACTORS_MAXPID_REPLY;
   answer.value              = kernel::actor::ActorImpl::get_maxpid();
-  xbt_assert(channel_.send(answer) == 0, "Could not send response");
+  xbt_assert(channel_.send(answer) == 0, "Could not send response: %s", strerror(errno));
 }
 
 #define assert_msg_size(_name_, _type_)                                                                                \
@@ -281,7 +276,7 @@ void AppSide::handle_messages()
       XBT_DEBUG("Socket closed on the Checker side, bailing out.");
       ::_Exit(0); // Nobody's listening to that process anymore => exit as quickly as possible.
     }
-    xbt_assert(received_size >= 0, "Could not receive commands from the model-checker");
+    xbt_assert(received_size >= 0, "Could not receive commands from the model-checker: %s", strerror(errno));
     xbt_assert(static_cast<size_t>(received_size) >= sizeof(s_mc_message_t), "Cannot handle short message (size=%zd)",
                received_size);
 
@@ -307,8 +302,8 @@ void AppSide::handle_messages()
         break;
 
       case MessageType::FORK:
-        assert_msg_size("FORK", s_mc_message_int_t);
-        handle_fork((s_mc_message_int_t*)message_buffer.data());
+        assert_msg_size("FORK", s_mc_message_fork_t);
+        handle_fork((s_mc_message_fork_t*)message_buffer.data());
         break;
 
       case MessageType::WAIT_CHILD:
@@ -316,11 +311,6 @@ void AppSide::handle_messages()
         handle_wait_child((s_mc_message_int_t*)message_buffer.data());
         break;
 
-      case MessageType::NEED_MEMINFO:
-        assert_msg_size("NEED_MEMINFO", s_mc_message_t);
-        handle_need_meminfo();
-        break;
-
       case MessageType::ACTORS_STATUS:
         assert_msg_size("ACTORS_STATUS", s_mc_message_t);
         handle_actors_status();
@@ -341,110 +331,23 @@ void AppSide::handle_messages()
 void AppSide::main_loop()
 {
   simgrid::mc::processes_time.resize(simgrid::kernel::actor::ActorImpl::get_maxpid());
-  MC_ignore_heap(simgrid::mc::processes_time.data(),
-                 simgrid::mc::processes_time.size() * sizeof(simgrid::mc::processes_time[0]));
 
   sthread_disable();
   coverage_checkpoint();
   sthread_enable();
   while (true) {
     simgrid::mc::execute_actors();
-    xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send WAITING message to model-checker");
+    xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send WAITING message to model-checker: %s",
+               strerror(errno));
     this->handle_messages();
   }
 }
 
 void AppSide::report_assertion_failure()
 {
-  xbt_assert(channel_.send(MessageType::ASSERTION_FAILED) == 0, "Could not send assertion to model-checker");
+  xbt_assert(channel_.send(MessageType::ASSERTION_FAILED) == 0, "Could not send assertion to model-checker: %s",
+             strerror(errno));
   this->handle_messages();
 }
 
-void AppSide::ignore_memory(void* addr, std::size_t size) const
-{
-  if (not MC_is_active() || not need_memory_info_)
-    return;
-
-  s_mc_message_ignore_memory_t message = {};
-  message.type = MessageType::IGNORE_MEMORY;
-  message.addr = (std::uintptr_t)addr;
-  message.size = size;
-  xbt_assert(channel_.send(message) == 0, "Could not send IGNORE_MEMORY message to model-checker");
-}
-
-void AppSide::ignore_heap(void* address, std::size_t size) const
-{
-  if (not MC_is_active() || not need_memory_info_)
-    return;
-
-  const s_xbt_mheap_t* heap = mmalloc_get_current_heap();
-
-  s_mc_message_ignore_heap_t message = {};
-  message.type    = MessageType::IGNORE_HEAP;
-  message.address = address;
-  message.size    = size;
-  message.block   = ((char*)address - (char*)heap->heapbase) / BLOCKSIZE + 1;
-  if (heap->heapinfo[message.block].type == 0) {
-    message.fragment = -1;
-    heap->heapinfo[message.block].busy_block.ignore++;
-  } else {
-    message.fragment = (ADDR2UINT(address) % BLOCKSIZE) >> heap->heapinfo[message.block].type;
-    heap->heapinfo[message.block].busy_frag.ignore[message.fragment]++;
-  }
-
-  xbt_assert(channel_.send(message) == 0, "Could not send ignored region to MCer");
-}
-
-void AppSide::unignore_heap(void* address, std::size_t size) const
-{
-  if (not MC_is_active() || not need_memory_info_)
-    return;
-
-  s_mc_message_ignore_memory_t message = {};
-  message.type = MessageType::UNIGNORE_HEAP;
-  message.addr = (std::uintptr_t)address;
-  message.size = size;
-  xbt_assert(channel_.send(message) == 0, "Could not send IGNORE_HEAP message to model-checker");
-}
-
-void AppSide::declare_symbol(const char* name, int* value) const
-{
-  if (not MC_is_active() || not need_memory_info_) {
-    XBT_CRITICAL("Ignore AppSide::declare_symbol(%s)", name);
-    return;
-  }
-
-  s_mc_message_register_symbol_t message = {};
-  message.type = MessageType::REGISTER_SYMBOL;
-  xbt_assert(strlen(name) + 1 <= message.name.size(), "Symbol is too long");
-  strncpy(message.name.data(), name, message.name.size() - 1);
-  message.callback = nullptr;
-  message.data     = value;
-  xbt_assert(channel_.send(message) == 0, "Could send REGISTER_SYMBOL message to model-checker");
-}
-
-/** 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() || not need_memory_info_)
-    return;
-
-  const s_xbt_mheap_t* heap = mmalloc_get_current_heap();
-
-  s_stack_region_t region = {};
-  region.address = stack;
-  region.context = context;
-  region.size    = size;
-  region.block   = ((char*)stack - (char*)heap->heapbase) / BLOCKSIZE + 1;
-
-  s_mc_message_stack_region_t message = {};
-  message.type         = MessageType::STACK_REGION;
-  message.stack_region = region;
-  xbt_assert(channel_.send(message) == 0, "Could not send STACK_REGION to model-checker");
-}
 } // namespace simgrid::mc
index 5dcb934..03250e9 100644 (file)
@@ -22,7 +22,7 @@ class XBT_PUBLIC AppSide {
 private:
   Channel channel_;
   static std::unique_ptr<AppSide> instance_;
-  bool need_memory_info_ = false; /* by default we don't send memory info, unless we got a NEED_MEMINFO */
+  std::unordered_map<int, int> child_statuses_;
 
 public:
   AppSide();
@@ -33,9 +33,8 @@ 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_finalize(const s_mc_message_int_t* msg) const;
-  void handle_fork(const s_mc_message_int_t* msg);
+  void handle_fork(const s_mc_message_fork_t* msg);
   void handle_wait_child(const s_mc_message_int_t* msg);
-  void handle_need_meminfo();
   void handle_actors_status() const;
   void handle_actors_maxpid() const;
 
@@ -44,18 +43,9 @@ public:
   Channel& get_channel() { return channel_; }
   XBT_ATTRIB_NORETURN void main_loop();
   void report_assertion_failure();
-  void ignore_memory(void* addr, std::size_t size) const;
-  void ignore_heap(void* addr, std::size_t size) const;
-  void unignore_heap(void* addr, std::size_t size) const;
-  void declare_symbol(const char* name, int* value) const;
-#if HAVE_UCONTEXT_H
-  void declare_stack(void* stack, size_t size, ucontext_t* context) const;
-#endif
 
-  // Singleton :/
   // TODO, remove the singleton antipattern.
-  static AppSide* initialize();
-  static AppSide* get() { return instance_.get(); }
+  static AppSide* get();
 };
 } // namespace simgrid::mc
 
index 6160412..7e3bfb9 100644 (file)
@@ -1,5 +1,4 @@
-/* Copyright (c) 2015-2023. The SimGrid Team.
- * All rights reserved.                                                     */
+/* Copyright (c) 2015-2023. The SimGrid Team.  All rights reserved.         */
 
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
@@ -7,15 +6,20 @@
 #include "src/mc/remote/Channel.hpp"
 #include <xbt/log.h>
 
+#include <algorithm>
 #include <cerrno>
 #include <cstring>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_Channel, mc, "MC interprocess communication");
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_channel, mc, "MC interprocess communication");
 
 namespace simgrid::mc {
+Channel::Channel(int sock, Channel const& other) : socket_(sock), buffer_(other.buffer_)
+{
+  XBT_DEBUG("Adopt %zu bytes buffered by father channel.", buffer_.size());
+}
 
 Channel::~Channel()
 {
@@ -43,16 +47,44 @@ int Channel::send(const void* message, size_t size) const
   return 0;
 }
 
-ssize_t Channel::receive(void* message, size_t size) const
+ssize_t Channel::receive(void* message, size_t size, int flags)
 {
-  ssize_t res = recv(this->socket_, message, size, 0);
-  xbt_assert(res != -1, "Channel::receive failure: %s", strerror(errno));
+  size_t bufsize = buffer_.size();
+  ssize_t copied = 0;
+  auto* whereto  = static_cast<char*>(message);
+  size_t todo    = size;
+  if (bufsize > 0) {
+    XBT_DEBUG("%d %zu bytes (of %zu expected) are already in buffer", getpid(), bufsize, size);
+    copied = std::min(size, bufsize);
+    std::copy_n(begin(buffer_), copied, whereto);
+    buffer_.erase(begin(buffer_), begin(buffer_) + copied);
+    todo -= copied;
+    whereto += copied;
+  }
+  ssize_t res = 0;
+  if (todo > 0) {
+    errno = 0;
+    res   = recv(this->socket_, whereto, todo, flags);
+    xbt_assert(res != -1 || errno == EAGAIN, "Channel::receive failure: %s", strerror(errno));
+    if (res == -1) {
+      res = 0;
+    }
+  }
+  XBT_DEBUG("%d Wanted %zu; Got %zd from buffer and %zd from network", getpid(), size, copied, res);
+  res += copied;
   if (static_cast<size_t>(res) >= sizeof(int) && is_valid_MessageType(*static_cast<const int*>(message))) {
-    XBT_DEBUG("Receive %s (requested %zu; received %zd at %p)", to_c_str(*static_cast<const MessageType*>(message)),
-              size, res, message);
+    XBT_DEBUG("%d Receive %s (requested %zu; received %zd at %p)", getpid(),
+              to_c_str(*static_cast<const MessageType*>(message)), size, res, message);
   } else {
     XBT_DEBUG("Receive %zd bytes", res);
   }
   return res;
 }
+
+void Channel::reinject(const char* data, size_t size)
+{
+  xbt_assert(size > 0, "Cannot reinject less than one char (size: %lu)", size);
+  XBT_DEBUG("%d Reinject %zu bytes on top of %zu pre-existing bytes", getpid(), size, buffer_.size());
+  buffer_.insert(end(buffer_), data, data + size);
+}
 } // namespace simgrid::mc
index c9e1aeb..06d22b1 100644 (file)
@@ -20,10 +20,12 @@ namespace simgrid::mc {
 class Channel {
   int socket_ = -1;
   template <class M> static constexpr bool messageType() { return std::is_class_v<M> && std::is_trivial_v<M>; }
+  std::vector<char> buffer_;
 
 public:
   Channel() = default;
   explicit Channel(int sock) : socket_(sock) {}
+  Channel(int sock, Channel const& other);
   ~Channel();
 
   // No copy:
@@ -44,11 +46,13 @@ public:
   }
 
   // Receive
-  ssize_t receive(void* message, size_t size) const;
-  template <class M> typename std::enable_if_t<messageType<M>(), ssize_t> receive(M& m) const
+  ssize_t receive(void* message, size_t size, int flags = 0);
+  template <class M> typename std::enable_if_t<messageType<M>(), ssize_t> receive(M& m)
   {
-    return this->receive(&m, sizeof(M));
+    return this->receive(&m, sizeof(M), 0);
   }
+  void reinject(const char* data, size_t size);
+  bool has_pending_data() const { return not buffer_.empty(); }
 
   // Socket handling
   int get_socket() const { return socket_; }
index a19f093..2ad4f7e 100644 (file)
@@ -5,8 +5,8 @@
 
 #include "src/mc/remote/CheckerSide.hpp"
 #include "src/mc/explo/Exploration.hpp"
-#include "src/mc/explo/LivenessChecker.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
+#include "src/mc/mc_environ.h"
+#include "xbt/config.hpp"
 #include "xbt/system_error.hpp"
 
 #ifdef __linux__
@@ -36,7 +36,7 @@ static simgrid::config::Flag<std::string> _sg_mc_setenv{
 
 namespace simgrid::mc {
 
-XBT_ATTRIB_NORETURN static void run_child_process(int socket, const std::vector<char*>& args, bool need_ptrace)
+XBT_ATTRIB_NORETURN 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
@@ -50,14 +50,7 @@ XBT_ATTRIB_NORETURN static void run_child_process(int socket, const std::vector<
   xbt_assert(prctl(PR_SET_PDEATHSIG, SIGHUP) == 0, "Could not PR_SET_PDEATHSIG");
 #endif
 
-  // Remove CLOEXEC to pass the socket to the application
-  int fdflags = fcntl(socket, F_GETFD, 0);
-  xbt_assert(fdflags != -1 && fcntl(socket, F_SETFD, fdflags & ~FD_CLOEXEC) != -1,
-             "Could not remove CLOEXEC for socket");
-
   setenv(MC_ENV_SOCKET_FD, std::to_string(socket).c_str(), 1);
-  if (need_ptrace)
-    setenv("MC_NEED_PTRACE", "1", 1);
 
   /* Setup the tokenizer that parses the cfg:model-check/setenv parameter */
   using Tokenizer = boost::tokenizer<boost::char_separator<char>>;
@@ -110,13 +103,14 @@ static void wait_application_process(pid_t pid)
 #elif defined BSD
   ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
 #else
-#error "no ptrace equivalent coded for this platform"
+  xbt_die("no ptrace equivalent coded for this platform, stateful model-checking is impossible.");
 #endif
   xbt_assert(errno == 0,
              "Ptrace does not seem to be usable in your setup (errno: %d). "
              "If you run from within a docker, adding `--cap-add SYS_PTRACE` to the docker line may help. "
              "If it does not help, please report this bug.",
              errno);
+  XBT_DEBUG("%d ptrace correctly setup.", getpid());
 }
 
 void CheckerSide::setup_events(bool socket_only)
@@ -127,20 +121,24 @@ void CheckerSide::setup_events(bool socket_only)
   socket_event_ = event_new(
       base, get_channel().get_socket(), EV_READ | EV_PERSIST,
       [](evutil_socket_t, short events, void* arg) {
-        auto checker = static_cast<simgrid::mc::CheckerSide*>(arg);
+        auto* checker = static_cast<simgrid::mc::CheckerSide*>(arg);
         if (events == EV_READ) {
-          std::array<char, MC_MESSAGE_LENGTH> buffer;
-          ssize_t size = recv(checker->get_channel().get_socket(), buffer.data(), buffer.size(), MSG_DONTWAIT);
-          if (size == -1) {
-            XBT_ERROR("Channel::receive failure: %s", strerror(errno));
-            if (errno != EAGAIN)
-              throw simgrid::xbt::errno_error();
-          }
-
-          if (size == 0) // The app closed the socket. It must be dead by now.
-            checker->handle_waitpid();
-          else if (not checker->handle_message(buffer.data(), size))
-            checker->break_loop();
+          do {
+            std::array<char, MC_MESSAGE_LENGTH> buffer;
+            ssize_t size = checker->get_channel().receive(buffer.data(), buffer.size(), MSG_DONTWAIT);
+            if (size == -1) {
+              XBT_ERROR("Channel::receive failure: %s", strerror(errno));
+              if (errno != EAGAIN)
+                throw simgrid::xbt::errno_error();
+            }
+
+            if (size == 0) // The app closed the socket. It must be dead by now.
+              checker->handle_waitpid();
+            else if (not checker->handle_message(buffer.data(), size)) {
+              checker->break_loop();
+              break;
+            }
+          } while (checker->get_channel().has_pending_data());
         } else {
           xbt_die("Unexpected event");
         }
@@ -154,7 +152,7 @@ void CheckerSide::setup_events(bool socket_only)
     signal_event_ = event_new(
         base, SIGCHLD, EV_SIGNAL | EV_PERSIST,
         [](evutil_socket_t sig, short events, void* arg) {
-          auto checker = static_cast<simgrid::mc::CheckerSide*>(arg);
+          auto* checker = static_cast<simgrid::mc::CheckerSide*>(arg);
           if (events == EV_SIGNAL) {
             if (sig == SIGCHLD)
               checker->handle_waitpid();
@@ -170,20 +168,28 @@ void CheckerSide::setup_events(bool socket_only)
 }
 
 /* When this constructor is called, no other checkerside exists */
-CheckerSide::CheckerSide(const std::vector<char*>& args, bool need_memory_info) : running_(true)
+CheckerSide::CheckerSide(const std::vector<char*>& args) : running_(true)
 {
-  // Create an AF_LOCAL socketpair used for exchanging messages between the model-checker process (ancestor)
+  XBT_DEBUG("Create a CheckerSide.");
+
+  // Create an AF_UNIX socketpair used for exchanging messages between the model-checker process (ancestor)
   // and the application process (child)
   int sockets[2];
-  xbt_assert(socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != -1, "Could not create socketpair: %s",
-             strerror(errno));
+  xbt_assert(socketpair(AF_UNIX,
+#ifdef __APPLE__
+                        SOCK_STREAM, /* Mac OSX does not have AF_UNIX + SOCK_SEQPACKET, even if that's faster */
+#else
+                        SOCK_SEQPACKET,
+#endif
+                        0, sockets) != -1,
+             "Could not create socketpair: %s", strerror(errno));
 
   pid_ = fork();
   xbt_assert(pid_ >= 0, "Could not fork application process");
 
   if (pid_ == 0) { // Child
     ::close(sockets[1]);
-    run_child_process(sockets[0], args, need_memory_info); // We need ptrace if we need the mem info
+    run_child_process(sockets[0], args);
     DIE_IMPOSSIBLE;
   }
 
@@ -192,24 +198,6 @@ CheckerSide::CheckerSide(const std::vector<char*>& args, bool need_memory_info)
   channel_.reset_socket(sockets[1]);
 
   setup_events(false); /* we need a signal handler too */
-  if (need_memory_info) {
-    // setup ptrace and sync with the app
-    wait_application_process(pid_);
-
-    // Request the initial memory on need
-    channel_.send(MessageType::NEED_MEMINFO);
-    s_mc_message_need_meminfo_reply_t answer;
-    ssize_t answer_size = channel_.receive(answer);
-    xbt_assert(answer_size != -1, "Could not receive message");
-    xbt_assert(answer.type == MessageType::NEED_MEMINFO_REPLY,
-               "The received message is not the NEED_MEMINFO_REPLY I was expecting but of type %s",
-               to_c_str(answer.type));
-    xbt_assert(answer_size == sizeof answer, "Broken message (size=%zd; expected %zu)", answer_size, sizeof answer);
-
-    /* We now have enough info to create the memory address space */
-    remote_memory_ = std::make_unique<simgrid::mc::RemoteProcessMemory>(pid_, answer.mmalloc_default_mdp);
-  }
-
   wait_for_requests();
 }
 
@@ -225,7 +213,7 @@ CheckerSide::~CheckerSide()
 
 /* This constructor is called when cloning a checkerside to get its application to fork away */
 CheckerSide::CheckerSide(int socket, CheckerSide* child_checker)
-    : channel_(socket), running_(true), child_checker_(child_checker)
+    : channel_(socket, child_checker->channel_), running_(true), child_checker_(child_checker)
 {
   setup_events(true); // We already have a signal handled in that case
 
@@ -241,11 +229,12 @@ CheckerSide::CheckerSide(int socket, CheckerSide* child_checker)
   wait_for_requests();
 }
 
-std::unique_ptr<CheckerSide> CheckerSide::clone(int master_socket)
+std::unique_ptr<CheckerSide> CheckerSide::clone(int master_socket, const std::string& master_socket_name)
 {
-  s_mc_message_int_t m = {};
-  m.type               = MessageType::FORK;
-  m.value              = getpid();
+  s_mc_message_fork_t m = {};
+  m.type                = MessageType::FORK;
+  xbt_assert(master_socket_name.size() == MC_SOCKET_NAME_LEN);
+  std::copy_n(begin(master_socket_name), MC_SOCKET_NAME_LEN, begin(m.socket_name));
   xbt_assert(get_channel().send(m) == 0, "Could not ask the app to fork on need.");
 
   int sock = accept(master_socket, nullptr /* I know who's connecting*/, nullptr);
@@ -283,85 +272,36 @@ void CheckerSide::break_loop() const
 bool CheckerSide::handle_message(const char* buffer, ssize_t size)
 {
   s_mc_message_t base_message;
+  ssize_t consumed;
   xbt_assert(size >= (ssize_t)sizeof(base_message), "Broken message. Got only %ld bytes.", size);
   memcpy(&base_message, buffer, sizeof(base_message));
 
   switch (base_message.type) {
-    case MessageType::IGNORE_HEAP: {
-      if (remote_memory_ != nullptr) {
-        s_mc_message_ignore_heap_t message;
-        xbt_assert(size == sizeof(message), "Broken message");
-        memcpy(&message, buffer, sizeof(message));
-
-        IgnoredHeapRegion region;
-        region.block    = message.block;
-        region.fragment = message.fragment;
-        region.address  = message.address;
-        region.size     = message.size;
-        get_remote_memory()->ignore_heap(region);
-      } else {
-        XBT_INFO("Ignoring a IGNORE_HEAP message because we don't need to introspect memory.");
-      }
-      break;
-    }
-
-    case MessageType::UNIGNORE_HEAP: {
-      if (remote_memory_ != nullptr) {
-        s_mc_message_ignore_memory_t message;
-        xbt_assert(size == sizeof(message), "Broken message");
-        memcpy(&message, buffer, sizeof(message));
-        get_remote_memory()->unignore_heap((void*)message.addr, message.size);
-      } else {
-        XBT_INFO("Ignoring an UNIGNORE_HEAP message because we don't need to introspect memory.");
-      }
-      break;
-    }
-
-    case MessageType::IGNORE_MEMORY: {
-      if (remote_memory_ != nullptr) {
-        s_mc_message_ignore_memory_t message;
-        xbt_assert(size == sizeof(message), "Broken message");
-        memcpy(&message, buffer, sizeof(message));
-        get_remote_memory()->ignore_region(message.addr, message.size);
-      } else {
-        XBT_INFO("Ignoring an IGNORE_MEMORY message because we don't need to introspect memory.");
-      }
-      break;
-    }
 
-    case MessageType::STACK_REGION: {
-      if (remote_memory_ != nullptr) {
-        s_mc_message_stack_region_t message;
-        xbt_assert(size == sizeof(message), "Broken message");
-        memcpy(&message, buffer, sizeof(message));
-        get_remote_memory()->stack_areas().push_back(message.stack_region);
-      } else {
-        XBT_INFO("Ignoring an STACK_REGION message because we don't need to introspect memory.");
+    case MessageType::WAITING:
+      consumed = sizeof(s_mc_message_t);
+      if (size > consumed) {
+        XBT_DEBUG("%d reinject %d bytes after a %s message", getpid(), (int)(size - consumed),
+                  to_c_str(base_message.type));
+        channel_.reinject(&buffer[consumed], size - consumed);
       }
-      break;
-    }
-
-    case MessageType::REGISTER_SYMBOL: {
-      s_mc_message_register_symbol_t message;
-      xbt_assert(size == sizeof(message), "Broken message");
-      memcpy(&message, buffer, sizeof(message));
-      xbt_assert(not message.callback, "Support for client-side function proposition is not implemented.");
-      XBT_DEBUG("Received symbol: %s", message.name.data());
 
-      LivenessChecker::automaton_register_symbol(*get_remote_memory(), message.name.data(), remote((int*)message.data));
-      break;
-    }
-
-    case MessageType::WAITING:
       return false;
 
     case MessageType::ASSERTION_FAILED:
+      // report_assertion_failure() is NORETURN, but it may change when we report more than one error per run,
+      // so please keep the consumed computation even if clang-static detects it as a dead affectation.
+      consumed = sizeof(s_mc_message_t);
       Exploration::get_instance()->report_assertion_failure();
       break;
 
     default:
       xbt_die("Unexpected message from the application");
   }
+  if (size > consumed) {
+    XBT_DEBUG("%d reinject %d bytes after a %s message", getpid(), (int)(size - consumed), to_c_str(base_message.type));
+    channel_.reinject(&buffer[consumed], size - consumed);
+  }
   return true;
 }
 
@@ -370,18 +310,11 @@ void CheckerSide::wait_for_requests()
   XBT_DEBUG("Resume the application");
   if (get_channel().send(MessageType::CONTINUE) != 0)
     throw xbt::errno_error();
-  clear_memory_cache();
 
   if (running())
     dispatch_events();
 }
 
-void CheckerSide::clear_memory_cache()
-{
-  if (remote_memory_)
-    remote_memory_->clear_cache();
-}
-
 void CheckerSide::handle_dead_child(int status)
 {
   // From PTRACE_O_TRACEEXIT:
@@ -420,7 +353,8 @@ void CheckerSide::handle_dead_child(int status)
 
 void CheckerSide::handle_waitpid()
 {
-  XBT_DEBUG("Check for wait event");
+  XBT_DEBUG("%d checks for wait event. %s", getpid(),
+            child_checker_ == nullptr ? "Wait directly." : "Ask our proxy to wait for its child.");
 
   if (child_checker_ == nullptr) { // Wait directly
     int status;
@@ -440,7 +374,6 @@ void CheckerSide::handle_waitpid()
     }
 
   } else { // Ask our proxy to wait for us
-
     s_mc_message_int_t request = {};
     request.type               = MessageType::WAIT_CHILD;
     request.value              = pid_;
index a3cb6a6..f4605e4 100644 (file)
@@ -21,7 +21,6 @@ class CheckerSide {
   event* socket_event_;
   event* signal_event_;
   std::unique_ptr<event_base, decltype(&event_base_free)> base_{nullptr, &event_base_free};
-  std::unique_ptr<RemoteProcessMemory> remote_memory_;
 
   Channel channel_;
   bool running_ = false;
@@ -31,13 +30,12 @@ class CheckerSide {
   CheckerSide* child_checker_ = nullptr;
 
   void setup_events(bool socket_only); // Part of the initialization
-  void clear_memory_cache();
   void handle_dead_child(int status); // Launched when the dying child is the PID we follow
   void handle_waitpid();              // Launched when receiving a sigchild
 
 public:
   explicit CheckerSide(int socket, CheckerSide* child_checker);
-  explicit CheckerSide(const std::vector<char*>& args, bool need_memory_introspection);
+  explicit CheckerSide(const std::vector<char*>& args);
   ~CheckerSide();
 
   // No copy:
@@ -55,7 +53,7 @@ public:
   void wait_for_requests();
 
   /* Create a new CheckerSide by forking the currently existing one, and connect it through the master_socket */
-  std::unique_ptr<CheckerSide> clone(int master_socket);
+  std::unique_ptr<CheckerSide> clone(int master_socket, const std::string& master_socket_name);
 
   /** Ask the application to run post-mortem analysis, and maybe to stop ASAP */
   void finalize(bool terminate_asap = false);
@@ -64,7 +62,6 @@ public:
   pid_t get_pid() const { return pid_; }
   bool running() const { return running_; }
   void terminate() { running_ = false; }
-  RemoteProcessMemory* get_remote_memory() { return remote_memory_.get(); }
 };
 
 } // namespace simgrid::mc
index 2900710..16efc93 100644 (file)
@@ -37,7 +37,7 @@ public:
   std::size_t get_buffer_size() const { return sizeof(T); }
   operator T() const
   {
-    static_assert(std::is_trivial<T>::value, "Cannot convert non trivial type");
+    static_assert(std::is_trivial_v<T>, "Cannot convert non trivial type");
     return *get_buffer();
   }
   void clear() { std::memset(&buffer, 0, sizeof buffer); }
index 920f43f..0c41b27 100644 (file)
 
 #include "simgrid/forward.h" // aid_t
 #include "src/mc/datatypes.h"
-#include "src/xbt/mmalloc/mmalloc.h"
 #include <xbt/utility.hpp>
 
 #include <array>
 #include <cstdint>
+#include <sys/un.h>
 
 // ***** Messages
 namespace simgrid::mc {
 
-XBT_DECLARE_ENUM_CLASS(MessageType, NONE, NEED_MEMINFO, NEED_MEMINFO_REPLY, FORK, FORK_REPLY, WAIT_CHILD,
-                       WAIT_CHILD_REPLY, CONTINUE, IGNORE_HEAP, UNIGNORE_HEAP, IGNORE_MEMORY, STACK_REGION,
-                       REGISTER_SYMBOL, DEADLOCK_CHECK, DEADLOCK_CHECK_REPLY, WAITING, SIMCALL_EXECUTE,
-                       SIMCALL_EXECUTE_REPLY, ASSERTION_FAILED, ACTORS_STATUS, ACTORS_STATUS_REPLY_COUNT,
-                       ACTORS_STATUS_REPLY_SIMCALL, ACTORS_STATUS_REPLY_TRANSITION, ACTORS_MAXPID, ACTORS_MAXPID_REPLY,
-                       FINALIZE, FINALIZE_REPLY);
+XBT_DECLARE_ENUM_CLASS(MessageType, NONE, FORK, FORK_REPLY, WAIT_CHILD, WAIT_CHILD_REPLY, CONTINUE, DEADLOCK_CHECK,
+                       DEADLOCK_CHECK_REPLY, WAITING, SIMCALL_EXECUTE, SIMCALL_EXECUTE_REPLY, ASSERTION_FAILED,
+                       ACTORS_STATUS, ACTORS_STATUS_REPLY_COUNT, ACTORS_STATUS_REPLY_SIMCALL,
+                       ACTORS_STATUS_REPLY_TRANSITION, ACTORS_MAXPID, ACTORS_MAXPID_REPLY, FINALIZE, FINALIZE_REPLY);
 } // namespace simgrid::mc
 
 constexpr unsigned MC_MESSAGE_LENGTH                 = 512;
+constexpr unsigned MC_SOCKET_NAME_LEN                = sizeof(sockaddr_un::sun_path);
 constexpr unsigned SIMCALL_SERIALIZATION_BUFFER_SIZE = 2048;
 
 /** Basic structure for a MC message
  *
- *  The current version of the client/server protocol sends C structures over `AF_LOCAL`
+ *  The current version of the client/server protocol sends C structures over `AF_UNIX`
  *  `SOCK_SEQPACKET` sockets. This means that the protocol is ABI/architecture specific:
  *  we currently can't model-check a x86 process from a x86_64 process.
  *
@@ -55,36 +54,11 @@ struct s_mc_message_int_t {
 };
 
 /* Client->Server */
-struct s_mc_message_ignore_heap_t {
-  simgrid::mc::MessageType type;
-  int block;
-  int fragment;
-  void* address;
-  size_t size;
-};
-
-struct s_mc_message_ignore_memory_t {
-  simgrid::mc::MessageType type;
-  uint64_t addr;
-  size_t size;
-};
-
-struct s_mc_message_stack_region_t {
-  simgrid::mc::MessageType type;
-  s_stack_region_t stack_region;
-};
-
-struct s_mc_message_register_symbol_t {
-  simgrid::mc::MessageType type;
-  std::array<char, 128> name;
-  int (*callback)(void*);
-  void* data;
-};
 
 /* Server -> client */
-struct s_mc_message_need_meminfo_reply_t {
+struct s_mc_message_fork_t {
   simgrid::mc::MessageType type;
-  xbt_mheap_t mmalloc_default_mdp;
+  std::array<char, MC_SOCKET_NAME_LEN> socket_name;
 };
 
 struct s_mc_message_simcall_execute_t {
diff --git a/src/mc/sosp/ChunkedData.cpp b/src/mc/sosp/ChunkedData.cpp
deleted file mode 100644 (file)
index 75c5341..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/AddressSpace.hpp"
-#include "src/mc/sosp/ChunkedData.hpp"
-
-namespace simgrid::mc {
-
-/** Take a per-page snapshot of a region
- *
- *  @param addr            The start of the region (must be at the beginning of a page)
- *  @param page_count      Number of pages of the region
- *  @return                Snapshot page numbers of this new snapshot
- */
-ChunkedData::ChunkedData(PageStore& store, const AddressSpace& as, RemotePtr<void> addr, std::size_t page_count)
-    : store_(&store)
-{
-  this->pagenos_.resize(page_count);
-  std::vector<char> buffer(xbt_pagesize);
-
-  for (size_t i = 0; i != page_count; ++i) {
-    RemotePtr<void> page = remote((void*)simgrid::mc::mmu::join(i, addr.address()));
-    xbt_assert(simgrid::mc::mmu::split(page.address()).second == 0, "Not at the beginning of a page");
-
-    /* Adding another copy (and a syscall) will probably slow things a lot.
-       TODO, optimize this somehow (at least by grouping the syscalls)
-       if needed. Either:
-       - reduce the number of syscalls
-       - let the application snapshot itself
-       - move the segments in shared memory (this will break `fork` however)
-    */
-
-    as.read_bytes(buffer.data(), xbt_pagesize, page);
-
-    pagenos_[i] = store_->store_page(buffer.data());
-  }
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/sosp/ChunkedData.hpp b/src/mc/sosp/ChunkedData.hpp
deleted file mode 100644 (file)
index c4a706f..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_CHUNKED_DATA_HPP
-#define SIMGRID_MC_CHUNKED_DATA_HPP
-
-#include <vector>
-
-#include "src/mc/mc_forward.hpp"
-#include "src/mc/remote/RemotePtr.hpp"
-#include "src/mc/sosp/PageStore.hpp"
-
-namespace simgrid::mc {
-
-/** A byte-string represented as a sequence of chunks from a PageStore
- *
- *  In order to save memory when taking memory snapshots, a given byte-string
- *  is split in fixed-size chunks. Identical chunks (either from the same
- *  snapshot or more probably from different snapshots) share the same memory
- *  storage.
- *
- *  Thus a chunked is represented as a sequence of indices of each chunk.
- */
-class ChunkedData {
-  /** This is where we store the chunks */
-  PageStore* store_ = nullptr;
-  /** Indices of the chunks in the `PageStore` */
-  std::vector<std::size_t> pagenos_;
-
-public:
-  ChunkedData() = default;
-  void clear()
-  {
-    for (std::size_t const& pageno : pagenos_)
-      store_->unref_page(pageno);
-    pagenos_.clear();
-  }
-  ~ChunkedData() { clear(); }
-
-  // Copy and move
-  ChunkedData(ChunkedData const& that) : store_(that.store_), pagenos_(that.pagenos_)
-  {
-    for (std::size_t const& pageno : pagenos_)
-      store_->ref_page(pageno);
-  }
-  ChunkedData(ChunkedData&& that) noexcept : pagenos_(std::move(that.pagenos_))
-  {
-    std::swap(store_, that.store_);
-    that.pagenos_.clear();
-  }
-  ChunkedData& operator=(ChunkedData const& that)
-  {
-    if (this != &that) {
-      this->clear();
-      store_   = that.store_;
-      pagenos_ = that.pagenos_;
-      for (std::size_t const& pageno : pagenos_)
-        store_->ref_page(pageno);
-    }
-    return *this;
-  }
-  ChunkedData& operator=(ChunkedData&& that) noexcept
-  {
-    if (this != &that) {
-      this->clear();
-      store_      = that.store_;
-      that.store_ = nullptr;
-      pagenos_    = std::move(that.pagenos_);
-      that.pagenos_.clear();
-    }
-    return *this;
-  }
-
-  /** How many pages are used */
-  std::size_t page_count() const { return pagenos_.size(); }
-
-  /** Get a chunk index */
-  std::size_t pageno(std::size_t i) const { return pagenos_[i]; }
-
-  /** Get a view of the chunk indices */
-  const std::size_t* pagenos() const { return pagenos_.data(); }
-
-  /** Get a pointer to a chunk */
-  void* page(std::size_t i) const { return store_->get_page(pagenos_[i]); }
-
-  ChunkedData(PageStore& store, const AddressSpace& as, RemotePtr<void> addr, std::size_t page_count);
-};
-
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/sosp/PageStore.cpp b/src/mc/sosp/PageStore.cpp
deleted file mode 100644 (file)
index 83061b0..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <sys/mman.h>
-#ifdef __FreeBSD__
-#define MAP_POPULATE MAP_PREFAULT_READ
-#endif
-
-#include "src/internal_config.h"
-#include "xbt/log.h"
-#include "xbt/sysdep.h"
-
-#include "src/3rd-party/xxhash.hpp"
-#include "src/mc/mc_mmu.hpp"
-#include "src/mc/sosp/PageStore.hpp"
-
-#include <cstring> // memcpy, memcmp
-#include <unistd.h>
-
-namespace simgrid::mc {
-
-/** @brief Compute a hash for the given memory page
- *
- *  The page is used before inserting the page in the page store in order to find duplicate of this page in the page
- *  store.
- *
- *  @param data Memory page
- *  @return hash off the page
- */
-static XBT_ALWAYS_INLINE PageStore::hash_type mc_hash_page(const void* data)
-{
-  return xxh::xxhash<64>(data, xbt_pagesize);
-}
-
-// ***** snapshot_page_manager
-
-PageStore::PageStore(std::size_t size) : capacity_(size)
-{
-  // Using mmap in order to be able to expand the region by relocating it somewhere else in the virtual memory space:
-  void* memory =
-      ::mmap(nullptr, size << xbt_pagebits, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
-  xbt_assert(memory != MAP_FAILED, "Could not mmap initial snapshot pages.");
-
-  this->top_index_ = 0;
-  this->memory_    = memory;
-  this->page_counts_.resize(size);
-}
-
-PageStore::~PageStore()
-{
-  ::munmap(this->memory_, this->capacity_ << xbt_pagebits);
-}
-
-void PageStore::resize(std::size_t size)
-{
-  size_t old_bytesize = this->capacity_ << xbt_pagebits;
-  size_t new_bytesize = size << xbt_pagebits;
-  void* new_memory;
-
-  // Expand the memory region by moving it into another
-  // virtual memory address if necessary:
-#if HAVE_MREMAP
-  new_memory = mremap(this->memory_, old_bytesize, new_bytesize, MREMAP_MAYMOVE);
-  xbt_assert(new_memory != MAP_FAILED, "Could not mremap snapshot pages.");
-#else
-  if (new_bytesize > old_bytesize) {
-    // Grow: first try to add new space after current map
-    new_memory = mmap((char*)this->memory_ + old_bytesize, new_bytesize - old_bytesize, PROT_READ | PROT_WRITE,
-                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
-    xbt_assert(new_memory != MAP_FAILED, "Could not mremap snapshot pages.");
-    // Check if expanding worked
-    if (new_memory != (char*)this->memory_ + old_bytesize) {
-      // New memory segment could not be put at the end of this->memory_,
-      // so cancel this one and try to relocate everything and copy data
-      munmap(new_memory, new_bytesize - old_bytesize);
-      new_memory =
-          mmap(nullptr, new_bytesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
-      xbt_assert(new_memory != MAP_FAILED, "Could not mremap snapshot pages.");
-      memcpy(new_memory, this->memory_, old_bytesize);
-      munmap(this->memory_, old_bytesize);
-    }
-  } else {
-    // We don't have functions to shrink a mapping, so leave memory as
-    // it is for now
-    new_memory = this->memory_;
-  }
-#endif
-
-  this->capacity_ = size;
-  this->memory_   = new_memory;
-  this->page_counts_.resize(size, 0);
-}
-
-/** Allocate a free page
- *
- *  @return index of the free page
- */
-std::size_t PageStore::alloc_page()
-{
-  if (this->free_pages_.empty()) {
-    // Expand the region:
-    if (this->top_index_ == this->capacity_)
-      // All the pages are allocated, we need add more pages:
-      this->resize(2 * this->capacity_);
-
-    // Use a page from the top:
-    return this->top_index_++;
-  } else {
-    // Use a page from free_pages_ (inside of the region):
-    size_t res = this->free_pages_[this->free_pages_.size() - 1];
-    this->free_pages_.pop_back();
-    return res;
-  }
-}
-
-void PageStore::remove_page(std::size_t pageno)
-{
-  this->free_pages_.push_back(pageno);
-  const void* page = this->get_page(pageno);
-  hash_type hash   = mc_hash_page(page);
-  this->hash_index_[hash].erase(pageno);
-}
-
-/** Store a page in memory */
-std::size_t PageStore::store_page(const void* page)
-{
-  xbt_assert(top_index_ <= this->capacity_, "top_index is not consistent");
-
-  // First, we check if a page with the same content is already in the page store:
-  //  1. compute the hash of the page
-  //  2. find pages with the same hash using `hash_index_`
-  //  3. find a page with the same content
-  hash_type hash = mc_hash_page(page);
-
-  // Try to find a duplicate in set of pages with the same hash:
-  page_set_type& page_set = this->hash_index_[hash];
-  for (size_t const& pageno : page_set) {
-    const void* snapshot_page = this->get_page(pageno);
-    if (memcmp(page, snapshot_page, xbt_pagesize) == 0) {
-      // If a page with the same content is already in the page store it's reused and its refcount is incremented.
-      page_counts_[pageno]++;
-      return pageno;
-    }
-  }
-
-  // Otherwise, a new page is allocated in the page store and the content of the page is `memcpy()`-ed to this new page.
-  std::size_t pageno = alloc_page();
-  xbt_assert(this->page_counts_[pageno] == 0, "Allocated page is already used");
-  void* snapshot_page = this->get_page(pageno);
-  memcpy(snapshot_page, page, xbt_pagesize);
-  page_set.insert(pageno);
-  page_counts_[pageno]++;
-  return pageno;
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/sosp/PageStore.hpp b/src/mc/sosp/PageStore.hpp
deleted file mode 100644 (file)
index 034512c..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_PAGESTORE_HPP
-#define SIMGRID_MC_PAGESTORE_HPP
-
-#include "src/mc/mc_forward.hpp"
-#include "src/mc/mc_mmu.hpp"
-
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#ifndef XBT_ALWAYS_INLINE
-#define XBT_ALWAYS_INLINE inline __attribute__((always_inline))
-#endif
-
-namespace simgrid::mc {
-
-/** @brief Storage for snapshot memory pages
- *
- * The first (lower) layer of the per-page snapshot mechanism is a page store:
- * its responsibility is to store immutable shareable reference-counted memory
- * pages independently of the snapshotting logic. Snapshot management and
- * representation is handled to an higher layer. READMORE
- *
- * Data structure:
- *
- *  * A pointer (`memory_`) to a (currently anonymous) `mmap()`ed memory
- *    region holding the memory pages (the address of the first page).
- *
- *    We want to keep this memory region aligned on the memory pages (so
- *    that we might be able to create non-linear memory mappings on those
- *    pages in the future) and be able to expand it without copying the
- *    data (there will be a lot of pages here): we will be able to
- *    efficiently expand the memory mapping using `mremap()`, moving it
- *    to another virtual address if necessary.
- *
- *    Because we will move this memory mapping on the virtual address
- *    space, only the index of the page will be stored in the snapshots
- *    and the page will always be looked up by going through `memory`:
- *
- *         void* page = (char*) page_store->memory + page_index << pagebits;
- *
- *  * The number of pages mapped in virtual memory (`capacity_`). Once all
- *    those pages are used, we need to expand the page store with
- *    `mremap()`.
- *
- *  * A reference count for each memory page `page_counts_`. Each time a
- *    snapshot references a page, the counter is incremented. If a
- *    snapshot is freed, the reference count is decremented. When the
- *    reference count, of a page reaches 0 it is added to a list of available
- *    pages (`free_pages_`).
- *
- *  * A list of free pages `free_pages_` which can be reused. This avoids having
- *    to scan the reference count list to find a free page.
- *
- *  * When we are expanding the memory map we do not want to add thousand of page
- *    to the `free_pages_` list and remove them just afterwards. The `top_index_`
- *    field is an index after which all pages are free and are not in the `free_pages_`
- *    list.
- *
- *  * When we are adding a page, we need to check if a page with the same
- *    content is already in the page store in order to reuse it. For this
- *    reason, we maintain an index (`hash_index_`) mapping the hash of a
- *    page to the list of page indices with this hash.
- *    We use a fast (non cryptographic) hash so there may be conflicts:
- *    we must be able to store multiple indices for the same hash.
- *
- */
-class PageStore {
-public: // Types
-  using hash_type = std::uint64_t;
-
-private:
-  // Types
-  // We are using a cheap hash to index a page.
-  // We should expect collision and we need to associate multiple page indices
-  // to the same hash.
-  using page_set_type  = std::unordered_set<std::size_t>;
-  using pages_map_type = std::unordered_map<hash_type, page_set_type>;
-
-  // Fields:
-  /** First page */
-  void* memory_;
-  /** Number of available pages in virtual memory */
-  std::size_t capacity_;
-  /** Top of the used pages (index of the next available page) */
-  std::size_t top_index_;
-  /** Page reference count */
-  std::vector<std::uint64_t> page_counts_;
-  /** Index of available pages before the top */
-  std::vector<std::size_t> free_pages_;
-  /** Index from page hash to page index */
-  pages_map_type hash_index_;
-
-  // Methods
-  void resize(std::size_t size);
-  std::size_t alloc_page();
-  void remove_page(std::size_t pageno);
-
-public:
-  // Constructors
-  PageStore(PageStore const&) = delete;
-  PageStore& operator=(PageStore const&) = delete;
-  explicit PageStore(std::size_t size);
-  ~PageStore();
-
-  // Methods
-
-  /** @brief Decrement the reference count for a given page
-   *
-   * Decrement the reference count of this page. Used when a snapshot is destroyed.
-   *
-   * If the reference count reaches zero, the page is recycled:
-   * it is added to the `free_pages_` list and removed from the `hash_index_`.
-   *
-   * */
-  void unref_page(std::size_t pageno);
-
-  /** @brief Increment the refcount for a given page
-   *
-   * This method used to increase a reference count of a page if we know
-   * that the content of a page is the same as a page already in the page
-   * store.
-   *
-   * This will be the case if a page if soft clean: we know that is has not
-   * changed since the previous snapshot/restoration and we can avoid
-   * hashing the page, comparing byte-per-byte to candidates.
-   * */
-  void ref_page(size_t pageno);
-
-  /** @brief Store a page in the page store */
-  std::size_t store_page(const void* page);
-
-  /** @brief Get a page from its page number
-   *
-   *  @param pageno Number of the memory page in the store
-   *  @return Start of the page
-   */
-  void* get_page(std::size_t pageno) const;
-
-  // Debug/test methods
-
-  /** @brief Get the number of references for a page */
-  std::size_t get_ref(std::size_t pageno) const;
-
-  /** @brief Get the number of used pages */
-  std::size_t size() const;
-
-  /** @brief Get the capacity of the page store
-   *
-   *  The capacity is expanded by a system call (mremap).
-   * */
-  std::size_t capacity() const;
-};
-
-XBT_ALWAYS_INLINE void PageStore::unref_page(std::size_t pageno)
-{
-  if ((--this->page_counts_[pageno]) == 0)
-    this->remove_page(pageno);
-}
-
-XBT_ALWAYS_INLINE void PageStore::ref_page(size_t pageno)
-{
-  ++this->page_counts_[pageno];
-}
-
-XBT_ALWAYS_INLINE void* PageStore::get_page(std::size_t pageno) const
-{
-  return (void*)simgrid::mc::mmu::join(pageno, (std::uintptr_t)this->memory_);
-}
-
-XBT_ALWAYS_INLINE std::size_t PageStore::get_ref(std::size_t pageno) const
-{
-  return this->page_counts_[pageno];
-}
-
-XBT_ALWAYS_INLINE std::size_t PageStore::size() const
-{
-  return this->top_index_ - this->free_pages_.size();
-}
-
-XBT_ALWAYS_INLINE std::size_t PageStore::capacity() const
-{
-  return this->capacity_;
-}
-
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/sosp/PageStore_test.cpp b/src/mc/sosp/PageStore_test.cpp
deleted file mode 100644 (file)
index 05e1d72..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/3rd-party/catch.hpp"
-
-#include <array>
-#include <cstdint>
-#include <cstring>
-#include <iostream>
-
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <memory>
-
-#include "src/mc/sosp/PageStore.hpp"
-
-using simgrid::mc::PageStore;
-
-/***********************************/
-// a class to hold the variable used in the test cases
-class helper_tests {
-public:
-  static std::size_t pagesize;
-  static std::unique_ptr<PageStore> store;
-  static void* data;
-  static std::array<size_t, 4> pageno;
-  static int value;
-
-  // member functions used by the test suite(s)
-  static void Init();
-  static void store_page_once();
-  static void store_same_page();
-  static void store_new_page();
-  static void unref_pages();
-  static void reallocate_page();
-
-  static void new_content(void* buf, std::size_t size);
-};
-
-// static member data initialization
-std::size_t helper_tests::pagesize             = 0;
-std::unique_ptr<PageStore> helper_tests::store = nullptr;
-void* helper_tests::data                       = nullptr;
-std::array<size_t, 4> helper_tests::pageno     = {{0, 0, 0, 0}};
-int helper_tests::value                        = 0;
-
-void helper_tests::Init()
-{
-  pagesize = (size_t)getpagesize();
-  store    = std::make_unique<simgrid::mc::PageStore>(50);
-  data     = mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  REQUIRE(store->size() == 0);
-}
-
-void helper_tests::store_page_once()
-{
-  new_content(data, pagesize);
-  pageno[0] = store->store_page(data);
-  REQUIRE(store->get_ref(pageno[0]) == 1);
-  const void* copy = store->get_page(pageno[0]);
-  REQUIRE(::memcmp(data, copy, pagesize) == 0); // The page data should be the same
-  REQUIRE(store->size() == 1);
-}
-
-void helper_tests::store_same_page()
-{
-  pageno[1] = store->store_page(data);
-  REQUIRE(pageno[0] == pageno[1]); // Page should be the same
-  REQUIRE(store->get_ref(pageno[0]) == 2);
-  REQUIRE(store->size() == 1);
-}
-
-void helper_tests::store_new_page()
-{
-  new_content(data, pagesize);
-  pageno[2] = store->store_page(data);
-  REQUIRE(pageno[0] != pageno[2]); // The new page should be different
-  REQUIRE(store->size() == 2);
-}
-
-void helper_tests::unref_pages()
-{
-  store->unref_page(pageno[0]);
-  REQUIRE(store->get_ref(pageno[0]) == 1);
-  REQUIRE(store->size() == 2);
-
-  store->unref_page(pageno[1]);
-  REQUIRE(store->size() == 1);
-}
-
-void helper_tests::reallocate_page()
-{
-  new_content(data, pagesize);
-  pageno[3] = store->store_page(data);
-  REQUIRE(pageno[0] == pageno[3]); // The old page should be reused
-  REQUIRE(store->get_ref(pageno[3]) == 1);
-  REQUIRE(store->size() == 2);
-}
-
-void helper_tests::new_content(void* buf, std::size_t size)
-{
-  value++;
-  ::memset(buf, value, size);
-}
-
-TEST_CASE("MC page store, used during checkpoint", "MC::PageStore")
-{
-  helper_tests::Init();
-  INFO("Store page once");
-  helper_tests::store_page_once();
-
-  INFO("Store the same page");
-  helper_tests::store_same_page();
-
-  INFO("Store a new page");
-  helper_tests::store_new_page();
-
-  INFO("Unref pages");
-  helper_tests::unref_pages();
-
-  INFO("Reallocate pages");
-  helper_tests::reallocate_page();
-}
diff --git a/src/mc/sosp/Region.cpp b/src/mc/sosp/Region.cpp
deleted file mode 100644 (file)
index 2dca797..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/sosp/Region.hpp"
-#include "src/mc/mc_config.hpp"
-#include "src/mc/mc_forward.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-
-#include <cstdlib>
-#include <sys/mman.h>
-#ifdef __FreeBSD__
-#define MAP_POPULATE MAP_PREFAULT_READ
-#endif
-
-namespace simgrid::mc {
-
-Region::Region(PageStore& store, const RemoteProcessMemory& memory, RegionType region_type, void* start_addr,
-               size_t size)
-    : region_type_(region_type), start_addr_(start_addr), size_(size)
-{
-  xbt_assert((((uintptr_t)start_addr) & (xbt_pagesize - 1)) == 0, "Start address not at the beginning of a page");
-
-  chunks_ = ChunkedData(store, memory, RemotePtr<void>(start_addr), mmu::chunk_count(size));
-}
-
-/** @brief Restore a region from a snapshot
- *
- *  @param region     Target region
- */
-void Region::restore(const RemoteProcessMemory& memory) const
-{
-  xbt_assert(((start().address()) & (xbt_pagesize - 1)) == 0, "Not at the beginning of a page");
-  xbt_assert(simgrid::mc::mmu::chunk_count(size()) == get_chunks().page_count());
-
-  for (size_t i = 0; i != get_chunks().page_count(); ++i) {
-    auto* target_page       = (void*)simgrid::mc::mmu::join(i, (std::uintptr_t)(void*)start().address());
-    const void* source_page = get_chunks().page(i);
-    memory.write_bytes(source_page, xbt_pagesize, remote(target_page));
-  }
-}
-
-static XBT_ALWAYS_INLINE void* mc_translate_address_region(uintptr_t addr, const simgrid::mc::Region* region)
-{
-  auto [pageno, offset] = simgrid::mc::mmu::split(addr - region->start().address());
-  void* snapshot_page   = region->get_chunks().page(pageno);
-  return (char*)snapshot_page + offset;
-}
-
-void* Region::read(void* target, const void* addr, std::size_t size) const
-{
-  xbt_assert(contain(simgrid::mc::remote(addr)), "Trying to read out of the region boundary.");
-
-  // Last byte of the region:
-  const void* end_addr = (const char*)addr + size - 1;
-  if (simgrid::mc::mmu::same_chunk((std::uintptr_t)addr, (std::uintptr_t)end_addr)) {
-    // The memory is contained in a single page:
-    return mc_translate_address_region((uintptr_t)addr, this);
-  }
-  // Otherwise, the memory spans several pages. Let's copy it all into the provided buffer
-  xbt_assert(target != nullptr, "Missing destination buffer for fragmented memory access");
-
-  // TODO, we assume the chunks are aligned to natural chunk boundaries.
-  // We should remove this assumption.
-
-  // Page of the last byte of the memory area:
-  size_t page_end = simgrid::mc::mmu::split((std::uintptr_t)end_addr).first;
-
-  void* dest = target; // iterator in the buffer to where we should copy next
-
-  // Read each page:
-  while (simgrid::mc::mmu::split((std::uintptr_t)addr).first != page_end) {
-    const void* snapshot_addr = mc_translate_address_region((uintptr_t)addr, this);
-    auto* next_page     = (void*)simgrid::mc::mmu::join(simgrid::mc::mmu::split((std::uintptr_t)addr).first + 1, 0);
-    size_t readable     = (char*)next_page - (const char*)addr;
-    memcpy(dest, snapshot_addr, readable);
-    addr = (const char*)addr + readable;
-    dest = (char*)dest + readable;
-    size -= readable;
-  }
-
-  // Read the end:
-  const void* snapshot_addr = mc_translate_address_region((uintptr_t)addr, this);
-  memcpy(dest, snapshot_addr, size);
-
-  return target;
-}
-
-} // namespace simgrid::mc
-
-/** Compare memory between snapshots (with known regions)
- *
- * @param addr1 Address in the first snapshot
- * @param region1 Region of the address in the first snapshot
- * @param addr2 Address in the second snapshot
- * @param region2 Region of the address in the second snapshot
- * @return same semantic as memcmp
- */
-int MC_snapshot_region_memcmp(const void* addr1, const simgrid::mc::Region* region1, const void* addr2,
-                              const simgrid::mc::Region* region2, size_t size)
-{
-  // Using alloca() for large allocations may trigger stack overflow:
-  // use malloc if the buffer is too big.
-  bool stack_alloc    = size < 64;
-  void* buffer1a      = stack_alloc ? alloca(size) : ::operator new(size);
-  void* buffer2a      = stack_alloc ? alloca(size) : ::operator new(size);
-  const void* buffer1 = region1->read(buffer1a, addr1, size);
-  const void* buffer2 = region2->read(buffer2a, addr2, size);
-  int res;
-  if (buffer1 == buffer2)
-    res = 0;
-  else
-    res = memcmp(buffer1, buffer2, size);
-  if (not stack_alloc) {
-    ::operator delete(buffer1a);
-    ::operator delete(buffer2a);
-  }
-  return res;
-}
diff --git a/src/mc/sosp/Region.hpp b/src/mc/sosp/Region.hpp
deleted file mode 100644 (file)
index 7ab26e2..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_SOSP_REGION_HPP
-#define SIMGRID_MC_SOSP_REGION_HPP
-
-#include "src/mc/remote/RemotePtr.hpp"
-#include "src/mc/sosp/ChunkedData.hpp"
-
-#include <memory>
-#include <vector>
-
-namespace simgrid::mc {
-
-enum class RegionType { Heap = 1, Data = 2 };
-
-/** A copy/snapshot of a given memory region, where identical pages are stored only once */
-class Region {
-public:
-  static const RegionType HeapRegion    = RegionType::Heap;
-  static const RegionType DataRegion    = RegionType::Data;
-
-private:
-  RegionType region_type_;
-  simgrid::mc::ObjectInformation* object_info_ = nullptr;
-
-  /** @brief  Virtual address of the region in the simulated process */
-  void* start_addr_ = nullptr;
-
-  /** @brief Size of the data region in bytes */
-  std::size_t size_ = 0;
-
-  ChunkedData chunks_;
-
-public:
-  Region(PageStore& store, const RemoteProcessMemory& memory, RegionType type, void* start_addr, size_t size);
-  Region(Region const&) = delete;
-  Region& operator=(Region const&) = delete;
-  Region(Region&& that)            = delete;
-  Region& operator=(Region&& that) = delete;
-
-  // Data
-
-  ChunkedData const& get_chunks() const { return chunks_; }
-
-  simgrid::mc::ObjectInformation* object_info() const { return object_info_; }
-  void object_info(simgrid::mc::ObjectInformation* info) { object_info_ = info; }
-
-  // Other getters
-
-  RemotePtr<void> start() const { return remote(start_addr_); }
-  RemotePtr<void> end() const { return remote((char*)start_addr_ + size_); }
-  std::size_t size() const { return size_; }
-  RegionType region_type() const { return region_type_; }
-
-  bool contain(RemotePtr<void> p) const { return p >= start() && p < end(); }
-
-  /** @brief Restore a region from a snapshot */
-  void restore(const RemoteProcessMemory& memory) const;
-
-  /** @brief Read memory that was snapshotted in this region
-   *
-   *  @param target  Buffer to store contiguously the value if it spans over several pages
-   *  @param addr    Process (non-snapshot) address of the data
-   *  @param size    Size of the data to read in bytes
-   *  @return Pointer where the data is located (either target buffer or original location)
-   */
-  void* read(void* target, const void* addr, std::size_t size) const;
-};
-
-} // namespace simgrid::mc
-
-int MC_snapshot_region_memcmp(const void* addr1, const simgrid::mc::Region* region1, const void* addr2,
-                              const simgrid::mc::Region* region2, std::size_t size);
-
-static XBT_ALWAYS_INLINE void* MC_region_read_pointer(const simgrid::mc::Region* region, const void* addr)
-{
-  void* res;
-  return *(void**)region->read(&res, addr, sizeof(void*));
-}
-
-#endif
diff --git a/src/mc/sosp/RemoteProcessMemory.cpp b/src/mc/sosp/RemoteProcessMemory.cpp
deleted file mode 100644 (file)
index 18093b3..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#define _FILE_OFFSET_BITS 64 /* needed for pread_whole to work as expected on 32bits */
-
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-
-#include "src/mc/explo/Exploration.hpp"
-#include "src/mc/explo/LivenessChecker.hpp"
-#include "src/mc/sosp/Snapshot.hpp"
-#include "xbt/file.hpp"
-#include "xbt/log.h"
-#include "xbt/system_error.hpp"
-
-#include <fcntl.h>
-#include <libunwind-ptrace.h>
-#include <sys/mman.h> // PROT_*
-
-#include <algorithm>
-#include <cerrno>
-#include <cstring>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <string_view>
-
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_process, mc, "MC process information");
-
-namespace simgrid::mc {
-
-// ***** Helper stuff
-
-static bool is_filtered_lib(std::string_view libname)
-{
-  return libname != "libsimgrid";
-}
-
-static std::string get_lib_name(const std::string& pathname)
-{
-  std::string map_basename = simgrid::xbt::Path(pathname).get_base_name();
-  std::string libname;
-
-  if (size_t pos = map_basename.rfind(".so"); pos != std::string::npos) {
-    // strip the extension (matching regex "\.so.*$")
-    libname.assign(map_basename, 0, pos);
-
-    // strip the version suffix (matching regex "-[.0-9-]*$")
-    while (true) {
-      pos = libname.rfind('-');
-      if (pos == std::string::npos || libname.find_first_not_of(".0123456789", pos + 1) != std::string::npos)
-        break;
-      libname.erase(pos);
-    }
-  }
-
-  return libname;
-}
-
-static ssize_t pread_whole(int fd, void* buf, size_t count, off_t offset)
-{
-  auto* buffer       = static_cast<char*>(buf);
-  ssize_t real_count = count;
-  while (count) {
-    ssize_t res = pread(fd, buffer, count, offset);
-    if (res > 0) {
-      count -= res;
-      buffer += res;
-      offset += res;
-    } else if (res == 0)
-      return -1;
-    else if (errno != EINTR) {
-      XBT_ERROR("pread_whole: %s", strerror(errno));
-      return -1;
-    }
-  }
-  return real_count;
-}
-
-static ssize_t pwrite_whole(int fd, const void* buf, size_t count, off_t offset)
-{
-  const auto* buffer = static_cast<const char*>(buf);
-  ssize_t real_count = count;
-  while (count) {
-    ssize_t res = pwrite(fd, buffer, count, offset);
-    if (res > 0) {
-      count -= res;
-      buffer += res;
-      offset += res;
-    } else if (res == 0)
-      return -1;
-    else if (errno != EINTR) {
-      XBT_ERROR("pwrite_whole: %s", strerror(errno));
-      return -1;
-    }
-  }
-  return real_count;
-}
-
-int open_vm(pid_t pid, int flags)
-{
-  std::string buffer = "/proc/" + std::to_string(pid) + "/mem";
-  return open(buffer.c_str(), flags);
-}
-
-// ***** RemoteProcessMemory
-
-RemoteProcessMemory::RemoteProcessMemory(pid_t pid, xbt_mheap_t mmalloc_default_mdp) : AddressSpace(this), pid_(pid)
-{
-  this->heap_address = remote(mmalloc_default_mdp);
-
-  this->memory_map_ = simgrid::xbt::get_memory_map(this->pid_);
-  this->init_memory_map_info();
-
-  int fd = open_vm(this->pid_, O_RDWR);
-  xbt_assert(fd >= 0, "Could not open file for process virtual address space");
-  this->memory_file = fd;
-
-  this->unw_addr_space            = simgrid::mc::UnwindContext::createUnwindAddressSpace();
-  this->unw_underlying_addr_space = simgrid::unw::create_addr_space();
-  this->unw_underlying_context    = simgrid::unw::create_context(this->unw_underlying_addr_space, this->pid_);
-
-  auto ignored_local_variables = {
-      std::make_pair("e", "*"),
-      std::make_pair("_log_ev", "*"),
-
-      /* Ignore local variable about time used for tracing */
-      std::make_pair("start_time", "*"),
-  };
-  for (auto const& [var, frame] : ignored_local_variables)
-    ignore_local_variable(var, frame);
-
-  ignore_global_variable("counter"); // Static variable used for tracing
-}
-
-RemoteProcessMemory::~RemoteProcessMemory()
-{
-  if (this->memory_file >= 0)
-    close(this->memory_file);
-
-  if (this->unw_underlying_addr_space != unw_local_addr_space) {
-    if (this->unw_underlying_addr_space)
-      unw_destroy_addr_space(this->unw_underlying_addr_space);
-    if (this->unw_underlying_context)
-      _UPT_destroy(this->unw_underlying_context);
-  }
-
-  unw_destroy_addr_space(this->unw_addr_space);
-}
-
-/** Refresh the information about the process
- *
- *  Do not use directly, this is used by the getters when appropriate
- *  in order to have fresh data.
- */
-void RemoteProcessMemory::refresh_heap()
-{
-  // Read/dereference/refresh the std_heap pointer:
-  this->read(this->heap.get(), this->heap_address);
-  this->cache_flags_ |= RemoteProcessMemory::cache_heap;
-}
-
-/** Refresh the information about the process
- *
- *  Do not use directly, this is used by the getters when appropriate
- *  in order to have fresh data.
- * */
-void RemoteProcessMemory::refresh_malloc_info()
-{
-  // Refresh process->heapinfo:
-  if (this->cache_flags_ & RemoteProcessMemory::cache_malloc)
-    return;
-  size_t count = this->heap->heaplimit + 1;
-  if (this->heap_info.size() < count)
-    this->heap_info.resize(count);
-  this->read_bytes(this->heap_info.data(), count * sizeof(malloc_info), remote(this->heap->heapinfo));
-  this->cache_flags_ |= RemoteProcessMemory::cache_malloc;
-}
-std::size_t RemoteProcessMemory::get_remote_heap_bytes()
-{
-  return mmalloc_get_bytes_used_remote(get_heap()->heaplimit, get_malloc_info());
-}
-
-/** @brief Finds the range of the different memory segments and binary paths */
-void RemoteProcessMemory::init_memory_map_info()
-{
-  XBT_DEBUG("Get debug information ...");
-  this->maestro_stack_start_ = nullptr;
-  this->maestro_stack_end_   = nullptr;
-  this->object_infos.clear();
-  this->binary_info = nullptr;
-
-  std::vector<simgrid::xbt::VmMap> const& maps = this->memory_map_;
-
-  const char* current_name = nullptr;
-
-  for (size_t i = 0; i < maps.size(); i++) {
-    simgrid::xbt::VmMap const& reg = maps[i];
-    const char* pathname           = maps[i].pathname.c_str();
-
-    // Nothing to do
-    if (maps[i].pathname.empty()) {
-      current_name = nullptr;
-      continue;
-    }
-
-    // [stack], [vvar], [vsyscall], [vdso] ...
-    if (pathname[0] == '[') {
-      if ((reg.prot & PROT_WRITE) && not memcmp(pathname, "[stack]", 7)) {
-        this->maestro_stack_start_ = remote(reg.start_addr);
-        this->maestro_stack_end_   = remote(reg.end_addr);
-      }
-      current_name = nullptr;
-      continue;
-    }
-
-    if (current_name && strcmp(current_name, pathname) == 0)
-      continue;
-
-    current_name = pathname;
-    if (not(reg.prot & PROT_READ) && (reg.prot & PROT_EXEC))
-      continue;
-
-    const bool is_executable = not i;
-    std::string libname;
-    if (not is_executable) {
-      libname = get_lib_name(pathname);
-      if (is_filtered_lib(libname)) {
-        continue;
-      }
-    }
-
-    std::shared_ptr<simgrid::mc::ObjectInformation> info =
-        simgrid::mc::createObjectInformation(this->memory_map_, pathname);
-    this->object_infos.push_back(info);
-    if (is_executable)
-      this->binary_info = info;
-  }
-
-  xbt_assert(this->maestro_stack_start_, "Did not find maestro_stack_start");
-  xbt_assert(this->maestro_stack_end_, "Did not find maestro_stack_end");
-
-  XBT_DEBUG("Get debug information done !");
-}
-
-std::shared_ptr<simgrid::mc::ObjectInformation> RemoteProcessMemory::find_object_info(RemotePtr<void> addr) const
-{
-  for (auto const& object_info : this->object_infos)
-    if (addr.address() >= (std::uint64_t)object_info->start && addr.address() <= (std::uint64_t)object_info->end)
-      return object_info;
-  return nullptr;
-}
-
-std::shared_ptr<ObjectInformation> RemoteProcessMemory::find_object_info_exec(RemotePtr<void> addr) const
-{
-  for (std::shared_ptr<ObjectInformation> const& info : this->object_infos)
-    if (addr.address() >= (std::uint64_t)info->start_exec && addr.address() <= (std::uint64_t)info->end_exec)
-      return info;
-  return nullptr;
-}
-
-std::shared_ptr<ObjectInformation> RemoteProcessMemory::find_object_info_rw(RemotePtr<void> addr) const
-{
-  for (std::shared_ptr<ObjectInformation> const& info : this->object_infos)
-    if (addr.address() >= (std::uint64_t)info->start_rw && addr.address() <= (std::uint64_t)info->end_rw)
-      return info;
-  return nullptr;
-}
-
-simgrid::mc::Frame* RemoteProcessMemory::find_function(RemotePtr<void> ip) const
-{
-  std::shared_ptr<simgrid::mc::ObjectInformation> info = this->find_object_info_exec(ip);
-  return info ? info->find_function((void*)ip.address()) : nullptr;
-}
-
-/** Find (one occurrence of) the named variable definition
- */
-const simgrid::mc::Variable* RemoteProcessMemory::find_variable(const char* name) const
-{
-  // First lookup the variable in the executable shared object.
-  // A global variable used directly by the executable code from a library
-  // is reinstantiated in the executable memory .data/.bss.
-  // We need to look up the variable in the executable first.
-  if (this->binary_info) {
-    std::shared_ptr<simgrid::mc::ObjectInformation> const& info = this->binary_info;
-    const simgrid::mc::Variable* var                            = info->find_variable(name);
-    if (var)
-      return var;
-  }
-
-  for (std::shared_ptr<simgrid::mc::ObjectInformation> const& info : this->object_infos) {
-    const simgrid::mc::Variable* var = info->find_variable(name);
-    if (var)
-      return var;
-  }
-
-  return nullptr;
-}
-
-void RemoteProcessMemory::read_variable(const char* name, void* target, size_t size) const
-{
-  const simgrid::mc::Variable* var = this->find_variable(name);
-  xbt_assert(var, "Variable %s not found", name);
-  xbt_assert(var->address, "No simple location for this variable");
-
-  if (not var->type->full_type) // Try to resolve this type. The needed ObjectInfo was maybe (lazily) loaded recently
-    for (auto const& object_info : this->object_infos)
-      postProcessObjectInformation(this, object_info.get());
-  xbt_assert(var->type->full_type, "Partial type for %s (even after re-resolving types), cannot retrieve its size.",
-             name);
-  xbt_assert((size_t)var->type->full_type->byte_size == size, "Unexpected size for %s (expected %zu, received %zu).",
-             name, size, (size_t)var->type->full_type->byte_size);
-  this->read_bytes(target, size, remote(var->address));
-}
-
-std::string RemoteProcessMemory::read_string(RemotePtr<char> address) const
-{
-  if (not address)
-    return {};
-
-  std::vector<char> res(128);
-  off_t off = 0;
-
-  while (true) {
-    ssize_t c = pread(this->memory_file, res.data() + off, res.size() - off, (off_t)address.address() + off);
-    if (c == -1 && errno == EINTR)
-      continue;
-    xbt_assert(c > 0, "Could not read string from remote process");
-
-    if (memchr(res.data() + off, '\0', c))
-      return res.data();
-
-    off += c;
-    if (off == (off_t)res.size())
-      res.resize(res.size() * 2);
-  }
-}
-
-void* RemoteProcessMemory::read_bytes(void* buffer, std::size_t size, RemotePtr<void> address,
-                                      ReadOptions /*options*/) const
-{
-  xbt_assert(pread_whole(this->memory_file, buffer, size, (size_t)address.address()) != -1,
-             "Read at %p from process %lli failed", (void*)address.address(), (long long)this->pid_);
-  return buffer;
-}
-
-/** Write data to a process memory
- *
- *  @param buffer   local memory address (source)
- *  @param len      data size
- *  @param address  target process memory address (target)
- */
-void RemoteProcessMemory::write_bytes(const void* buffer, size_t len, RemotePtr<void> address) const
-{
-  xbt_assert(pwrite_whole(this->memory_file, buffer, len, (size_t)address.address()) != -1,
-             "Write to process %lli failed", (long long)this->pid_);
-}
-
-static void zero_buffer_init(const void** zero_buffer, size_t zero_buffer_size)
-{
-  int fd = open("/dev/zero", O_RDONLY);
-  xbt_assert(fd >= 0, "Could not open /dev/zero");
-  *zero_buffer = mmap(nullptr, zero_buffer_size, PROT_READ, MAP_SHARED, fd, 0);
-  xbt_assert(*zero_buffer != MAP_FAILED, "Could not map the zero buffer");
-  close(fd);
-}
-
-void RemoteProcessMemory::clear_bytes(RemotePtr<void> address, size_t len) const
-{
-  static constexpr size_t zero_buffer_size = 10 * 4096;
-  static const void* zero_buffer;
-  static std::once_flag zero_buffer_flag;
-
-  std::call_once(zero_buffer_flag, zero_buffer_init, &zero_buffer, zero_buffer_size);
-  while (len) {
-    size_t s = len > zero_buffer_size ? zero_buffer_size : len;
-    this->write_bytes(zero_buffer, s, address);
-    address = remote((char*)address.address() + s);
-    len -= s;
-  }
-}
-
-void RemoteProcessMemory::ignore_region(std::uint64_t addr, std::size_t size)
-{
-  IgnoredRegion region;
-  region.addr = addr;
-  region.size = size;
-
-  auto pos = std::lower_bound(ignored_regions_.begin(), ignored_regions_.end(), region,
-                              [](auto const& reg1, auto const& reg2) {
-                                return reg1.addr < reg2.addr || (reg1.addr == reg2.addr && reg1.size < reg2.size);
-                              });
-  if (pos == ignored_regions_.end() || pos->addr != addr || pos->size != size)
-    ignored_regions_.insert(pos, region);
-}
-
-void RemoteProcessMemory::ignore_heap(IgnoredHeapRegion const& region)
-{
-  // Binary search the position of insertion:
-  auto pos = std::lower_bound(ignored_heap_.begin(), ignored_heap_.end(), region.address,
-                              [](auto const& reg, auto const* addr) { return reg.address < addr; });
-  if (pos == ignored_heap_.end() || pos->address != region.address) {
-    // Insert it:
-    ignored_heap_.insert(pos, region);
-  }
-}
-
-void RemoteProcessMemory::unignore_heap(void* address, size_t size)
-{
-  // Binary search:
-  auto pos = std::lower_bound(ignored_heap_.begin(), ignored_heap_.end(), address,
-                              [](auto const& reg, auto const* addr) { return reg.address < addr; });
-  if (pos != ignored_heap_.end() && static_cast<char*>(pos->address) <= static_cast<char*>(address) + size)
-    ignored_heap_.erase(pos);
-}
-
-void RemoteProcessMemory::ignore_local_variable(const char* var_name, const char* frame_name) const
-{
-  if (frame_name != nullptr && strcmp(frame_name, "*") == 0)
-    frame_name = nullptr;
-  for (std::shared_ptr<simgrid::mc::ObjectInformation> const& info : this->object_infos)
-    info->remove_local_variable(var_name, frame_name);
-}
-
-void RemoteProcessMemory::dump_stack() const
-{
-  unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, BYTE_ORDER);
-  if (as == nullptr) {
-    XBT_ERROR("Could not initialize ptrace address space");
-    return;
-  }
-
-  void* context = _UPT_create(this->pid_);
-  if (context == nullptr) {
-    unw_destroy_addr_space(as);
-    XBT_ERROR("Could not initialize ptrace context");
-    return;
-  }
-
-  unw_cursor_t cursor;
-  if (unw_init_remote(&cursor, as, context) != 0) {
-    _UPT_destroy(context);
-    unw_destroy_addr_space(as);
-    XBT_ERROR("Could not initialize ptrace cursor");
-    return;
-  }
-
-  simgrid::mc::dumpStack(stderr, &cursor);
-
-  _UPT_destroy(context);
-  unw_destroy_addr_space(as);
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/sosp/RemoteProcessMemory.hpp b/src/mc/sosp/RemoteProcessMemory.hpp
deleted file mode 100644 (file)
index eeff932..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/* mc::RemoteClient: representative of the Client memory on the MC side */
-
-/* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_PROCESS_H
-#define SIMGRID_MC_PROCESS_H
-
-#include "src/mc/AddressSpace.hpp"
-#include "src/mc/datatypes.h"
-#include "src/mc/inspect/ObjectInformation.hpp"
-#include "src/mc/remote/RemotePtr.hpp"
-#include "src/xbt/memory_map.hpp"
-#include "src/xbt/mmalloc/mmprivate.h"
-
-#include <libunwind.h>
-#include <vector>
-
-namespace simgrid::mc {
-
-struct IgnoredRegion {
-  std::uint64_t addr;
-  std::size_t size;
-};
-
-struct IgnoredHeapRegion {
-  int block;
-  int fragment;
-  void* address;
-  std::size_t size;
-};
-
-/** The Application's process memory, seen from the Checker perspective. This class is not needed if you don't need to
- * introspect the application process.
- *
- *  Responsabilities:
- *    - reading from the process memory (`AddressSpace`);
- *    - accessing the system state of the process (heap, …);
- *    - stack unwinding;
- *    - etc.
- */
-class RemoteProcessMemory final : public AddressSpace {
-private:
-  // Those flags are used to track down which cached information
-  // is still up to date and which information needs to be updated.
-  static constexpr int cache_none   = 0;
-  static constexpr int cache_heap   = 1;
-  static constexpr int cache_malloc = 2;
-
-public:
-  explicit RemoteProcessMemory(pid_t pid, xbt_mheap_t mmalloc_default_mdp);
-  ~RemoteProcessMemory() override;
-
-  RemoteProcessMemory(RemoteProcessMemory const&)            = delete;
-  RemoteProcessMemory(RemoteProcessMemory&&)                 = delete;
-  RemoteProcessMemory& operator=(RemoteProcessMemory const&) = delete;
-  RemoteProcessMemory& operator=(RemoteProcessMemory&&)      = delete;
-
-  /* ************* */
-  /* Low-level API */
-  /* ************* */
-
-  // Read memory:
-  void* read_bytes(void* buffer, std::size_t size, RemotePtr<void> address,
-                   ReadOptions options = ReadOptions::none()) const override;
-
-  void read_variable(const char* name, void* target, size_t size) const;
-  template <class T> void read_variable(const char* name, T* target) const
-  {
-    read_variable(name, target, sizeof(*target));
-  }
-  template <class T> Remote<T> read_variable(const char* name) const
-  {
-    Remote<T> res;
-    read_variable(name, res.get_buffer(), sizeof(T));
-    return res;
-  }
-
-  std::string read_string(RemotePtr<char> address) const;
-  using AddressSpace::read_string;
-
-  // Write memory:
-  void write_bytes(const void* buffer, size_t len, RemotePtr<void> address) const;
-  void clear_bytes(RemotePtr<void> address, size_t len) const;
-
-  // Debug information:
-  std::shared_ptr<ObjectInformation> find_object_info(RemotePtr<void> addr) const;
-  std::shared_ptr<ObjectInformation> find_object_info_exec(RemotePtr<void> addr) const;
-  std::shared_ptr<ObjectInformation> find_object_info_rw(RemotePtr<void> addr) const;
-  Frame* find_function(RemotePtr<void> ip) const;
-  const Variable* find_variable(const char* name) const;
-
-  // Heap access:
-  xbt_mheap_t get_heap()
-  {
-    if (not(cache_flags_ & RemoteProcessMemory::cache_heap))
-      refresh_heap();
-    return this->heap.get();
-  }
-  const malloc_info* get_malloc_info()
-  {
-    if (not(this->cache_flags_ & RemoteProcessMemory::cache_malloc))
-      this->refresh_malloc_info();
-    return this->heap_info.data();
-  }
-  /* Get the amount of memory mallocated in the remote process (requires mmalloc) */
-  std::size_t get_remote_heap_bytes();
-
-  void clear_cache() { this->cache_flags_ = RemoteProcessMemory::cache_none; }
-
-  std::vector<IgnoredRegion> const& ignored_regions() const { return ignored_regions_; }
-  void ignore_region(std::uint64_t address, std::size_t size);
-
-  bool in_maestro_stack(RemotePtr<void> p) const
-  {
-    return p >= this->maestro_stack_start_ && p < this->maestro_stack_end_;
-  }
-
-  void ignore_global_variable(const char* name) const
-  {
-    for (std::shared_ptr<ObjectInformation> const& info : this->object_infos)
-      info->remove_global_variable(name);
-  }
-
-  std::vector<s_stack_region_t>& stack_areas() { return stack_areas_; }
-  std::vector<s_stack_region_t> const& stack_areas() const { return stack_areas_; }
-
-  std::vector<IgnoredHeapRegion> const& ignored_heap() const { return ignored_heap_; }
-  void ignore_heap(IgnoredHeapRegion const& region);
-  void unignore_heap(void* address, size_t size);
-
-  void ignore_local_variable(const char* var_name, const char* frame_name) const;
-
-  void dump_stack() const;
-
-private:
-  void init_memory_map_info();
-  void refresh_heap();
-  void refresh_malloc_info();
-
-  pid_t pid_ = -1;
-  std::vector<xbt::VmMap> memory_map_;
-  RemotePtr<void> maestro_stack_start_;
-  RemotePtr<void> maestro_stack_end_;
-  int memory_file = -1;
-  std::vector<IgnoredRegion> ignored_regions_;
-  std::vector<s_stack_region_t> stack_areas_;
-  std::vector<IgnoredHeapRegion> ignored_heap_;
-
-  /** State of the cache (which variables are up to date) */
-  int cache_flags_ = RemoteProcessMemory::cache_none;
-
-public:
-  // object info
-  // TODO, make private (first, objectify simgrid::mc::ObjectInformation*)
-  std::vector<std::shared_ptr<ObjectInformation>> object_infos;
-  std::shared_ptr<ObjectInformation> binary_info;
-
-  /** Address of the heap structure in the MCed process. */
-  RemotePtr<s_xbt_mheap_t> heap_address;
-
-  /** Copy of the heap structure of the process
-   *
-   *  This is refreshed with the `MC_process_refresh` call.
-   *  This is not used if the process is the current one:
-   *  use `get_heap_info()` in order to use it.
-   */
-  std::unique_ptr<s_xbt_mheap_t> heap = std::make_unique<s_xbt_mheap_t>();
-
-  /** Copy of the allocation info structure
-   *
-   *  This is refreshed with the `MC_process_refresh` call.
-   *  This is not used if the process is the current one:
-   *  use `get_malloc_info()` in order to use it.
-   */
-  std::vector<malloc_info> heap_info;
-
-  // Libunwind-data
-  /** Full-featured MC-aware libunwind address space for the process
-   *
-   *  This address space is using a simgrid::mc::UnwindContext*
-   *  (with simgrid::mc::Process* / simgrid::mc::AddressSpace*
-   *  and unw_context_t).
-   */
-  unw_addr_space_t unw_addr_space = nullptr;
-
-  /** Underlying libunwind address-space
-   *
-   *  The `find_proc_info`, `put_unwind_info`, `get_dyn_info_list_addr`
-   *  operations of the native MC address space is currently delegated
-   *  to this address space (either the local or a ptrace unwinder).
-   */
-  unw_addr_space_t unw_underlying_addr_space = nullptr;
-
-  /** The corresponding context
-   */
-  void* unw_underlying_context = nullptr;
-};
-
-/** Open a FD to a remote process memory (`/dev/$pid/mem`) */
-XBT_PRIVATE int open_vm(pid_t pid, int flags);
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/sosp/Snapshot.cpp b/src/mc/sosp/Snapshot.cpp
deleted file mode 100644 (file)
index 72e2355..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/sosp/Snapshot.hpp"
-#include "src/mc/mc_config.hpp"
-
-#include <cstddef> /* std::size_t */
-
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_snapshot, mc, "Taking and restoring snapshots");
-namespace simgrid::mc {
-/************************************* Take Snapshot ************************************/
-/****************************************************************************************/
-
-void Snapshot::snapshot_regions(RemoteProcessMemory& memory)
-{
-  snapshot_regions_.clear();
-
-  for (auto const& object_info : memory.object_infos)
-    add_region(RegionType::Data, memory, object_info.get(), object_info->start_rw,
-               object_info->end_rw - object_info->start_rw);
-
-  const s_xbt_mheap_t* heap = memory.get_heap();
-  void* start_heap = heap->base;
-  void* end_heap   = heap->breakval;
-
-  add_region(RegionType::Heap, memory, nullptr, start_heap, (char*)end_heap - (char*)start_heap);
-  heap_bytes_used_ = mmalloc_get_bytes_used_remote(heap->heaplimit, memory.get_malloc_info());
-}
-
-/** @brief Checks whether the variable is in scope for a given IP.
- *
- *  A variable may be defined only from a given value of IP.
- *
- *  @param var   Variable description
- *  @param scope Scope description
- *  @param ip    Instruction pointer
- *  @return      true if the variable is valid
- * */
-static bool valid_variable(const simgrid::mc::Variable* var, simgrid::mc::Frame* scope, const void* ip)
-{
-  // The variable is not yet valid:
-  if (scope->range.begin() + var->start_scope > (std::uint64_t)ip)
-    return false;
-  else
-    return true;
-}
-
-static void fill_local_variables_values(mc_stack_frame_t stack_frame, Frame* scope,
-                                        std::vector<s_local_variable_t>& result, AddressSpace* memory)
-{
-  if (not scope || not scope->range.contain(stack_frame->ip))
-    return;
-
-  for (const Variable& current_variable : scope->variables) {
-    if (not valid_variable(&current_variable, scope, (void*)stack_frame->ip))
-      continue;
-
-    if (not current_variable.type) {
-      XBT_VERB("Ignore local variable without type: '%s' [%s]", current_variable.name.c_str(),
-               stack_frame->frame->name.c_str());
-      continue;
-    }
-
-    s_local_variable_t new_var;
-    new_var.subprogram = stack_frame->frame;
-    new_var.ip         = stack_frame->ip;
-    new_var.name       = current_variable.name;
-    new_var.type       = current_variable.type;
-    new_var.address    = nullptr;
-
-    if (current_variable.address != nullptr)
-      new_var.address = current_variable.address;
-    else if (not current_variable.location_list.empty()) {
-      dwarf::Location location =
-          simgrid::dwarf::resolve(current_variable.location_list, current_variable.object_info,
-                                  &(stack_frame->unw_cursor), (void*)stack_frame->frame_base, memory);
-
-      xbt_assert(location.in_memory(), "Cannot handle non-address variable");
-      new_var.address = location.address();
-    } else
-      xbt_die("No address");
-
-    result.push_back(std::move(new_var));
-  }
-
-  // Recursive processing of nested scopes:
-  for (Frame& nested_scope : scope->scopes)
-    fill_local_variables_values(stack_frame, &nested_scope, result, memory);
-}
-
-static std::vector<s_local_variable_t> get_local_variables_values(std::vector<s_mc_stack_frame_t>& stack_frames,
-                                                                  AddressSpace* memory)
-{
-  std::vector<s_local_variable_t> variables;
-  for (s_mc_stack_frame_t& stack_frame : stack_frames)
-    fill_local_variables_values(&stack_frame, stack_frame.frame, variables, memory);
-  return variables;
-}
-
-static std::vector<s_mc_stack_frame_t> unwind_stack_frames(UnwindContext* stack_context,
-                                                           const RemoteProcessMemory* process_memory)
-{
-  std::vector<s_mc_stack_frame_t> result;
-
-  unw_cursor_t c = stack_context->cursor();
-
-  // TODO, check condition check (unw_init_local==0 means end of frame)
-
-  while (true) {
-    s_mc_stack_frame_t stack_frame;
-
-    stack_frame.unw_cursor = c;
-
-    unw_word_t ip;
-    unw_word_t sp;
-
-    unw_get_reg(&c, UNW_REG_IP, &ip);
-    unw_get_reg(&c, UNW_REG_SP, &sp);
-
-    stack_frame.ip = ip;
-    stack_frame.sp = sp;
-
-    // TODO, use real addresses in frame_t instead of fixing it here
-
-    Frame* frame              = process_memory->find_function(remote(ip));
-    stack_frame.frame         = frame;
-
-    if (frame) {
-      stack_frame.frame_name = frame->name;
-      stack_frame.frame_base = (unw_word_t)frame->frame_base(c);
-    } else {
-      stack_frame.frame_base = 0;
-      stack_frame.frame_name = "";
-    }
-
-    result.push_back(std::move(stack_frame));
-
-    /* Stop before context switch with maestro */
-    if (frame != nullptr && frame->name == "smx_ctx_wrapper")
-      break;
-
-    int ret = unw_step(&c);
-    xbt_assert(ret >= 0, "Error while unwinding stack");
-    xbt_assert(ret != 0, "Unexpected end of stack.");
-  }
-
-  xbt_assert(not result.empty(), "unw_init_local failed");
-
-  return result;
-}
-
-void Snapshot::snapshot_stacks(RemoteProcessMemory& process_memory)
-{
-  for (auto const& stack : process_memory.stack_areas()) {
-    s_mc_snapshot_stack_t st;
-
-    // Read the context from remote process memory:
-    unw_context_t context;
-    process_memory.read_bytes(&context, sizeof(context), remote(stack.context));
-
-    st.context.initialize(process_memory, &context);
-
-    st.stack_frames    = unwind_stack_frames(&st.context, &process_memory);
-    st.local_variables = get_local_variables_values(st.stack_frames, &process_memory);
-
-    unw_word_t sp = st.stack_frames[0].sp;
-
-    stacks_.push_back(std::move(st));
-
-    size_t stack_size = (char*)stack.address + stack.size - (char*)sp;
-    stack_sizes_.push_back(stack_size);
-  }
-}
-
-void Snapshot::handle_ignore()
-{
-  xbt_assert(get_remote_process_memory());
-
-  // Copy the memory:
-  for (auto const& region : get_remote_process_memory()->ignored_regions()) {
-    s_mc_snapshot_ignored_data_t ignored_data;
-    ignored_data.start = (void*)region.addr;
-    ignored_data.data.resize(region.size);
-    get_remote_process_memory()->read_bytes(ignored_data.data.data(), region.size, remote(region.addr));
-    ignored_data_.push_back(std::move(ignored_data));
-  }
-
-  // Zero the memory:
-  for (auto const& region : get_remote_process_memory()->ignored_regions())
-    get_remote_process_memory()->clear_bytes(remote(region.addr), region.size);
-}
-
-void Snapshot::ignore_restore() const
-{
-  for (auto const& ignored_data : ignored_data_)
-    get_remote_process_memory()->write_bytes(ignored_data.data.data(), ignored_data.data.size(),
-                                             remote(ignored_data.start));
-}
-
-Snapshot::Snapshot(long num_state, PageStore& store, RemoteProcessMemory& memory)
-    : AddressSpace(&memory), page_store_(store), num_state_(num_state)
-{
-  XBT_DEBUG("Taking snapshot %ld", num_state);
-
-  handle_ignore();
-
-  /* Save the std heap and the writable mapped pages of libsimgrid and binary */
-  snapshot_regions(memory);
-
-  to_ignore_ = memory.ignored_heap();
-
-  if (_sg_mc_max_visited_states > 0 || not _sg_mc_property_file.get().empty()) {
-    snapshot_stacks(memory);
-    hash_ = this->do_hash();
-  }
-
-  ignore_restore();
-}
-
-void Snapshot::add_region(RegionType type, RemoteProcessMemory& memory, ObjectInformation* object_info,
-                          void* start_addr, std::size_t size)
-{
-  if (type == RegionType::Data)
-    xbt_assert(object_info, "Missing object info for object.");
-  else if (type == RegionType::Heap)
-    xbt_assert(not object_info, "Unexpected object info for heap region.");
-
-  auto* region = new Region(page_store_, memory, type, start_addr, size);
-  region->object_info(object_info);
-  snapshot_regions_.push_back(std::unique_ptr<Region>(region));
-}
-
-void* Snapshot::read_bytes(void* buffer, std::size_t size, RemotePtr<void> address, ReadOptions options) const
-{
-  const Region* region = this->get_region((void*)address.address());
-  if (region) {
-    void* res = region->read(buffer, (void*)address.address(), size);
-    if (buffer == res || options & ReadOptions::lazy())
-      return res;
-    else {
-      memcpy(buffer, res, size);
-      return buffer;
-    }
-  } else
-    return this->get_remote_process_memory()->read_bytes(buffer, size, address, options);
-}
-/** @brief Find the snapshotted region from a pointer
- *
- *  @param addr     Pointer
- * */
-Region* Snapshot::get_region(const void* addr) const
-{
-  size_t n = snapshot_regions_.size();
-  for (size_t i = 0; i != n; ++i) {
-    Region* region = snapshot_regions_[i].get();
-    if (not(region && region->contain(simgrid::mc::remote(addr))))
-      continue;
-
-    return region;
-  }
-
-  return nullptr;
-}
-
-/** @brief Find the snapshotted region from a pointer, with a hinted_region */
-Region* Snapshot::get_region(const void* addr, Region* hinted_region) const
-{
-  if (hinted_region->contain(simgrid::mc::remote(addr)))
-    return hinted_region;
-  else
-    return get_region(addr);
-}
-
-void Snapshot::restore(RemoteProcessMemory& memory) const
-{
-  XBT_DEBUG("Restore snapshot %ld", num_state_);
-
-  // Restore regions
-  for (std::unique_ptr<Region> const& region : snapshot_regions_) {
-    region->restore(memory);
-  }
-
-  ignore_restore();
-  memory.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
diff --git a/src/mc/sosp/Snapshot.hpp b/src/mc/sosp/Snapshot.hpp
deleted file mode 100644 (file)
index 04e871c..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* Copyright (c) 2007-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifndef SIMGRID_MC_SNAPSHOT_HPP
-#define SIMGRID_MC_SNAPSHOT_HPP
-
-#include "src/mc/inspect/mc_unw.hpp"
-#include "src/mc/sosp/Region.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-
-// ***** MC Snapshot
-
-/** Ignored data
- *
- *  Some parts of the snapshot are ignored by zeroing them out: the real values is stored here.
- */
-struct s_mc_snapshot_ignored_data_t {
-  void* start;
-  std::vector<char> data;
-};
-
-/** Information about a given stack frame */
-struct s_mc_stack_frame_t {
-  /** Instruction pointer */
-  unw_word_t ip;
-  /** Stack pointer */
-  unw_word_t sp;
-  unw_word_t frame_base;
-  simgrid::mc::Frame* frame;
-  std::string frame_name;
-  unw_cursor_t unw_cursor;
-};
-using mc_stack_frame_t = s_mc_stack_frame_t*;
-
-struct s_local_variable_t {
-  simgrid::mc::Frame* subprogram;
-  unsigned long ip;
-  std::string name;
-  simgrid::mc::Type* type;
-  void* address;
-};
-using local_variable_t       = s_local_variable_t*;
-using const_local_variable_t = const s_local_variable_t*;
-
-struct XBT_PRIVATE s_mc_snapshot_stack_t {
-  std::vector<s_local_variable_t> local_variables;
-  simgrid::mc::UnwindContext context;
-  std::vector<s_mc_stack_frame_t> stack_frames;
-};
-using mc_snapshot_stack_t       = s_mc_snapshot_stack_t*;
-using const_mc_snapshot_stack_t = const s_mc_snapshot_stack_t*;
-
-namespace simgrid::mc {
-
-using hash_type = std::uint64_t;
-
-class XBT_PRIVATE Snapshot final : public AddressSpace {
-  PageStore& page_store_;
-
-public:
-  /* Initialization */
-  Snapshot(long num_state, PageStore& store, RemoteProcessMemory& memory);
-
-  /* Regular use */
-  bool on_heap(const void* address) const
-  {
-    const s_xbt_mheap_t* heap = get_remote_process_memory()->get_heap();
-    return address >= heap->heapbase && address < heap->breakval;
-  }
-
-  void* read_bytes(void* buffer, std::size_t size, RemotePtr<void> address,
-                   ReadOptions options = ReadOptions::none()) const override;
-  Region* get_region(const void* addr) const;
-  Region* get_region(const void* addr, Region* hinted_region) const;
-  void restore(RemoteProcessMemory& memory) const;
-
-  bool equals_to(const Snapshot& other, RemoteProcessMemory& memory);
-
-  // To be private
-  long num_state_;
-  std::size_t heap_bytes_used_ = 0;
-  std::vector<std::unique_ptr<Region>> snapshot_regions_;
-  std::vector<std::size_t> stack_sizes_;
-  std::vector<s_mc_snapshot_stack_t> stacks_;
-  std::vector<simgrid::mc::IgnoredHeapRegion> to_ignore_;
-  std::uint64_t hash_ = 0;
-  std::vector<s_mc_snapshot_ignored_data_t> ignored_data_;
-
-private:
-  void add_region(RegionType type, RemoteProcessMemory& memory, ObjectInformation* object_info, void* start_addr,
-                  std::size_t size);
-  void snapshot_regions(RemoteProcessMemory& memory);
-  void snapshot_stacks(RemoteProcessMemory& memory);
-  void handle_ignore();
-  void ignore_restore() const;
-  hash_type do_hash() const;
-};
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/sosp/Snapshot_test.cpp b/src/mc/sosp/Snapshot_test.cpp
deleted file mode 100644 (file)
index d2f7d0e..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/3rd-party/catch.hpp"
-#include "src/mc/mc_config.hpp"
-#include "src/mc/sosp/Snapshot.hpp"
-
-#include <cstddef>
-#include <memory>
-#include <sys/mman.h>
-#include <xbt/random.hpp>
-
-/**************** Class BOOST_tests *************************/
-using simgrid::mc::Region;
-class snap_test_helper {
-  static simgrid::mc::PageStore page_store_;
-  static std::unique_ptr<simgrid::mc::RemoteProcessMemory> memory_;
-
-public:
-  static void init_memory(void* mem, size_t size);
-  static void Init();
-  struct prologue_return {
-    size_t size;
-    void* src;
-    void* dstn;
-    Region* region0;
-    Region* region;
-  };
-  static prologue_return prologue(int n); // common to the below 5 fxs
-  static void read_whole_region();
-  static void read_region_parts();
-  static void compare_whole_region();
-  static void compare_region_parts();
-  static void read_pointer();
-
-  static void cleanup() { memory_ = nullptr; }
-};
-
-// static member variables init.
-simgrid::mc::PageStore snap_test_helper::page_store_(500);
-std::unique_ptr<simgrid::mc::RemoteProcessMemory> snap_test_helper::memory_ = nullptr;
-
-void snap_test_helper::init_memory(void* mem, size_t size)
-{
-  auto* dest = static_cast<char*>(mem);
-  for (size_t i = 0; i < size; ++i) {
-    dest[i] = simgrid::xbt::random::uniform_int(0, 0xff);
-  }
-}
-
-void snap_test_helper::Init()
-{
-  REQUIRE(xbt_pagesize == getpagesize());
-  REQUIRE(1 << xbt_pagebits == xbt_pagesize);
-
-  memory_ = std::make_unique<simgrid::mc::RemoteProcessMemory>(getpid(), nullptr);
-}
-
-snap_test_helper::prologue_return snap_test_helper::prologue(int n)
-{
-  // Store region page(s):
-  size_t byte_size = n * xbt_pagesize;
-  void* source     = mmap(nullptr, byte_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  INFO("Could not allocate source memory");
-  REQUIRE(source != MAP_FAILED);
-
-  // Init memory and take snapshots:
-  init_memory(source, byte_size);
-  auto* region0 =
-      new simgrid::mc::Region(page_store_, *memory_.get(), simgrid::mc::RegionType::Data, source, byte_size);
-  for (int i = 0; i < n; i += 2) {
-    init_memory((char*)source + i * xbt_pagesize, xbt_pagesize);
-  }
-  auto* region = new simgrid::mc::Region(page_store_, *memory_.get(), simgrid::mc::RegionType::Data, source, byte_size);
-
-  void* destination = mmap(nullptr, byte_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  INFO("Could not allocate destination memory");
-  REQUIRE(destination != MAP_FAILED);
-
-  return {.size = byte_size, .src = source, .dstn = destination, .region0 = region0, .region = region};
-}
-
-void snap_test_helper::read_whole_region()
-{
-  for (int n = 1; n != 32; ++n) {
-    prologue_return ret = prologue(n);
-    const void* read    = ret.region->read(ret.dstn, ret.src, ret.size);
-    INFO("Mismatch in MC_region_read()");
-    REQUIRE(not memcmp(ret.src, read, ret.size));
-
-    munmap(ret.dstn, ret.size);
-    munmap(ret.src, ret.size);
-    delete ret.region0;
-    delete ret.region;
-  }
-}
-
-void snap_test_helper::read_region_parts()
-{
-  for (int n = 1; n != 32; ++n) {
-    prologue_return ret = prologue(n);
-
-    for (int j = 0; j != 100; ++j) {
-      size_t offset    = simgrid::xbt::random::uniform_int(0, ret.size - 1);
-      size_t size      = simgrid::xbt::random::uniform_int(0, ret.size - offset - 1);
-      const void* read = ret.region->read(ret.dstn, (const char*)ret.src + offset, size);
-      INFO("Mismatch in MC_region_read()");
-      REQUIRE(not memcmp((char*)ret.src + offset, read, size));
-    }
-    munmap(ret.dstn, ret.size);
-    munmap(ret.src, ret.size);
-    delete ret.region0;
-    delete ret.region;
-  }
-}
-
-void snap_test_helper::compare_whole_region()
-{
-  for (int n = 1; n != 32; ++n) {
-    prologue_return ret = prologue(n);
-
-    INFO("Unexpected match in MC_snapshot_region_memcmp() with previous snapshot");
-    REQUIRE(MC_snapshot_region_memcmp(ret.src, ret.region0, ret.src, ret.region, ret.size));
-
-    munmap(ret.dstn, ret.size);
-    munmap(ret.src, ret.size);
-    delete ret.region0;
-    delete ret.region;
-  }
-}
-
-void snap_test_helper::compare_region_parts()
-{
-  for (int n = 1; n != 32; ++n) {
-    prologue_return ret = prologue(n);
-
-    for (int j = 0; j != 100; ++j) {
-      size_t offset = simgrid::xbt::random::uniform_int(0, ret.size - 1);
-      size_t size   = simgrid::xbt::random::uniform_int(0, ret.size - offset - 1);
-
-      INFO("Mismatch in MC_snapshot_region_memcmp()");
-      REQUIRE(not MC_snapshot_region_memcmp((char*)ret.src + offset, ret.region, (char*)ret.src + offset, ret.region,
-                                            size));
-    }
-    munmap(ret.dstn, ret.size);
-    munmap(ret.src, ret.size);
-    delete ret.region0;
-    delete ret.region;
-  }
-}
-
-const int some_global_variable  = 42;
-const void* some_global_pointer = &some_global_variable;
-void snap_test_helper::read_pointer()
-{
-  prologue_return ret = prologue(1);
-  memcpy(ret.src, &some_global_pointer, sizeof(void*));
-  const simgrid::mc::Region region2(page_store_, *memory_.get(), simgrid::mc::RegionType::Data, ret.src, ret.size);
-  INFO("Mismtach in MC_region_read_pointer()");
-  REQUIRE(MC_region_read_pointer(&region2, ret.src) == some_global_pointer);
-
-  munmap(ret.dstn, ret.size);
-  munmap(ret.src, ret.size);
-  delete ret.region0;
-  delete ret.region;
-}
-
-/*************** End: class snap_test_helper *****************************/
-
-TEST_CASE("MC::Snapshot: A copy/snapshot of a given memory region", "MC::Snapshot")
-{
-  INFO("Sparse snapshot (using pages)");
-
-  snap_test_helper::Init();
-
-  INFO("Read whole region");
-  snap_test_helper::read_whole_region();
-
-  INFO("Read region parts");
-  snap_test_helper::read_region_parts();
-
-  INFO("Compare whole region");
-  snap_test_helper::compare_whole_region();
-
-  INFO("Compare region parts");
-  snap_test_helper::compare_region_parts();
-
-  INFO("Read pointer");
-  snap_test_helper::read_pointer();
-
-  snap_test_helper::cleanup();
-}
index f2ce4ab..fc3a5e2 100644 (file)
@@ -11,7 +11,7 @@
 
 #if SIMGRID_HAVE_MC
 #include "src/mc/explo/Exploration.hpp"
-#include "src/mc/transition/TransitionActorJoin.hpp"
+#include "src/mc/transition/TransitionActor.hpp"
 #include "src/mc/transition/TransitionAny.hpp"
 #include "src/mc/transition/TransitionComm.hpp"
 #include "src/mc/transition/TransitionObjectAccess.hpp"
@@ -47,7 +47,6 @@ std::string Transition::dot_string() const
 void Transition::replay(RemoteApp& app) const
 {
   replayed_transitions_++;
-
 #if SIMGRID_HAVE_MC
   app.handle_simcall(aid_, times_considered_, false);
   app.wait_for_requests();
@@ -96,6 +95,8 @@ Transition* deserialize_transition(aid_t issuer, int times_considered, std::stri
 
     case Transition::Type::ACTOR_JOIN:
       return new ActorJoinTransition(issuer, times_considered, stream);
+    case Transition::Type::ACTOR_SLEEP:
+      return new ActorSleepTransition(issuer, times_considered, stream);
 
     case Transition::Type::OBJECT_ACCESS:
       return new ObjectAccessTransition(issuer, times_considered, stream);
index 17fb7e6..246b3f0 100644 (file)
@@ -7,6 +7,7 @@
 #define SIMGRID_MC_TRANSITION_HPP
 
 #include "simgrid/forward.h" // aid_t
+#include "xbt/ex.h"
 #include "xbt/utility.hpp"   // XBT_DECLARE_ENUM_CLASS
 
 #include <sstream>
@@ -23,7 +24,7 @@ namespace simgrid::mc {
  *  calls.
  */
 class Transition {
-  /* Textual representation of the transition, to display backtraces */
+  /* Global statistics */
   static unsigned long executed_transitions_;
   static unsigned long replayed_transitions_;
 
@@ -31,18 +32,30 @@ class Transition {
 
 public:
   /* Ordering is important here. depends() implementations only consider subsequent types in this ordering */
-  XBT_DECLARE_ENUM_CLASS(Type, RANDOM, ACTOR_JOIN, /* First because indep with anybody including themselves */
-                         OBJECT_ACCESS,            /* high priority because indep with almost everybody */
-                         TESTANY, WAITANY,         /* high priority because they can rewrite themselves to *_WAIT */
-                         BARRIER_ASYNC_LOCK, BARRIER_WAIT, /* BARRIER transitions sorted alphabetically */
-                         COMM_ASYNC_RECV, COMM_ASYNC_SEND, COMM_TEST, COMM_WAIT, /* Alphabetical ordering of COMM_* */
-                         MUTEX_ASYNC_LOCK, MUTEX_TEST, MUTEX_TRYLOCK, MUTEX_UNLOCK, MUTEX_WAIT, /* alphabetical */
-                         SEM_ASYNC_LOCK, SEM_UNLOCK, SEM_WAIT, /* alphabetical ordering of SEM transitions */
-                         /* UNKNOWN must be last */ UNKNOWN);
+  XBT_DECLARE_ENUM_CLASS(Type,
+                         /* First because indep with anybody including themselves */
+                         RANDOM, ACTOR_JOIN, ACTOR_SLEEP,
+                         /* high priority because indep with almost everybody */
+                         OBJECT_ACCESS,
+                         /* high priority because they can rewrite themselves to *_WAIT */
+                         TESTANY, WAITANY,
+                         /* BARRIER transitions sorted alphabetically */
+                         BARRIER_ASYNC_LOCK, BARRIER_WAIT,
+                         /* Alphabetical ordering of COMM_* */
+                         COMM_ASYNC_RECV, COMM_ASYNC_SEND, COMM_TEST, COMM_WAIT,
+                         /* alphabetical */
+                         MUTEX_ASYNC_LOCK, MUTEX_TEST, MUTEX_TRYLOCK, MUTEX_UNLOCK, MUTEX_WAIT,
+                         /* alphabetical ordering of SEM transitions */
+                         SEM_ASYNC_LOCK, SEM_UNLOCK, SEM_WAIT,
+                         /* UNKNOWN must be last */
+                         UNKNOWN);
   Type type_ = Type::UNKNOWN;
 
   aid_t aid_ = 0;
 
+  /** The user function call that caused this transition to exist. Format: >>filename:line:function()<< */
+  std::string call_location_ = "";
+
   /* Which transition was executed for this simcall
    *
    * Some simcalls can lead to different transitions:
@@ -65,11 +78,28 @@ public:
   /** Returns something like >>label = "desc", color = c<< to describe the transition in dot format */
   virtual std::string dot_string() const;
 
+  std::string const& get_call_location() const { return call_location_; }
+
   /* Moves the application toward a path that was already explored, but don't change the current transition */
   void replay(RemoteApp& app) const;
 
   virtual bool depends(const Transition* other) const { return true; }
 
+  /**
+   The reversible race detector should only be used if we already have the assumption
+   this <* other (see Source set: a foundation for ODPOR). In particular this means that :
+   - this -->_E other
+   - proc(this) != proc(other)
+   - there is no event e s.t. this --> e --> other
+
+    @note: It is safe to assume that there is indeed a race between the two events in the execution;
+     indeed, the question the method answers is only sensible in the context of a race
+  */
+  virtual bool reversible_race(const Transition* other) const
+  {
+    xbt_die("%s unimplemented for %s", __func__, to_c_str(type_));
+  }
+
   /* Returns the total amount of transitions executed so far (for statistics) */
   static unsigned long get_executed_transitions() { return executed_transitions_; }
   /* Returns the total amount of transitions replayed so far while backtracing (for statistics) */
diff --git a/src/mc/transition/TransitionActor.cpp b/src/mc/transition/TransitionActor.cpp
new file mode 100644 (file)
index 0000000..3e1027b
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/mc/transition/TransitionActor.hpp"
+#include "simgrid/config.h"
+#include "xbt/asserts.h"
+#include "xbt/string.hpp"
+
+#include <sstream>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_trans_actorlifecycle, mc_transition,
+                                "Logging specific to MC transitions about actors' lifecycle: joining, ending");
+
+namespace simgrid::mc {
+
+ActorJoinTransition::ActorJoinTransition(aid_t issuer, int times_considered, std::stringstream& stream)
+    : Transition(Type::ACTOR_JOIN, issuer, times_considered)
+{
+  xbt_assert(stream >> target_ >> timeout_);
+  XBT_DEBUG("ActorJoinTransition target:%ld, %s ", target_, (timeout_ ? "timeout" : "no-timeout"));
+}
+std::string ActorJoinTransition::to_string(bool verbose) const
+{
+  return xbt::string_printf("ActorJoin(target %ld, %s)", target_, (timeout_ ? "timeout" : "no timeout"));
+}
+bool ActorJoinTransition::depends(const Transition* other) const
+{
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
+
+  // Joining is dependent with any transition whose
+  // actor is that of the `other` action. , Join i
+  if (other->aid_ == target_) {
+    return true;
+  }
+
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
+
+  // Otherwise, joining is indep with any other transitions:
+  // - It is only enabled once the target ends, and after this point it's enabled no matter what
+  // - Other joins don't affect it, and it does not impact on the enabledness of any other transition
+  return false;
+}
+
+bool ActorJoinTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::ACTOR_JOIN, "Unexpected transition type %s", to_c_str(type_));
+
+  // ActorJoin races with another event iff its target `T` is the same as  the actor executing the other transition.
+  // Clearly, then, we could not join on that actor `T` and then run a transition by `T`, so no race is reversible
+  return false;
+}
+
+ActorSleepTransition::ActorSleepTransition(aid_t issuer, int times_considered, std::stringstream&)
+    : Transition(Type::ACTOR_SLEEP, issuer, times_considered)
+{
+  XBT_DEBUG("ActorSleepTransition()");
+}
+std::string ActorSleepTransition::to_string(bool verbose) const
+{
+  return xbt::string_printf("ActorSleep()");
+}
+bool ActorSleepTransition::depends(const Transition* other) const
+{
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
+
+  // Sleeping is indep with any other transitions: always enabled, not impacted by any transition
+  return false;
+}
+
+bool ActorSleepTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::ACTOR_SLEEP, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // Always enabled
+}
+
+} // namespace simgrid::mc
similarity index 64%
rename from src/mc/transition/TransitionActorJoin.hpp
rename to src/mc/transition/TransitionActor.hpp
index 78bc765..68cc89f 100644 (file)
@@ -3,8 +3,8 @@
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
-#ifndef SIMGRID_MC_TRANSITION_ACTOR_JOIN_HPP
-#define SIMGRID_MC_TRANSITION_ACTOR_JOIN_HPP
+#ifndef SIMGRID_MC_TRANSITION_ACTOR_HPP
+#define SIMGRID_MC_TRANSITION_ACTOR_HPP
 
 #include "src/kernel/actor/SimcallObserver.hpp"
 #include "src/mc/transition/Transition.hpp"
@@ -23,12 +23,22 @@ public:
   ActorJoinTransition(aid_t issuer, int times_considered, std::stringstream& stream);
   std::string to_string(bool verbose) const override;
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 
   bool get_timeout() const { return timeout_; }
   /** Target ID */
   aid_t get_target() const { return target_; }
 };
 
+class ActorSleepTransition : public Transition {
+
+public:
+  ActorSleepTransition(aid_t issuer, int times_considered, std::stringstream& stream);
+  std::string to_string(bool verbose) const override;
+  bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
+};
+
 } // namespace simgrid::mc
 
 #endif
diff --git a/src/mc/transition/TransitionActorJoin.cpp b/src/mc/transition/TransitionActorJoin.cpp
deleted file mode 100644 (file)
index 49331de..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (c) 2015-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/mc/transition/TransitionActorJoin.hpp"
-#include "simgrid/config.h"
-#include "xbt/asserts.h"
-#include "xbt/string.hpp"
-#if SIMGRID_HAVE_MC
-#include "src/mc/api/RemoteApp.hpp"
-#include "src/mc/api/State.hpp"
-#endif
-
-#include <sstream>
-
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_trans_actorlifecycle, mc_transition,
-                                "Logging specific to MC transitions about actors' lifecycle: joining, ending");
-
-namespace simgrid::mc {
-
-ActorJoinTransition::ActorJoinTransition(aid_t issuer, int times_considered, std::stringstream& stream)
-    : Transition(Type::ACTOR_JOIN, issuer, times_considered)
-{
-  xbt_assert(stream >> target_ >> timeout_);
-  XBT_DEBUG("ActorJoinTransition target:%ld, %s ", target_, (timeout_ ? "timeout" : "no-timeout"));
-}
-std::string ActorJoinTransition::to_string(bool verbose) const
-{
-  return xbt::string_printf("ActorJoin(target %ld, %s)", target_, (timeout_ ? "timeout" : "no timeout"));
-}
-bool ActorJoinTransition::depends(const Transition* other) const
-{
-  // Joining is indep with any other transitions:
-  // - It is only enabled once the target ends, and after this point it's enabled no matter what
-  // - Other joins don't affect it, and it does not impact on the enabledness of any other transition
-  return false;
-}
-
-} // namespace simgrid::mc
index 0f10bb1..b3c7b63 100644 (file)
@@ -7,10 +7,6 @@
 #include "simgrid/config.h"
 #include "xbt/asserts.h"
 #include "xbt/string.hpp"
-#if SIMGRID_HAVE_MC
-#include "src/mc/api/RemoteApp.hpp"
-#include "src/mc/api/State.hpp"
-#endif
 
 #include <sstream>
 
@@ -25,22 +21,35 @@ TestAnyTransition::TestAnyTransition(aid_t issuer, int times_considered, std::st
   xbt_assert(stream >> size);
   for (int i = 0; i < size; i++) {
     Transition* t = deserialize_transition(issuer, 0, stream);
-    XBT_DEBUG("TestAny received a transition %s", t->to_string(true).c_str());
+    XBT_INFO("TestAny received a transition %s", t->to_string(true).c_str());
     transitions_.push_back(t);
   }
 }
 std::string TestAnyTransition::to_string(bool verbose) const
 {
-  auto res = xbt::string_printf("TestAny");
-  for (auto const* t : transitions_)
+  auto res = xbt::string_printf("TestAny(%s){ ", this->result() ? "TRUE" : "FALSE");
+  for (auto const* t : transitions_) {
     res += t->to_string(verbose);
+    res += "; ";
+  }
   res += " }";
   return res;
 }
 bool TestAnyTransition::depends(const Transition* other) const
 {
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
+
   return transitions_[times_considered_]->depends(other);
 }
+bool TestAnyTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::TESTANY, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // TestAny is always enabled
+}
+
 WaitAnyTransition::WaitAnyTransition(aid_t issuer, int times_considered, std::stringstream& stream)
     : Transition(Type::WAITANY, issuer, times_considered)
 {
@@ -48,6 +57,7 @@ WaitAnyTransition::WaitAnyTransition(aid_t issuer, int times_considered, std::st
   xbt_assert(stream >> size);
   for (int i = 0; i < size; i++) {
     Transition* t = deserialize_transition(issuer, 0, stream);
+    XBT_INFO("WaitAny received transition %d/%d %s", (i + 1), size, t->to_string(true).c_str());
     transitions_.push_back(t);
   }
 }
@@ -56,12 +66,22 @@ std::string WaitAnyTransition::to_string(bool verbose) const
   auto res = xbt::string_printf("WaitAny{ ");
   for (auto const* t : transitions_)
     res += t->to_string(verbose);
-  res += " }";
+  res += " } (times considered = " + std::to_string(times_considered_) + ")";
   return res;
 }
 bool WaitAnyTransition::depends(const Transition* other) const
 {
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
   return transitions_[times_considered_]->depends(other);
 }
+bool WaitAnyTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::WAITANY, "Unexpected transition type %s", to_c_str(type_));
+
+  // TODO: We need to check if any of the transitions waited on occurred before `e1`
+  return true; // Let's overapproximate to not miss branches
+}
 
 } // namespace simgrid::mc
index df5954e..35cbf4e 100644 (file)
@@ -8,7 +8,9 @@
 
 #include "src/kernel/actor/SimcallObserver.hpp"
 #include "src/mc/transition/Transition.hpp"
+#include "src/mc/transition/TransitionComm.hpp"
 
+#include <algorithm>
 #include <sstream>
 #include <string>
 
@@ -21,8 +23,16 @@ public:
   TestAnyTransition(aid_t issuer, int times_considered, std::stringstream& stream);
   std::string to_string(bool verbose) const override;
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 
   Transition* get_current_transition() const { return transitions_.at(times_considered_); }
+  bool result() const
+  {
+    return std::any_of(begin(transitions_), end(transitions_), [](const Transition* transition) {
+      const auto* tested_transition = static_cast<const CommTestTransition*>(transition);
+      return (tested_transition->get_sender() != -1 && tested_transition->get_receiver() != -1);
+    });
+  }
 };
 
 class WaitAnyTransition : public Transition {
@@ -32,6 +42,7 @@ public:
   WaitAnyTransition(aid_t issuer, int times_considered, std::stringstream& stream);
   std::string to_string(bool verbose) const override;
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 
   Transition* get_current_transition() const { return transitions_.at(times_considered_); }
 };
index de0ec2b..d23cd86 100644 (file)
@@ -5,13 +5,12 @@
 
 #include "src/mc/transition/TransitionComm.hpp"
 #include "simgrid/config.h"
-#include "xbt/asserts.h"
-#include "xbt/string.hpp"
-#if SIMGRID_HAVE_MC
 #include "src/mc/api/RemoteApp.hpp"
 #include "src/mc/api/State.hpp"
-#endif
+#include "xbt/asserts.h"
+#include "xbt/string.hpp"
 
+#include <inttypes.h>
 #include <sstream>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_trans_comm, mc_transition,
@@ -19,68 +18,83 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_trans_comm, mc_transition,
 
 namespace simgrid::mc {
 
+CommWaitTransition::CommWaitTransition(aid_t issuer, int times_considered, bool timeout_, unsigned comm_, aid_t sender_,
+                                       aid_t receiver_, unsigned mbox_)
+    : Transition(Type::COMM_WAIT, issuer, times_considered)
+    , timeout_(timeout_)
+    , comm_(comm_)
+    , mbox_(mbox_)
+    , sender_(sender_)
+    , receiver_(receiver_)
+{
+}
 CommWaitTransition::CommWaitTransition(aid_t issuer, int times_considered, std::stringstream& stream)
     : Transition(Type::COMM_WAIT, issuer, times_considered)
 {
-  xbt_assert(stream >> timeout_ >> comm_ >> sender_ >> receiver_ >> mbox_ >> sbuff_ >> rbuff_ >> size_);
-  XBT_DEBUG("CommWaitTransition %s comm:%" PRIxPTR ", sender:%ld receiver:%ld mbox:%u sbuff:%" PRIxPTR
-            " rbuff:%" PRIxPTR " size:%zu",
-            (timeout_ ? "timeout" : "no-timeout"), comm_, sender_, receiver_, mbox_, sbuff_, rbuff_, size_);
+  xbt_assert(stream >> timeout_ >> comm_ >> sender_ >> receiver_ >> mbox_ >> call_location_);
+  XBT_DEBUG("CommWaitTransition %s comm:%u, sender:%ld receiver:%ld mbox:%u call_loc:%s",
+            (timeout_ ? "timeout" : "no-timeout"), comm_, sender_, receiver_, mbox_, call_location_.c_str());
 }
 std::string CommWaitTransition::to_string(bool verbose) const
 {
-  auto res = xbt::string_printf("WaitComm(from %ld to %ld, mbox=%u, %s", sender_, receiver_, mbox_,
-                                (timeout_ ? "timeout" : "no timeout"));
-  if (verbose) {
-    res += ", sbuff=" + xbt::string_printf("%" PRIxPTR, sbuff_) + ", size=" + std::to_string(size_);
-    res += ", rbuff=" + xbt::string_printf("%" PRIxPTR, rbuff_);
-  }
-  res += ")";
-  return res;
+  return xbt::string_printf("WaitComm(from %ld to %ld, mbox=%u, %s)", sender_, receiver_, mbox_,
+                            (timeout_ ? "timeout" : "no timeout"));
 }
 bool CommWaitTransition::depends(const Transition* other) const
 {
   if (other->type_ < type_)
     return other->depends(this);
 
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
+
   if (const auto* wait = dynamic_cast<const CommWaitTransition*>(other)) {
     if (timeout_ || wait->timeout_)
       return true; // Timeouts are not considered by the independence theorem, thus assumed dependent
-
-    if (sbuff_ == wait->sbuff_ && rbuff_ == wait->rbuff_)
-      return false;
-    if (sbuff_ != 0 && rbuff_ != 0 && wait->sbuff_ != 0 && wait->rbuff_ != 0 && rbuff_ != wait->sbuff_ &&
-        rbuff_ != wait->rbuff_ && rbuff_ != sbuff_)
-      return false;
-
-    return true;
   }
 
   return false; // Comm transitions are INDEP with non-comm transitions
 }
+
+bool CommWaitTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::COMM_WAIT, "Unexpected transition type %s", to_c_str(type_));
+
+  // If the other event is a communication event, then we are not reversible; otherwise we are reversible.
+  return other->type_ != Transition::Type::COMM_ASYNC_SEND && other->type_ != Transition::Type::COMM_ASYNC_RECV;
+}
+
+CommTestTransition::CommTestTransition(aid_t issuer, int times_considered, unsigned comm_, aid_t sender_,
+                                       aid_t receiver_, unsigned mbox_)
+    : Transition(Type::COMM_TEST, issuer, times_considered)
+    , comm_(comm_)
+    , mbox_(mbox_)
+    , sender_(sender_)
+    , receiver_(receiver_)
+{
+}
 CommTestTransition::CommTestTransition(aid_t issuer, int times_considered, std::stringstream& stream)
     : Transition(Type::COMM_TEST, issuer, times_considered)
 {
-  xbt_assert(stream >> comm_ >> sender_ >> receiver_ >> mbox_ >> sbuff_ >> rbuff_ >> size_);
-  XBT_DEBUG("CommTestTransition comm:%" PRIxPTR ", sender:%ld receiver:%ld mbox:%u sbuff:%" PRIxPTR " rbuff:%" PRIxPTR
-            " size:%zu",
-            comm_, sender_, receiver_, mbox_, sbuff_, rbuff_, size_);
+  xbt_assert(stream >> comm_ >> sender_ >> receiver_ >> mbox_ >> call_location_);
+  XBT_DEBUG("CommTestTransition comm:%u, sender:%ld receiver:%ld mbox:%u call_loc:%s", comm_, sender_, receiver_, mbox_,
+            call_location_.c_str());
 }
 std::string CommTestTransition::to_string(bool verbose) const
 {
-  auto res = xbt::string_printf("TestComm(from %ld to %ld, mbox=%u", sender_, receiver_, mbox_);
-  if (verbose) {
-    res += ", sbuff=" + xbt::string_printf("%" PRIxPTR, sbuff_) + ", size=" + std::to_string(size_);
-    res += ", rbuff=" + xbt::string_printf("%" PRIxPTR, rbuff_);
-  }
-  res += ")";
-  return res;
+  return xbt::string_printf("TestComm(from %ld to %ld, mbox=%u)", sender_, receiver_, mbox_);
 }
+
 bool CommTestTransition::depends(const Transition* other) const
 {
   if (other->type_ < type_)
     return other->depends(this);
 
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
+
   if (dynamic_cast<const CommTestTransition*>(other) != nullptr)
     return false; // Test & Test are independent
 
@@ -95,24 +109,35 @@ bool CommTestTransition::depends(const Transition* other) const
   return false; // Comm transitions are INDEP with non-comm transitions
 }
 
+bool CommTestTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::COMM_TEST, "Unexpected transition type %s", to_c_str(type_));
+  return true; // CommTest is always enabled
+}
+
+CommRecvTransition::CommRecvTransition(aid_t issuer, int times_considered, unsigned comm_, unsigned mbox_, int tag_)
+    : Transition(Type::COMM_ASYNC_RECV, issuer, times_considered), comm_(comm_), mbox_(mbox_), tag_(tag_)
+{
+}
 CommRecvTransition::CommRecvTransition(aid_t issuer, int times_considered, std::stringstream& stream)
     : Transition(Type::COMM_ASYNC_RECV, issuer, times_considered)
 {
-  xbt_assert(stream >> comm_ >> mbox_ >> rbuff_ >> tag_);
+  xbt_assert(stream >> comm_ >> mbox_ >> tag_ >> call_location_);
+  XBT_DEBUG("CommRecvTransition comm:%u, mbox:%u tag:%d call_loc:%s", comm_, mbox_, tag_, call_location_.c_str());
 }
 std::string CommRecvTransition::to_string(bool verbose) const
 {
-  auto res = xbt::string_printf("iRecv(mbox=%u", mbox_);
-  if (verbose)
-    res += ", rbuff=" + xbt::string_printf("%" PRIxPTR, rbuff_);
-  res += ")";
-  return res;
+  return xbt::string_printf("iRecv(mbox=%u)", mbox_);
 }
 bool CommRecvTransition::depends(const Transition* other) const
 {
   if (other->type_ < type_)
     return other->depends(this);
 
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
+
   if (const auto* recv = dynamic_cast<const CommRecvTransition*>(other))
     return mbox_ == recv->mbox_;
 
@@ -123,20 +148,30 @@ bool CommRecvTransition::depends(const Transition* other) const
     if (mbox_ != test->mbox_)
       return false;
 
-    if ((aid_ != test->sender_) && (aid_ != test->receiver_) && (test->rbuff_ != rbuff_))
+    if ((aid_ != test->sender_) && (aid_ != test->receiver_))
+      return false;
+
+    // If the test is checking a paired comm already, we're independent!
+    // If we happen to make up that pair, then we're dependent...
+    if (test->comm_ != comm_)
       return false;
 
     return true; // DEP with other send transitions
   }
 
-  if (auto* wait = dynamic_cast<const CommWaitTransition*>(other)) {
+  if (const auto* wait = dynamic_cast<const CommWaitTransition*>(other)) {
     if (wait->timeout_)
       return true;
 
     if (mbox_ != wait->mbox_)
       return false;
 
-    if ((aid_ != wait->sender_) && (aid_ != wait->receiver_) && (wait->rbuff_ != rbuff_))
+    if ((aid_ != wait->sender_) && (aid_ != wait->receiver_))
+      return false;
+
+    // If the wait is waiting on a paired comm already, we're independent!
+    // If we happen to make up that pair, then we're dependent...
+    if ((aid_ != wait->aid_) && wait->comm_ != comm_)
       return false;
 
     return true; // DEP with other wait transitions
@@ -145,19 +180,26 @@ bool CommRecvTransition::depends(const Transition* other) const
   return false; // Comm transitions are INDEP with non-comm transitions
 }
 
+bool CommRecvTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::COMM_ASYNC_RECV, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // CommRecv is always enabled
+}
+
+CommSendTransition::CommSendTransition(aid_t issuer, int times_considered, unsigned comm_, unsigned mbox_, int tag_)
+    : Transition(Type::COMM_ASYNC_SEND, issuer, times_considered), comm_(comm_), mbox_(mbox_), tag_(tag_)
+{
+}
 CommSendTransition::CommSendTransition(aid_t issuer, int times_considered, std::stringstream& stream)
     : Transition(Type::COMM_ASYNC_SEND, issuer, times_considered)
 {
-  xbt_assert(stream >> comm_ >> mbox_ >> sbuff_ >> size_ >> tag_);
-  XBT_DEBUG("SendTransition comm:%" PRIxPTR " mbox:%u sbuff:%" PRIxPTR " size:%zu", comm_, mbox_, sbuff_, size_);
+  xbt_assert(stream >> comm_ >> mbox_ >> tag_ >> call_location_);
+  XBT_DEBUG("SendTransition comm:%u mbox:%u tag:%d call_loc:%s", comm_, mbox_, tag_, call_location_.c_str());
 }
 std::string CommSendTransition::to_string(bool verbose = false) const
 {
-  auto res = xbt::string_printf("iSend(mbox=%u", mbox_);
-  if (verbose)
-    res += ", sbuff=" + xbt::string_printf("%" PRIxPTR, sbuff_) + ", size=" + std::to_string(size_);
-  res += ")";
-  return res;
+  return xbt::string_printf("iSend(mbox=%u)", mbox_);
 }
 
 bool CommSendTransition::depends(const Transition* other) const
@@ -165,6 +207,10 @@ bool CommSendTransition::depends(const Transition* other) const
   if (other->type_ < type_)
     return other->depends(this);
 
+  // Actions executed by the same actor are always dependent
+  if (other->aid_ == aid_)
+    return true;
+
   if (const auto* other_isend = dynamic_cast<const CommSendTransition*>(other))
     return mbox_ == other_isend->mbox_;
 
@@ -175,7 +221,12 @@ bool CommSendTransition::depends(const Transition* other) const
     if (mbox_ != test->mbox_)
       return false;
 
-    if ((aid_ != test->sender_) && (aid_ != test->receiver_) && (test->sbuff_ != sbuff_))
+    if ((aid_ != test->sender_) && (aid_ != test->receiver_))
+      return false;
+
+    // If the test is checking a paired comm already, we're independent!
+    // If we happen to make up that pair, then we're dependent...
+    if (test->comm_ != comm_)
       return false;
 
     return true; // DEP with other test transitions
@@ -188,7 +239,12 @@ bool CommSendTransition::depends(const Transition* other) const
     if (mbox_ != wait->mbox_)
       return false;
 
-    if ((aid_ != wait->sender_) && (aid_ != wait->receiver_) && (wait->sbuff_ != sbuff_))
+    if ((aid_ != wait->sender_) && (aid_ != wait->receiver_))
+      return false;
+
+    // If the wait is waiting on a paired comm already, we're independent!
+    // If we happen to make up that pair, then we're dependent...
+    if ((aid_ != wait->aid_) && wait->comm_ != comm_)
       return false;
 
     return true; // DEP with other wait transitions
@@ -197,4 +253,11 @@ bool CommSendTransition::depends(const Transition* other) const
   return false; // Comm transitions are INDEP with non-comm transitions
 }
 
+bool CommSendTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::COMM_ASYNC_SEND, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // CommSend is always enabled
+}
+
 } // namespace simgrid::mc
index f652d03..1e9d074 100644 (file)
@@ -21,111 +21,94 @@ class CommTestTransition;
 
 class CommWaitTransition : public Transition {
   bool timeout_;
-  uintptr_t comm_;
+  unsigned comm_;
+  unsigned mbox_;
   aid_t sender_;
   aid_t receiver_;
-  unsigned mbox_;
-  uintptr_t sbuff_;
-  uintptr_t rbuff_;
-  size_t size_;
   friend CommRecvTransition;
   friend CommSendTransition;
   friend CommTestTransition;
 
 public:
+  CommWaitTransition(aid_t issuer, int times_considered, bool timeout_, unsigned comm_, aid_t sender_, aid_t receiver_,
+                     unsigned mbox_);
   CommWaitTransition(aid_t issuer, int times_considered, std::stringstream& stream);
   std::string to_string(bool verbose) const override;
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 
   bool get_timeout() const { return timeout_; }
-  /** Address of the corresponding Communication object in the application */
-  uintptr_t get_comm() const { return comm_; }
+  /** ID of the corresponding Communication object in the application, or 0 if unknown */
+  unsigned get_comm() const { return comm_; }
   /** Sender ID */
   aid_t get_sender() const { return sender_; }
   /** Receiver ID */
   aid_t get_receiver() const { return receiver_; }
   /** Mailbox ID */
   unsigned get_mailbox() const { return mbox_; }
-  /** Sender buffer */
-  uintptr_t get_sbuff() const { return sbuff_; }
-  /** Receiver buffer */
-  uintptr_t get_rbuff() const { return rbuff_; }
-  /** data size */
-  size_t get_size() const { return size_; }
 };
 class CommTestTransition : public Transition {
-  uintptr_t comm_;
+  unsigned comm_;
+  unsigned mbox_;
   aid_t sender_;
   aid_t receiver_;
-  unsigned mbox_;
-  uintptr_t sbuff_;
-  uintptr_t rbuff_;
-  size_t size_;
   friend CommSendTransition;
   friend CommRecvTransition;
 
 public:
+  CommTestTransition(aid_t issuer, int times_considered, unsigned comm_, aid_t sender_, aid_t receiver_,
+                     unsigned mbox_);
   CommTestTransition(aid_t issuer, int times_considered, std::stringstream& stream);
   std::string to_string(bool verbose) const override;
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 
-  /** Address of the corresponding Communication object in the application */
-  uintptr_t get_comm() const { return comm_; }
+  /** ID of the corresponding Communication object in the application, or 0 if unknown */
+  unsigned get_comm() const { return comm_; }
   /** Sender ID */
   aid_t get_sender() const { return sender_; }
   /** Receiver ID */
   aid_t get_receiver() const { return receiver_; }
   /** Mailbox ID */
   unsigned get_mailbox() const { return mbox_; }
-  /** Sender buffer */
-  uintptr_t get_sbuff() const { return sbuff_; }
-  /** Receiver buffer */
-  uintptr_t get_rbuff() const { return rbuff_; }
-  /** data size */
-  size_t get_size() const { return size_; }
 };
 
 class CommRecvTransition : public Transition {
-  uintptr_t comm_; /* Addr of the CommImpl */
+  unsigned comm_; /* ID of the CommImpl or 0 if not known */
   unsigned mbox_;
-  uintptr_t rbuff_;
   int tag_;
 
 public:
+  CommRecvTransition(aid_t issuer, int times_considered, unsigned comm_, unsigned mbox_, int tag_);
   CommRecvTransition(aid_t issuer, int times_considered, std::stringstream& stream);
   std::string to_string(bool verbose) const override;
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 
-  /** Address of the corresponding Communication object in the application */
-  uintptr_t get_comm() const { return comm_; }
+  /** ID of the corresponding Communication object in the application (or 0 if unknown)*/
+  unsigned get_comm() const { return comm_; }
   /** Mailbox ID */
   unsigned get_mailbox() const { return mbox_; }
-  /** Receiver buffer */
-  uintptr_t get_rbuff() const { return rbuff_; }
   /** If using SMPI, the tag */
   int get_tag() const { return tag_; }
 };
 
 class CommSendTransition : public Transition {
-  uintptr_t comm_; /* Addr of the CommImpl */
+  unsigned comm_;
   unsigned mbox_;
-  uintptr_t sbuff_;
-  size_t size_;
   int tag_;
 
 public:
+  CommSendTransition(aid_t issuer, int times_considered, unsigned comm_, unsigned mbox_, int tag_);
   CommSendTransition(aid_t issuer, int times_considered, std::stringstream& stream);
   std::string to_string(bool verbose) const override;
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 
-  /** Address of the corresponding Communication object in the application */
-  uintptr_t get_comm() const { return comm_; }
+  /** ID of the corresponding Communication object in the application, or 0 if unknown */
+  unsigned get_comm() const { return comm_; }
   /** Mailbox ID */
   unsigned get_mailbox() const { return mbox_; }
-  /** Sender buffer */
-  uintptr_t get_sbuff() const { return sbuff_; }
-  /** data size */
-  size_t get_size() const { return size_; }
   /** If using SMPI, the tag */
   int get_tag() const { return tag_; }
 };
index 63a7d92..f32e459 100644 (file)
@@ -34,9 +34,23 @@ std::string ObjectAccessTransition::to_string(bool verbose) const
 }
 bool ObjectAccessTransition::depends(const Transition* o) const
 {
+  if (o->type_ < type_)
+    return o->depends(this);
+
+  // Actions executed by the same actor are always dependent
+  if (o->aid_ == aid_)
+    return true;
+
   if (const auto* other = dynamic_cast<const ObjectAccessTransition*>(o))
     return objaddr_ == other->objaddr_; // dependent only if it's an access to the same object
   return false;
 }
 
+bool ObjectAccessTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::OBJECT_ACCESS, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // Object access is always enabled
+}
+
 } // namespace simgrid::mc
index 4ca7ff8..f9d7bc2 100644 (file)
@@ -22,6 +22,7 @@ public:
   ObjectAccessTransition(aid_t issuer, int times_considered, std::stringstream& stream);
   std::string to_string(bool verbose) const override;
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 };
 
 } // namespace simgrid::mc
index d117a57..7470be2 100644 (file)
@@ -23,4 +23,11 @@ RandomTransition::RandomTransition(aid_t issuer, int times_considered, std::stri
   xbt_assert(stream >> min_ >> max_);
 }
 
+bool RandomTransition::reversible_race(const Transition* other) const
+{
+  xbt_assert(type_ == Type::RANDOM, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // Random is always enabled
+}
+
 } // namespace simgrid::mc
index ba00821..27d9757 100644 (file)
@@ -17,7 +17,14 @@ class RandomTransition : public Transition {
 public:
   std::string to_string(bool verbose) const override;
   RandomTransition(aid_t issuer, int times_considered, std::stringstream& stream);
-  bool depends(const Transition* other) const override { return aid_ == other->aid_; } // Independent with any other transition
+  bool depends(const Transition* other) const override
+  {
+    if (other->type_ < type_)
+      return other->depends(this);
+
+    return aid_ == other->aid_;
+  } // Independent with any other transition
+  bool reversible_race(const Transition* other) const override;
 };
 
 } // namespace simgrid::mc
index a93e27b..3d0e0cd 100644 (file)
@@ -4,6 +4,8 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/mc/transition/TransitionSynchro.hpp"
+#include "src/mc/mc_forward.hpp"
+#include "src/mc/transition/TransitionObjectAccess.hpp"
 #include "xbt/asserts.h"
 #include "xbt/ex.h"
 #include "xbt/string.hpp"
@@ -29,7 +31,11 @@ bool BarrierTransition::depends(const Transition* o) const
   if (o->type_ < type_)
     return o->depends(this);
 
-  if (auto* other = dynamic_cast<const BarrierTransition*>(o)) {
+  // Actions executed by the same actor are always dependent
+  if (o->aid_ == aid_)
+    return true;
+
+  if (const auto* other = dynamic_cast<const BarrierTransition*>(o)) {
     if (bar_ != other->bar_)
       return false;
 
@@ -46,6 +52,19 @@ bool BarrierTransition::depends(const Transition* o) const
 
   return false; // barriers are INDEP with non-barrier transitions
 }
+bool BarrierTransition::reversible_race(const Transition* other) const
+{
+  switch (type_) {
+    case Type::BARRIER_ASYNC_LOCK:
+      return true; // BarrierAsyncLock is always enabled
+    case Type::BARRIER_WAIT:
+      // If the other event is a barrier lock event, then we are not reversible;
+      // otherwise we are reversible.
+      return other->type_ != Transition::Type::BARRIER_ASYNC_LOCK;
+    default:
+      xbt_die("Unexpected transition type %s", to_c_str(type_));
+  }
+}
 
 std::string MutexTransition::to_string(bool verbose) const
 {
@@ -63,9 +82,13 @@ bool MutexTransition::depends(const Transition* o) const
   if (o->type_ < type_)
     return o->depends(this);
 
+  // Actions executed by the same actor are always dependent
+  if (o->aid_ == aid_)
+    return true;
+
   // type_ <= other->type_ in  MUTEX_LOCK, MUTEX_TEST, MUTEX_TRYLOCK, MUTEX_UNLOCK, MUTEX_WAIT,
 
-  if (auto* other = dynamic_cast<const MutexTransition*>(o)) {
+  if (const auto* other = dynamic_cast<const MutexTransition*>(o)) {
     // Theorem 4.4.7: Any pair of synchronization actions of distinct actors concerning distinct mutexes are independent
     if (mutex_ != other->mutex_)
       return false;
@@ -80,6 +103,12 @@ bool MutexTransition::depends(const Transition* o) const
     if (type_ == Type::MUTEX_ASYNC_LOCK && other->type_ == Type::MUTEX_UNLOCK)
       return false;
 
+    // Theorem 4.4.9: LOCK indep UNLOCK.
+    //  any combination of wait and test is indenpendent.
+    if ((type_ == Type::MUTEX_WAIT || type_ == Type::MUTEX_TEST) &&
+        (other->type_ == Type::MUTEX_WAIT || other->type_ == Type::MUTEX_TEST))
+      return false;
+
     // TEST is a pure function; TEST/WAIT won't change the owner; TRYLOCK will always fail if TEST is enabled (because a
     // request is queued)
     if (type_ == Type::MUTEX_TEST &&
@@ -98,26 +127,49 @@ bool MutexTransition::depends(const Transition* o) const
   return false; // mutexes are INDEP with non-mutex transitions
 }
 
+bool SemaphoreTransition::reversible_race(const Transition* other) const
+{
+  switch (type_) {
+    case Type::SEM_ASYNC_LOCK:
+      return true; // SemAsyncLock is always enabled
+    case Type::SEM_UNLOCK:
+      return true; // SemUnlock is always enabled
+    case Type::SEM_WAIT:
+      if (other->type_ == Transition::Type::SEM_UNLOCK &&
+          static_cast<const SemaphoreTransition*>(other)->get_capacity() <= 1) {
+        return false;
+      }
+      xbt_die("SEM_WAIT that is dependent with a SEM_UNLOCK should not be reversible. FixMe");
+      return true;
+    default:
+      xbt_die("Unexpected transition type %s", to_c_str(type_));
+  }
+}
+
 std::string SemaphoreTransition::to_string(bool verbose) const
 {
   if (type_ == Type::SEM_ASYNC_LOCK || type_ == Type::SEM_UNLOCK)
-    return xbt::string_printf("%s(semaphore: %" PRIxPTR ")", Transition::to_c_str(type_), sem_);
+    return xbt::string_printf("%s(semaphore: %u, capacity: %u)", Transition::to_c_str(type_), sem_, capacity_);
   if (type_ == Type::SEM_WAIT)
-    return xbt::string_printf("%s(semaphore: %" PRIxPTR ", granted: %s)", Transition::to_c_str(type_), sem_,
-                              granted_ ? "yes" : "no");
+    return xbt::string_printf("%s(semaphore: %u, capacity: %u, granted: %s)", Transition::to_c_str(type_), sem_,
+                              capacity_, granted_ ? "yes" : "no");
   THROW_IMPOSSIBLE;
 }
 SemaphoreTransition::SemaphoreTransition(aid_t issuer, int times_considered, Type type, std::stringstream& stream)
     : Transition(type, issuer, times_considered)
 {
-  xbt_assert(stream >> sem_ >> granted_);
+  xbt_assert(stream >> sem_ >> granted_ >> capacity_);
 }
 bool SemaphoreTransition::depends(const Transition* o) const
 {
   if (o->type_ < type_)
     return o->depends(this);
 
-  if (auto* other = dynamic_cast<const SemaphoreTransition*>(o)) {
+  // Actions executed by the same actor are always dependent
+  if (o->aid_ == aid_)
+    return true;
+
+  if (const auto* other = dynamic_cast<const SemaphoreTransition*>(o)) {
     if (sem_ != other->sem_)
       return false;
 
@@ -134,6 +186,10 @@ bool SemaphoreTransition::depends(const Transition* o) const
     if (type_ == Type::SEM_UNLOCK && other->type_ == Type::SEM_UNLOCK)
       return false;
 
+    // UNLOCK indep with a WAIT if the semaphore had enought capacity anyway
+    if (type_ == Type::SEM_UNLOCK && capacity_ > 1 && other->type_ == Type::SEM_WAIT)
+      return false;
+
     // WAIT indep WAIT:
     // if both enabled (may happen in the initial value is sufficient), the ordering has no impact on the result.
     // If only one enabled, the other won't be enabled by the first one.
@@ -147,4 +203,26 @@ bool SemaphoreTransition::depends(const Transition* o) const
   return false; // semaphores are INDEP with non-semaphore transitions
 }
 
+bool MutexTransition::reversible_race(const Transition* other) const
+{
+  switch (type_) {
+    case Type::MUTEX_ASYNC_LOCK:
+      return true; // MutexAsyncLock is always enabled
+    case Type::MUTEX_TEST:
+      return true; // MutexTest is always enabled
+    case Type::MUTEX_TRYLOCK:
+      return true; // MutexTrylock is always enabled
+    case Type::MUTEX_UNLOCK:
+      return true; // MutexUnlock is always enabled
+
+    case Type::MUTEX_WAIT:
+      // Only an Unlock can be dependent with a Wait
+      // and in this case, that Unlock enabled the wait
+      // Not reversible
+      return false;
+    default:
+      xbt_die("Unexpected transition type %s", to_c_str(type_));
+  }
+}
+
 } // namespace simgrid::mc
index 87e4865..d8b7d03 100644 (file)
@@ -19,6 +19,7 @@ public:
   std::string to_string(bool verbose) const override;
   BarrierTransition(aid_t issuer, int times_considered, Type type, std::stringstream& stream);
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
 };
 
 class MutexTransition : public Transition {
@@ -29,16 +30,24 @@ public:
   std::string to_string(bool verbose) const override;
   MutexTransition(aid_t issuer, int times_considered, Type type, std::stringstream& stream);
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
+
+  uintptr_t get_mutex() const { return this->mutex_; }
+  aid_t get_owner() const { return this->owner_; }
 };
 
 class SemaphoreTransition : public Transition {
-  uintptr_t sem_;
+  unsigned int sem_; // ID
   bool granted_;
+  unsigned capacity_;
 
 public:
   std::string to_string(bool verbose) const override;
   SemaphoreTransition(aid_t issuer, int times_considered, Type type, std::stringstream& stream);
   bool depends(const Transition* other) const override;
+  bool reversible_race(const Transition* other) const override;
+
+  int get_capacity() const { return capacity_; }
 };
 
 } // namespace simgrid::mc
diff --git a/src/plugins/battery.cpp b/src/plugins/battery.cpp
new file mode 100644 (file)
index 0000000..0cbfdbc
--- /dev/null
@@ -0,0 +1,472 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+#include <simgrid/Exception.hpp>
+#include <simgrid/plugins/battery.hpp>
+#include <simgrid/plugins/energy.h>
+#include <simgrid/s4u/Engine.hpp>
+#include <simgrid/simix.hpp>
+
+#include "src/kernel/resource/CpuImpl.hpp"
+#include "src/simgrid/module.hpp"
+
+SIMGRID_REGISTER_PLUGIN(battery, "Battery management", nullptr)
+/** @defgroup plugin_battery plugin_battery Plugin Battery
+
+  @beginrst
+
+This is the battery plugin, enabling management of batteries.
+
+Batteries
+.........
+
+A battery has an initial State of Charge :math:`SoC`, a nominal charge power, a nominal discharge power, a charge
+efficiency :math:`\eta_{charge}`, a discharge efficiency :math:`\eta_{discharge}`, an initial capacity
+:math:`C_{initial}` and a number of cycle :math:`N`.
+
+The nominal charge(discharge) power is the maximum power the Battery can consume(provide), before application of the
+charge(discharge) efficiency factor. For instance, if a load provides(consumes) 100W to(from) the Battery with a nominal
+charge(discharge) power of 50W and a charge(discharge) efficiency of 0.9, the Battery will only gain(provide) 45W.
+
+We distinguish the energy provided :math:`E_{provided}` / consumed :math:`E_{consumed}` from the energy lost
+:math:`E_{lost}` / gained :math:`E_{gained}`. The energy provided / consumed shows the external point of view, and the
+energy lost / gained shows the internal point of view:
+
+.. math::
+
+  E_{lost} = {E_{provided} \over \eta_{discharge}}
+
+  E_{gained} = E_{consumed} \times \eta_{charge}
+
+For instance, if you apply a load of 100W to a battery for 10s with a discharge efficiency of 0.8, the energy provided
+will be equal to 10kJ, and the energy lost will be equal to 12.5kJ.
+
+All the energies are positive, but loads connected to a Battery may be positive or negative, as explained in the next
+section.
+
+Use the battery reduces its State of Health :math:`SoH` and its capacity :math:`C` linearly in consequence:
+
+.. math::
+
+  SoH = 1 - {E_{lost} + E_{gained} \over E_{budget}}
+
+  C = C_{initial} \times SoH
+
+With:
+
+.. math::
+
+  E_{budget} = C_{initial} \times N \times 2
+
+Plotting the output of the example "battery-degradation" highlights the linear decrease of the :math:`SoH` due to a
+continuous use of the battery alternating between charge and discharge:
+
+.. image:: /img/battery_degradation.svg
+   :align: center
+
+The natural depletion of batteries over time is not taken into account.
+
+Loads & Hosts
+.............
+
+You can add named loads to a battery. Those loads may be positive and consume energy from the battery, or negative and
+provide energy to the battery. You can also connect hosts to a battery. Theses hosts will consume their energy from the
+battery until the battery is empty or until the connection between the hosts and the battery is set inactive.
+
+Handlers
+........
+
+You can schedule handlers that will happen at specific SoC of the battery and trigger a callback.
+Theses handlers may be recurrent, for instance you may want to always set all loads to zero and deactivate all hosts
+connections when the battery reaches 20% SoC.
+
+Connector
+.........
+
+A Battery can act as a connector to connect Solar Panels direcly to loads. Such Battery is created without any
+parameter, cannot store energy and has a transfer efficiency of 100%.
+
+  @endrst
+ */
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Battery, kernel, "Logging specific to the battery plugin");
+
+namespace simgrid::plugins {
+
+/* BatteryModel */
+
+BatteryModel::BatteryModel() : Model("BatteryModel") {}
+
+void BatteryModel::add_battery(BatteryPtr b)
+{
+  batteries_.push_back(b);
+}
+
+void BatteryModel::update_actions_state(double now, double delta)
+{
+  for (auto battery : batteries_)
+    battery->update();
+}
+
+double BatteryModel::next_occurring_event(double now)
+{
+  static bool init = false;
+  if (!init) {
+    init = true;
+    return 0;
+  }
+  double time_delta = -1;
+  for (auto battery : batteries_) {
+    double time_delta_battery = battery->next_occurring_handler();
+    time_delta                = time_delta == -1 or time_delta_battery < time_delta ? time_delta_battery : time_delta;
+  }
+  return time_delta;
+}
+
+/* Handler */
+
+Battery::Handler::Handler(double state_of_charge, Flow flow, Persistancy p, std::function<void()> callback)
+    : state_of_charge_(state_of_charge), flow_(flow), callback_(callback), persistancy_(p)
+{
+}
+
+std::shared_ptr<Battery::Handler> Battery::Handler::init(double state_of_charge, Flow flow, Persistancy p,
+                                                         std::function<void()> callback)
+{
+  return std::make_shared<Battery::Handler>(state_of_charge, flow, p, callback);
+}
+
+/* Battery */
+
+std::shared_ptr<BatteryModel> Battery::battery_model_;
+
+void Battery::init_plugin()
+{
+  auto model = std::make_shared<BatteryModel>();
+  simgrid::s4u::Engine::get_instance()->add_model(model);
+  Battery::battery_model_ = model;
+}
+
+void Battery::update()
+{
+  kernel::actor::simcall_answered([this] {
+    double now          = s4u::Engine::get_clock();
+    double time_delta_s = now - last_updated_;
+
+    // Nothing to update
+    if (time_delta_s <= 0)
+      return;
+
+    // Calculate energy provided / consumed during this step
+    double provided_power_w = 0;
+    double consumed_power_w = 0;
+    for (auto const& [host, active] : host_loads_)
+      provided_power_w += active ? sg_host_get_current_consumption(host) : 0;
+    for (auto const& [name, pair] : named_loads_) {
+      if (not pair.first)
+        continue;
+      if (pair.second > 0)
+        provided_power_w += pair.second;
+      else
+        consumed_power_w += -pair.second;
+    }
+
+    provided_power_w = std::min(provided_power_w, nominal_discharge_power_w_ * discharge_efficiency_);
+    consumed_power_w = std::min(consumed_power_w, -nominal_charge_power_w_);
+
+    double energy_lost_delta_j   = provided_power_w / discharge_efficiency_ * time_delta_s;
+    double energy_gained_delta_j = consumed_power_w * charge_efficiency_ * time_delta_s;
+
+    // Check that the provided/consumed energy is valid
+    energy_lost_delta_j = std::min(energy_lost_delta_j, energy_stored_j_ + energy_gained_delta_j);
+    /* Charging deteriorate the capacity, but the capacity is used to evaluate the maximum charge so
+       we need to evaluate the theorethical new capacity in the worst case when we fully charge the battery */
+    double new_tmp_capacity_wh =
+        (initial_capacity_wh_ *
+         (1 - (energy_provided_j_ + energy_lost_delta_j * discharge_efficiency_ + energy_consumed_j_ -
+               (energy_stored_j_ + energy_lost_delta_j) / charge_efficiency_) /
+                  energy_budget_j_)) /
+        (1 + 3600 * initial_capacity_wh_ / (charge_efficiency_ * energy_budget_j_));
+    energy_gained_delta_j =
+        std::min(energy_gained_delta_j, (3600 * new_tmp_capacity_wh) - energy_stored_j_ + energy_lost_delta_j);
+
+    // Updating battery
+    energy_provided_j_ += energy_lost_delta_j * discharge_efficiency_;
+    energy_consumed_j_ += energy_gained_delta_j / charge_efficiency_;
+
+    // This battery is a simple connector, we only update energy provided and consumed
+    if (energy_budget_j_ == 0) {
+      energy_consumed_j_ = energy_provided_j_;
+      last_updated_      = now;
+      return;
+    }
+
+    capacity_wh_ =
+        initial_capacity_wh_ *
+        (1 - (energy_provided_j_ / discharge_efficiency_ + energy_consumed_j_ * charge_efficiency_) / energy_budget_j_);
+    energy_stored_j_ += energy_gained_delta_j - energy_lost_delta_j;
+    energy_stored_j_ = std::min(energy_stored_j_, 3600 * capacity_wh_);
+    last_updated_    = now;
+
+    auto handlers_2 = handlers_;
+    for (auto handler : handlers_2) {
+      if (abs(handler->time_delta_ - time_delta_s) < 0.000000001) {
+        handler->callback_();
+        if (handler->persistancy_ == Handler::Persistancy::PERSISTANT)
+          handler->time_delta_ = -1;
+        else
+          delete_handler(handler);
+      }
+    }
+  });
+}
+
+double Battery::next_occurring_handler()
+{
+  double provided_power_w = 0;
+  double consumed_power_w = 0;
+  for (auto const& [host, active] : host_loads_)
+    provided_power_w += active ? sg_host_get_current_consumption(host) : 0;
+  for (auto const& [name, pair] : named_loads_) {
+    if (not pair.first)
+      continue;
+    if (pair.second > 0)
+      provided_power_w += pair.second;
+    else
+      consumed_power_w += -pair.second;
+  }
+
+  provided_power_w = std::min(provided_power_w, nominal_discharge_power_w_ * discharge_efficiency_);
+  consumed_power_w = std::min(consumed_power_w, -nominal_charge_power_w_);
+
+  double time_delta = -1;
+  for (auto& handler : handlers_) {
+    double lost_power_w   = provided_power_w / discharge_efficiency_;
+    double gained_power_w = consumed_power_w * charge_efficiency_;
+    if ((lost_power_w == gained_power_w) or (handler->state_of_charge_ == get_state_of_charge()) or
+        (lost_power_w > gained_power_w and
+         (handler->flow_ == Flow::CHARGE or handler->state_of_charge_ > get_state_of_charge())) or
+        (lost_power_w < gained_power_w and
+         (handler->flow_ == Flow::DISCHARGE or handler->state_of_charge_ < get_state_of_charge()))) {
+      continue;
+    }
+    // Evaluate time until handler happen
+    else {
+      /* The time to reach a state of charge depends on the capacity, but charging and discharging deteriorate the
+       * capacity, so we need to evaluate the time considering a capacity that also depends on time
+       */
+      handler->time_delta_ =
+          (3600 * handler->state_of_charge_ * initial_capacity_wh_ *
+               (1 - (energy_provided_j_ / discharge_efficiency_ + energy_consumed_j_ * charge_efficiency_) /
+                        energy_budget_j_) -
+           energy_stored_j_) /
+          (gained_power_w - lost_power_w +
+           3600 * handler->state_of_charge_ * initial_capacity_wh_ * (gained_power_w + lost_power_w) /
+               energy_budget_j_);
+      if ((time_delta == -1 or handler->time_delta_ < time_delta) and abs(handler->time_delta_) > 0.000000001)
+        time_delta = handler->time_delta_;
+    }
+  }
+  return time_delta;
+}
+
+Battery::Battery(const std::string& name, double state_of_charge, double nominal_charge_power_w,
+                 double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
+                 double initial_capacity_wh, int cycles)
+    : name_(name)
+    , nominal_charge_power_w_(nominal_charge_power_w)
+    , nominal_discharge_power_w_(nominal_discharge_power_w)
+    , charge_efficiency_(charge_efficiency)
+    , discharge_efficiency_(discharge_efficiency)
+    , initial_capacity_wh_(initial_capacity_wh)
+    , energy_budget_j_(initial_capacity_wh * 3600 * cycles * 2)
+    , capacity_wh_(initial_capacity_wh)
+    , energy_stored_j_(state_of_charge * 3600 * initial_capacity_wh)
+{
+  xbt_assert(nominal_charge_power_w <= 0, " : nominal charge power must be <= 0 (provided: %f)",
+             nominal_charge_power_w);
+  xbt_assert(nominal_discharge_power_w >= 0, " : nominal discharge power must be non-negative (provided: %f)",
+             nominal_discharge_power_w);
+  xbt_assert(state_of_charge >= 0 and state_of_charge <= 1, " : state of charge should be in [0, 1] (provided: %f)",
+             state_of_charge);
+  xbt_assert(charge_efficiency > 0 and charge_efficiency <= 1, " : charge efficiency should be in [0,1] (provided: %f)",
+             charge_efficiency);
+  xbt_assert(discharge_efficiency > 0 and discharge_efficiency <= 1,
+             " : discharge efficiency should be in [0,1] (provided: %f)", discharge_efficiency);
+  xbt_assert(initial_capacity_wh > 0, " : initial capacity should be > 0 (provided: %f)", initial_capacity_wh);
+  xbt_assert(cycles > 0, " : cycles should be > 0 (provided: %d)", cycles);
+}
+
+/** @ingroup plugin_battery
+ *  @brief Init a Battery with this constructor makes it only usable as a connector.
+ *         A connector has no capacity and only delivers as much power as it receives
+           with a transfer efficiency of 100%.
+ *  @return A BatteryPtr pointing to the new Battery.
+ */
+BatteryPtr Battery::init()
+{
+  static bool plugin_inited = false;
+  if (not plugin_inited) {
+    init_plugin();
+    plugin_inited = true;
+  }
+  auto battery = BatteryPtr(new Battery());
+  battery_model_->add_battery(battery);
+  return battery;
+}
+
+/** @ingroup plugin_battery
+ *  @param name The name of the Battery.
+ *  @param state_of_charge The initial state of charge of the Battery [0,1].
+ *  @param nominal_charge_power_w The maximum power absorbed by the Battery in W (<= 0).
+ *  @param nominal_discharge_power_w The maximum power delivered by the Battery in W (>= 0).
+ *  @param charge_efficiency The charge efficiency of the Battery [0,1].
+ *  @param discharge_efficiency The discharge efficiency of the Battery [0,1].
+ *  @param initial_capacity_wh The initial capacity of the Battery in Wh (>0).
+ *  @param cycles The number of charge-discharge cycles until complete depletion of the Battery capacity.
+ *  @return A BatteryPtr pointing to the new Battery.
+ */
+BatteryPtr Battery::init(const std::string& name, double state_of_charge, double nominal_charge_power_w,
+                         double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
+                         double initial_capacity_wh, int cycles)
+{
+  static bool plugin_inited = false;
+  if (not plugin_inited) {
+    init_plugin();
+    plugin_inited = true;
+  }
+  auto battery = BatteryPtr(new Battery(name, state_of_charge, nominal_charge_power_w, nominal_discharge_power_w,
+                                        charge_efficiency, discharge_efficiency, initial_capacity_wh, cycles));
+  battery_model_->add_battery(battery);
+  return battery;
+}
+
+/** @ingroup plugin_battery
+ *  @param name The name of the load
+ *  @param power_w Power of the load in W. A positive value discharges the Battery while a negative value charges it.
+ */
+void Battery::set_load(const std::string& name, double power_w)
+{
+  kernel::actor::simcall_answered([this, &name, &power_w] {
+    if (named_loads_.find(name) == named_loads_.end())
+      named_loads_[name] = std::make_pair(true, power_w);
+    else
+      named_loads_[name].second = power_w;
+  });
+}
+
+/** @ingroup plugin_battery
+ *  @param name The name of the load
+ *  @param active Status of the load. If false then the load is ignored by the Battery.
+ */
+void Battery::set_load(const std::string& name, bool active)
+{
+  kernel::actor::simcall_answered([this, &name, &active] { named_loads_[name].first = active; });
+}
+
+/** @ingroup plugin_battery
+ *  @param host The Host to connect.
+ *  @param active Status of the connected Host (default true).
+ *  @brief Connect a Host to the Battery with the status active. As long as the status is true the Host takes its energy
+ from the Battery. To modify this status connect again the same Host with a different status.
+    @warning Do NOT connect the same Host to multiple Batteries with the status true at the same time.
+    In this case all Batteries would have the full consumption from this Host.
+ */
+void Battery::connect_host(s4u::Host* host, bool active)
+{
+  kernel::actor::simcall_answered([this, &host, &active] { host_loads_[host] = active; });
+}
+
+/** @ingroup plugin_battery
+ *  @return The state of charge of the battery.
+ */
+double Battery::get_state_of_charge()
+{
+  return energy_stored_j_ / (3600 * capacity_wh_);
+}
+
+/** @ingroup plugin_battery
+ *  @return The state of health of the Battery.
+ */
+double Battery::get_state_of_health()
+{
+  return 1 -
+         ((energy_provided_j_ / discharge_efficiency_ + energy_consumed_j_ * charge_efficiency_) / energy_budget_j_);
+}
+
+/** @ingroup plugin_battery
+ *  @return The current capacity of the Battery.
+ */
+double Battery::get_capacity()
+{
+  return capacity_wh_;
+}
+
+/** @ingroup plugin_battery
+ *  @return The energy provided by the Battery.
+ *  @note It is the energy provided from an external point of view, after application of the discharge efficiency.
+          It means that the Battery lost more energy than it has provided.
+ */
+double Battery::get_energy_provided()
+{
+  return energy_provided_j_;
+}
+
+/** @ingroup plugin_battery
+ *  @return The energy consumed by the Battery.
+ *  @note It is the energy consumed from an external point of view, before application of the charge efficiency.
+          It means that the Battery consumed more energy than is has absorbed.
+ */
+double Battery::get_energy_consumed()
+{
+  return energy_consumed_j_;
+}
+
+/** @ingroup plugin_battery
+ *  @param unit Valid units are J (default) and Wh.
+ *  @return Energy stored in the Battery.
+ */
+double Battery::get_energy_stored(std::string unit)
+{
+  if (unit == "J")
+    return energy_stored_j_;
+  else if (unit == "Wh")
+    return energy_stored_j_ / 3600;
+  else
+    xbt_die("Invalid unit. Valid units are J (default) or Wh.");
+}
+
+/** @ingroup plugin_battery
+ *  @brief Schedule a new Handler.
+ *  @param state_of_charge The state of charge at which the Handler will happen.
+ *  @param flow The flow in which the Handler will happen, either when the Battery is charging or discharging.
+ *  @param callback The callable to trigger when the Handler happen.
+ *  @param p If the Handler is recurrent or unique.
+ *  @return A shared pointer of the new Handler.
+ */
+std::shared_ptr<Battery::Handler> Battery::schedule_handler(double state_of_charge, Flow flow, Handler::Persistancy p,
+                                                            std::function<void()> callback)
+{
+  auto handler = Handler::init(state_of_charge, flow, p, callback);
+  handlers_.push_back(handler);
+  return handler;
+}
+
+/** @ingroup plugin_battery
+ *  @return A vector containing the Handlers associated to the Battery.
+ */
+std::vector<std::shared_ptr<Battery::Handler>> Battery::get_handlers()
+{
+  return handlers_;
+}
+
+/** @ingroup plugin_battery
+ *  @brief Remove an Handler from the Battery.
+ */
+void Battery::delete_handler(std::shared_ptr<Handler> handler)
+{
+  handlers_.erase(std::remove_if(handlers_.begin(), handlers_.end(),
+                                 [&handler](std::shared_ptr<Handler> e) { return handler == e; }),
+                  handlers_.end());
+}
+} // namespace simgrid::plugins
\ No newline at end of file
index 04810ee..282bcd5 100644 (file)
@@ -23,7 +23,7 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(cmonkey, kernel, "Chaos Monkey plugin");
 
 static void sg_chaos_monkey_plugin_run()
 {
-  auto engine = sg4::Engine::get_instance();
+  const auto* engine = sg4::Engine::get_instance();
   auto hosts  = engine->get_all_hosts();
   auto links  = engine->get_all_links();
 
diff --git a/src/plugins/chiller.cpp b/src/plugins/chiller.cpp
new file mode 100644 (file)
index 0000000..0a4d3af
--- /dev/null
@@ -0,0 +1,305 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+#include <simgrid/Exception.hpp>
+#include <simgrid/plugins/chiller.hpp>
+#include <simgrid/plugins/energy.h>
+#include <simgrid/simix.hpp>
+#include <xbt/asserts.h>
+#include <xbt/log.h>
+
+#include "src/kernel/resource/CpuImpl.hpp"
+#include "src/simgrid/module.hpp"
+
+SIMGRID_REGISTER_PLUGIN(chiller, "Chiller management", nullptr)
+
+/** @defgroup plugin_chiller Plugin Chiller
+
+  @beginrst
+
+This is the chiller plugin, enabling management of chillers.
+
+Chiller
+.......
+
+A chiller is placed inside a room with several machines. The role of the chiller is to keep the temperature of the room
+below a threshold. This plugin and its equations are based on the paper "Co-simulation of FMUs and Distributed
+Applications with SimGrid" by Camus et al. (https://hal.science/hal-01762540).
+
+The heat generated inside the room :math:`Q_{room}` depends on the heat from the machines :math:`Q_{machines}` and
+from the heat of the other devices, such as lighing, accounted using a factor :math:`\alpha` such as:
+
+.. math::
+
+  Q_{room} = (1 + \alpha) \times Q_{machines}
+
+This energy heats the input temperature :math:`T_{in}` and gives an output temperature :math:`T_{out}` based on the
+mass of air inside the room :math:`m_{air}` and its specific heat :math:`C_{p}`:
+
+.. math::
+
+  T_{out} = T_{in} + {Q_{room} \over m_{air} \times C_{p}}
+
+If the output temperature is above the goal temperature :math:`T_{goal}` the chiller compensates the excessive heat
+using electrical energy :math:`Q_{cooling}` depending on its cooling efficiency :math:`\eta_{cooling}` :
+
+.. math::
+
+  Q_{cooling} = (T_{out} - T_{goal}) \times m_{air} \times C_{p} / \eta_{cooling}
+
+The chiller has a power threshold that cannot be exceeded. If the power needed is above this threshold, or if the
+chiller is not active, the temperature of the room increases.
+
+  @endrst
+ */
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Chiller, kernel, "Logging specific to the solar panel plugin");
+
+namespace simgrid::plugins {
+xbt::signal<void(Chiller*)> Chiller::on_power_change; // initialisation of static field
+
+/* ChillerModel */
+
+ChillerModel::ChillerModel() : Model("ChillerModel") {}
+
+void ChillerModel::add_chiller(ChillerPtr c)
+{
+  chillers_.push_back(c);
+}
+
+void ChillerModel::update_actions_state(double now, double delta)
+{
+  for (auto chiller : chillers_)
+    chiller->update();
+}
+
+double ChillerModel::next_occurring_event(double now)
+{
+  static bool init = false;
+  if (not init) {
+    init = true;
+    return 0;
+  } else
+    return -1;
+}
+
+/* Chiller */
+
+std::shared_ptr<ChillerModel> Chiller::chiller_model_;
+
+void Chiller::init_plugin()
+{
+  auto model = std::make_shared<ChillerModel>();
+  simgrid::s4u::Engine::get_instance()->add_model(model);
+  Chiller::chiller_model_ = model;
+}
+
+void Chiller::update()
+{
+  simgrid::kernel::actor::simcall_answered([this] {
+    double now          = s4u::Engine::get_clock();
+    double time_delta_s = now - last_updated_;
+
+    if (time_delta_s <= 0)
+      return;
+
+    double hosts_power_w = 0;
+    for (auto const& host : hosts_) {
+      hosts_power_w += sg_host_get_current_consumption(host);
+    }
+
+    double heat_generated_j = hosts_power_w * (1 + alpha_) * time_delta_s;
+    temp_out_c_             = temp_in_c_ + heat_generated_j / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
+    double cooling_demand_w =
+        std::max(temp_out_c_ - goal_temp_c_, 0.0) * air_mass_kg_ * specific_heat_j_per_kg_per_c_ / time_delta_s;
+    if (not active_)
+      power_w_ = 0;
+    else
+      power_w_ = std::min(max_power_w_, cooling_demand_w / cooling_efficiency_);
+    temp_in_c_ =
+        temp_out_c_ - (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_);
+    energy_consumed_j_ += power_w_ * time_delta_s;
+    last_updated_ = now;
+  });
+}
+
+Chiller::Chiller(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
+                 double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w)
+    : name_(name)
+    , air_mass_kg_(air_mass_kg)
+    , specific_heat_j_per_kg_per_c_(specific_heat_j_per_kg_per_c)
+    , alpha_(alpha)
+    , cooling_efficiency_(cooling_efficiency)
+    , temp_in_c_(initial_temp_c)
+    , temp_out_c_(initial_temp_c)
+    , goal_temp_c_(goal_temp_c)
+    , max_power_w_(max_power_w)
+{
+  xbt_assert(air_mass_kg > 0, ": air mass must be > 0 (provided: %f)", air_mass_kg);
+  xbt_assert(specific_heat_j_per_kg_per_c > 0, ": specific heat must be > 0 (provided: %f)",
+             specific_heat_j_per_kg_per_c);
+  xbt_assert(alpha >= 0, ": alpha must be >= 0 (provided: %f)", alpha);
+  xbt_assert(cooling_efficiency >= 0 and cooling_efficiency <= 1,
+             ": cooling efficiency must be in [0,1] (provided: %f)", cooling_efficiency);
+  xbt_assert(max_power_w >= 0, ": maximal power must be >=0 (provided: %f)", max_power_w);
+}
+
+/** @ingroup plugin_chiller
+ *  @param name The name of the Chiller.
+ *  @param air_mass_kg The air mass of the room managed by the Chiller in kg (> 0).
+ *  @param specific_heat_j_per_kg_per_c The specific heat of air in J per kg per °C (> 0).
+ *  @param alpha The ratio of the other devices in the total heat dissipation (e.g. lighting, Power Distribution Unit)
+ * (>= 0).
+ *  @param cooling_efficiency The cooling efficiency of the Chiller [0, 1].
+ *  @param initial_temp_c The initial temperature of the room managed by the Chiller.
+ *  @param goal_temp_c The goal temperature of the room. The Chiller is idle below this temperature.
+ *  @param max_power_w The maximal power delivered by the Chiller in W (> 0). If this power is reached the room
+ * temperature will raise above the goal temperature.
+ *  @return A ChillerPtr pointing to the new Chiller.
+ */
+ChillerPtr Chiller::init(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha,
+                         double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w)
+{
+  static bool plugin_inited = false;
+  if (not plugin_inited) {
+    init_plugin();
+    plugin_inited = true;
+  }
+  auto chiller = ChillerPtr(new Chiller(name, air_mass_kg, specific_heat_j_per_kg_per_c, alpha, cooling_efficiency,
+                                        initial_temp_c, goal_temp_c, max_power_w));
+  chiller_model_->add_chiller(chiller);
+  return chiller;
+}
+
+/** @ingroup plugin_chiller
+ *  @param name The new name of the Chiller.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::set_name(std::string name)
+{
+  simgrid::kernel::actor::simcall_answered([this, name] { name_ = name; });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param air_mass_kg The new air mass of the Chiller in kg.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::set_air_mass(double air_mass_kg)
+{
+  xbt_assert(air_mass_kg > 0, ": air mass must be > 0 (provided: %f)", air_mass_kg);
+  simgrid::kernel::actor::simcall_answered([this, air_mass_kg] { air_mass_kg_ = air_mass_kg; });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param specific_heat_j_per_kg_per_c The specific heat of the Chiller in J per kg per °C.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::set_specific_heat(double specific_heat_j_per_kg_per_c)
+{
+  xbt_assert(specific_heat_j_per_kg_per_c > 0, ": specific heat must be > 0 (provided: %f)",
+             specific_heat_j_per_kg_per_c);
+  simgrid::kernel::actor::simcall_answered(
+      [this, specific_heat_j_per_kg_per_c] { specific_heat_j_per_kg_per_c_ = specific_heat_j_per_kg_per_c; });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param alpha The new alpha of the Chiller.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::set_alpha(double alpha)
+{
+  xbt_assert(alpha >= 0, ": alpha must be >= 0 (provided: %f)", alpha);
+  simgrid::kernel::actor::simcall_answered([this, alpha] { alpha_ = alpha; });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param cooling_efficiency The new coolingefficiency of the Chiller.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::set_cooling_efficiency(double cooling_efficiency)
+{
+  xbt_assert(cooling_efficiency >= 0 and cooling_efficiency <= 1,
+             ": cooling efficiency must be in [0,1] (provided: %f)", cooling_efficiency);
+  simgrid::kernel::actor::simcall_answered([this, cooling_efficiency] { cooling_efficiency_ = cooling_efficiency; });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param goal_temp_c The new goal temperature of the Chiller in °C.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::set_goal_temp(double goal_temp_c)
+{
+  simgrid::kernel::actor::simcall_answered([this, goal_temp_c] { goal_temp_c_ = goal_temp_c; });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param max_power_w The new maximal power of the Chiller in W.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::set_max_power(double max_power_w)
+{
+  xbt_assert(max_power_w >= 0, ": maximal power must be >=0 (provided: %f)", max_power_w);
+  simgrid::kernel::actor::simcall_answered([this, max_power_w] { max_power_w_ = max_power_w; });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param active The new active status of the Chiller.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::set_active(bool active)
+{
+  simgrid::kernel::actor::simcall_answered([this, active] { active_ = active; });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param host The host to add to the room managed by the Chiller.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::add_host(s4u::Host* host)
+{
+  simgrid::kernel::actor::simcall_answered([this, host] { hosts_.insert(host); });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @param host The host to remove from the room managed by the Chiller.
+ *  @return A ChillerPtr pointing to the modified Chiller.
+ */
+ChillerPtr Chiller::remove_host(s4u::Host* host)
+{
+  simgrid::kernel::actor::simcall_answered([this, host] { hosts_.erase(host); });
+  return this;
+}
+
+/** @ingroup plugin_chiller
+ *  @return The time to reach to goal temp, assuming that the system remain in the same state.
+ */
+double Chiller::get_time_to_goal_temp() const
+{
+  if (goal_temp_c_ == temp_in_c_)
+    return 0;
+
+  double heat_power_w = 0;
+  for (auto const& host : hosts_)
+    heat_power_w += sg_host_get_current_consumption(host);
+  heat_power_w = heat_power_w * (1 + alpha_);
+
+  if (temp_in_c_ < goal_temp_c_)
+    return air_mass_kg_ * (goal_temp_c_ - temp_in_c_) * specific_heat_j_per_kg_per_c_ / heat_power_w;
+
+  if (not active_)
+    return -1;
+  else
+    return air_mass_kg_ * (temp_in_c_ - goal_temp_c_) * specific_heat_j_per_kg_per_c_ /
+           (power_w_ * cooling_efficiency_ - heat_power_w);
+}
+} // namespace simgrid::plugins
index 15f1871..31b7fff 100644 (file)
@@ -412,49 +412,28 @@ static void on_host_creation(simgrid::s4u::Host& host)
   host.extension_set<FileDescriptorHostExt>(new FileDescriptorHostExt());
 }
 
-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 (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());
-  }
-}
-
-static void on_simulation_end()
-{
-  XBT_DEBUG("Simulation is over, time to unregister remote disks if any");
-  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(":"));
-      XBT_DEBUG("Host '%s' wants to unmount a remote disk: %s of %s mounted on %s", host->get_cname(),
-                tokens[1].c_str(), tokens[2].c_str(), tokens[0].c_str());
-      host->remove_disk(tokens[1]);
-      XBT_DEBUG("Host '%s' now has %zu disks", host->get_cname(), host->get_disks().size());
-    }
-  }
+ 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 (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);
+   }
 }
 
 /* **************************** Public interface *************************** */
@@ -481,7 +460,6 @@ void sg_storage_file_system_init()
     simgrid::s4u::Host::on_creation_cb(&on_host_creation);
   }
   simgrid::s4u::Engine::on_platform_created_cb(&on_platform_created);
-  simgrid::s4u::Engine::on_simulation_end_cb(&on_simulation_end);
 }
 
 sg_file_t sg_file_open(const char* fullpath, void* data)
index 0a5ac58..138cdae 100644 (file)
@@ -289,21 +289,18 @@ public:
       if (activity.get_host() == get_host())
         pre_task();
     });
-    simgrid::s4u::Activity::on_completion_cb([this](simgrid::s4u::Activity const& activity) {
-      const auto* exec = dynamic_cast<simgrid::s4u::Exec const*>(&activity);
-      if (exec == nullptr) // Only Execs are concerned here
-        return;
+    simgrid::s4u::Exec::on_completion_cb([this](simgrid::s4u::Exec const& exec) {
       // For more than one host (not yet supported), we can access the host via
       // simcalls_.front()->issuer->get_iface()->get_host()
-      if (exec->get_host() == get_host() && iteration_running) {
-        comp_timer += exec->get_finish_time() - exec->get_start_time();
+      if (exec.get_host() == get_host() && iteration_running) {
+        comp_timer += exec.get_finish_time() - exec.get_start_time();
       }
     });
     // FIXME I think that this fires at the same time for all hosts, so when the src sends something,
     // the dst will be notified even though it didn't even arrive at the recv yet
-    kernel::activity::CommImpl::on_start.connect([this](const kernel::activity::CommImpl& comm) {
-      const auto* act = static_cast<kernel::resource::NetworkAction*>(comm.model_action_);
-      if ((get_host() == &act->get_src() || get_host() == &act->get_dst()) && iteration_running) {
+    simgrid::s4u::Comm::on_start_cb([this](const s4u::Comm& comm) {
+      if ((get_host() == comm.get_sender()->get_host() || get_host() == comm.get_receiver()->get_host()) &&
+           iteration_running) {
         post_task();
       }
     });
index 2bf95b1..aab32cb 100644 (file)
@@ -11,6 +11,7 @@
 #include <simgrid/s4u/VirtualMachine.hpp>
 #include <simgrid/simix.hpp>
 
+#include "src/kernel/activity/ActivityImpl.hpp"
 #include "src/kernel/resource/CpuImpl.hpp"
 #include "src/simgrid/module.hpp"
 
@@ -420,7 +421,7 @@ static void on_creation(simgrid::s4u::Host& host)
 static void on_action_state_change(simgrid::kernel::resource::CpuAction const& action,
                                    simgrid::kernel::resource::Action::State /*previous*/)
 {
-  for (simgrid::kernel::resource::CpuImpl* const& cpu : action.cpus()) {
+  for (simgrid::kernel::resource::CpuImpl const* cpu : action.cpus()) {
     simgrid::s4u::Host* host = cpu->get_iface();
     if (host != nullptr) {
       // If it's a VM, take the corresponding PM
@@ -438,14 +439,13 @@ static void on_action_state_change(simgrid::kernel::resource::CpuAction const& a
 
 /* This callback is fired either when the host changes its state (on/off) ("onStateChange") or its speed
  * (because the user changed the pstate, or because of external trace events) ("onSpeedChange") */
-static void on_host_change(simgrid::s4u::Host const& host)
+static void on_host_change(simgrid::s4u::Host const& h)
 {
-  if (dynamic_cast<simgrid::s4u::VirtualMachine const*>(&host)) // Ignore virtual machines
-    return;
-
-  auto* host_energy = host.extension<HostEnergy>();
+  const auto* host = &h;
+  if (const auto* vm = dynamic_cast<simgrid::s4u::VirtualMachine const*>(host)) // Take the PM of virtual machines
+    host = vm->get_pm();
 
-  host_energy->update();
+  host->extension<HostEnergy>()->update();
 }
 
 static void on_host_destruction(simgrid::s4u::Host const& host)
@@ -473,6 +473,12 @@ static void on_simulation_end()
            used_hosts_energy, total_energy - used_hosts_energy);
 }
 
+static void on_activity_suspend_resume(simgrid::s4u::Activity const& activity)
+{
+  if (const auto* action = dynamic_cast<simgrid::kernel::resource::CpuAction*>(activity.get_impl()->model_action_))
+    on_action_state_change(*action, /*ignored*/ action->get_state());
+}
+
 /* **************************** Public interface *************************** */
 
 /** @ingroup plugin_host_energy
@@ -487,20 +493,24 @@ void sg_host_energy_plugin_init()
   HostEnergy::EXTENSION_ID = simgrid::s4u::Host::extension_create<HostEnergy>();
 
   simgrid::s4u::Host::on_creation_cb(&on_creation);
-  simgrid::s4u::Host::on_state_change_cb(&on_host_change);
+  simgrid::s4u::Host::on_onoff_cb(&on_host_change);
   simgrid::s4u::Host::on_speed_change_cb(&on_host_change);
   simgrid::s4u::Host::on_destruction_cb(&on_host_destruction);
+  simgrid::s4u::Host::on_exec_state_change_cb(&on_action_state_change);
+  simgrid::s4u::VirtualMachine::on_suspend_cb(&on_host_change);
+  simgrid::s4u::VirtualMachine::on_resume_cb(&on_host_change);
+  simgrid::s4u::Exec::on_suspend_cb(on_activity_suspend_resume);
+  simgrid::s4u::Exec::on_resume_cb(on_activity_suspend_resume);
   simgrid::s4u::Engine::on_simulation_end_cb(&on_simulation_end);
-  simgrid::kernel::resource::CpuAction::on_state_change.connect(&on_action_state_change);
   // We may only have one actor on a node. If that actor executes something like
   //   compute -> recv -> compute
-  // the recv operation will not trigger a "CpuAction::on_state_change". This means
+  // the recv operation will not trigger a "Host::on_exec_state_change_cb". This means
   // that the next trigger would be the 2nd compute, hence ignoring the idle time
   // during the recv call. By updating at the beginning of a compute, we can
   // fix that. (If the cpu is not idle, this is not required.)
   simgrid::s4u::Exec::on_start_cb([](simgrid::s4u::Exec const& activity) {
     if (activity.get_host_number() == 1) { // We only run on one host
-      simgrid::s4u::Host* host         = activity.get_host();
+      simgrid::s4u::Host* host = activity.get_host();
       if (const auto* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(host))
         host = vm->get_pm();
       xbt_assert(host != nullptr);
@@ -544,7 +554,7 @@ static void ensure_plugin_inited()
 double sg_host_get_consumed_energy(const_sg_host_t host)
 {
   ensure_plugin_inited();
-  auto host_energy = host->extension<HostEnergy>();
+  auto* host_energy = host->extension<HostEnergy>();
   xbt_assert(host_energy->has_pstate_power_values(), "No power range properties specified for host %s",
              host->get_cname());
   return host_energy->get_consumed_energy();
@@ -598,7 +608,7 @@ double sg_host_get_power_range_slope_at(const_sg_host_t host, int pstate)
 double sg_host_get_current_consumption(const_sg_host_t host)
 {
   ensure_plugin_inited();
-  auto host_energy = host->extension<HostEnergy>();
+  auto* host_energy = host->extension<HostEnergy>();
   xbt_assert(host_energy->has_pstate_power_values(), "No power range properties specified for host %s",
              host->get_cname());
   return host_energy->get_current_watts_value();
index 6479b3a..a19b720 100644 (file)
@@ -24,8 +24,7 @@ It attaches an extension to each host to store some data, and places callbacks i
   - :cpp:func:`simgrid::s4u::Host::on_creation_cb`: Attach a new extension to the newly created host.
   - :cpp:func:`simgrid::s4u::Exec::on_start_cb`: Make note that a new execution started, increasing the load.
   - :cpp:func:`simgrid::s4u::Exec::on_completion_cb`: Make note that an execution completed, decreasing the load.
-  - :cpp:func:`simgrid::s4u::Host::on_state_change_cb`: Do what is appropriate when the host gets suspended, turned off
-    or similar.
+  - :cpp:func:`simgrid::s4u::Host::on_onoff_cb`: Do what is appropriate when the host gets turned off or on.
   - :cpp:func:`simgrid::s4u::Host::on_speed_change_cb`: Do what is appropriate when the DVFS is modified.
 
   Note that extensions are automatically destroyed when the host gets destroyed.
@@ -122,7 +121,7 @@ void HostLoad::update()
   // This loop updates the flops that the host executed for the ongoing computations
   auto iter = begin(current_activities);
   while (iter != end(current_activities)) {
-    auto& activity                         = iter->first;  // Just an alias
+    const auto& activity                   = iter->first;  // Just an alias
     auto& remaining_cost_after_last_update = iter->second; // Just an alias
     auto& action                           = activity->model_action_;
     auto current_iter                      = iter;
@@ -247,12 +246,9 @@ void sg_host_load_plugin_init()
       XBT_WARN("HostLoad plugin currently does not support executions on several hosts");
     }
   });
-  simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-    const auto* exec = dynamic_cast<simgrid::s4u::Exec const*>(&activity);
-    if (exec == nullptr) // Only Execs are concerned here
-      return;
-    if (exec->get_host_number() == 1) { // We only run on one host
-      simgrid::s4u::Host* host               = exec->get_host();
+  simgrid::s4u::Exec::on_completion_cb([](simgrid::s4u::Exec const& exec) {
+    if (exec.get_host_number() == 1) { // We only run on one host
+      simgrid::s4u::Host* host = exec.get_host();
       if (const auto* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(host))
         host = vm->get_pm();
       xbt_assert(host != nullptr);
@@ -261,7 +257,7 @@ void sg_host_load_plugin_init()
       XBT_WARN("HostLoad plugin currently does not support executions on several hosts");
     }
   });
-  simgrid::s4u::Host::on_state_change_cb(&on_host_change);
+  simgrid::s4u::Host::on_onoff_cb(&on_host_change);
   simgrid::s4u::Host::on_speed_change_cb(&on_host_change);
 }
 
diff --git a/src/plugins/jbod.cpp b/src/plugins/jbod.cpp
new file mode 100644 (file)
index 0000000..8e169c4
--- /dev/null
@@ -0,0 +1,170 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <simgrid/plugins/jbod.hpp>
+#include <simgrid/s4u/Comm.hpp>
+#include <simgrid/s4u/Disk.hpp>
+#include <simgrid/s4u/Exec.hpp>
+#include <simgrid/s4u/NetZone.hpp>
+
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_jbod, s4u, "Logging specific to the JBOD implmentation");
+
+namespace simgrid::plugin {
+
+JbodPtr Jbod::create_jbod(s4u::NetZone* zone, const std::string& name, double speed, unsigned int num_disks,
+                          RAID raid_level, double read_bandwidth, double write_bandwidth)
+{
+  xbt_assert(not ((raid_level == RAID::RAID4 || raid_level == RAID::RAID5) && num_disks < 3),
+             "RAID%d requires at least 3 disks", (int) raid_level);
+  xbt_assert(not (raid_level == RAID::RAID6 && num_disks < 4), "RAID6 requires at least 4 disks");
+
+  auto* jbod = new Jbod();
+  jbod->set_controller(zone->create_host(name, speed));
+  jbod->set_num_disks(num_disks);
+  jbod->set_parity_disk_idx(num_disks -1 );
+  jbod->set_read_disk_idx(-1);
+  jbod->set_raid_level(raid_level);
+  for (unsigned int i = 0; i < num_disks; i++)
+    jbod->get_controller()->create_disk(name + "_disk_" + std::to_string(i), read_bandwidth, write_bandwidth);
+
+  return JbodPtr(jbod, false);
+}
+
+JbodIoPtr Jbod::read_async(sg_size_t size)
+{
+  auto comm = s4u::Comm::sendto_init()->set_source(this->controller_)->set_payload_size(size);
+  std::vector<s4u::IoPtr> pending_ios;
+  sg_size_t read_size = 0;
+  std::vector<s4u::Disk*> targets;
+  switch(raid_level_) {
+    case RAID::RAID0:
+      read_size = size / num_disks_;
+      targets = controller_->get_disks();
+      break;
+    case RAID::RAID1:
+      read_size = size;
+      targets.push_back(controller_->get_disks().at(get_next_read_disk_idx()));
+      break;
+    case RAID::RAID4:
+      read_size = size / (num_disks_ - 1);
+      targets = controller_->get_disks();
+      targets.pop_back();
+      break;
+    case RAID::RAID5:
+      read_size = size / (num_disks_ - 1);
+      targets = controller_->get_disks();
+      targets.erase(targets.begin() + (get_parity_disk_idx() + 1 % num_disks_));
+      break;
+    case RAID::RAID6:
+      read_size = size / (num_disks_ - 2);
+      targets = controller_->get_disks();
+      if ( (get_parity_disk_idx() + 2 % num_disks_) == 0 ) {
+        targets.pop_back();
+        targets.erase(targets.begin());
+      } else if (get_parity_disk_idx() + 1 == static_cast<int>(num_disks_)) {
+        targets.pop_back();
+        targets.pop_back();
+      } else {
+        targets.erase(targets.begin() + (get_parity_disk_idx() + 1) % num_disks_,
+                      targets.begin() + get_parity_disk_idx() + 3);
+      }
+      break;
+    default:
+      xbt_die("Unsupported RAID level. Supported level are: 0, 1, 4, 5, and 6");
+  }
+  for (const auto* disk : targets) {
+    auto io = s4u::IoPtr(disk->io_init(read_size, s4u::Io::OpType::READ));
+    io->set_name(disk->get_name())->start();
+    pending_ios.push_back(io);
+  }
+
+  return JbodIoPtr(new JbodIo(this, comm, nullptr, pending_ios, s4u::Io::OpType::READ));
+}
+
+sg_size_t Jbod::read(sg_size_t size)
+{
+  read_async(size)->wait();
+  return size;
+}
+
+JbodIoPtr Jbod::write_async(sg_size_t size)
+{
+  auto comm = s4u::Comm::sendto_init(s4u::Host::current(), this->get_controller());
+  std::vector<s4u::IoPtr> pending_ios;
+  sg_size_t write_size = 0;
+  switch(raid_level_) {
+    case RAID::RAID0:
+      write_size = size / num_disks_;
+      break;
+    case RAID::RAID1:
+      write_size = size;
+      break;
+    case RAID::RAID4:
+      write_size = size / (num_disks_ - 1);
+      break;
+    case RAID::RAID5:
+      update_parity_disk_idx();
+      write_size = size / (num_disks_ - 1);
+      break;
+    case RAID::RAID6:
+      update_parity_disk_idx();
+      update_parity_disk_idx();
+      write_size = size / (num_disks_ - 2);
+      break;
+    default:
+      xbt_die("Unsupported RAID level. Supported level are: 0, 1, 4, 5, and 6");
+  }
+  for (const auto* disk : get_controller()->get_disks()) {
+    auto io = s4u::IoPtr(disk->io_init(write_size, s4u::Io::OpType::WRITE));
+    io->set_name(disk->get_name());
+    pending_ios.push_back(io);
+  }
+
+  s4u::ExecPtr parity_block_comp = nullptr;
+  if (raid_level_ == RAID::RAID4 || raid_level_ == RAID::RAID5 || raid_level_ == RAID::RAID6) {
+    // Assume 1 flop per byte to write per parity block and two for RAID6.
+    // Do not assign the Exec yet, will be done after the completion of the CommPtr
+    if (raid_level_ == RAID::RAID6)
+      parity_block_comp = s4u::Exec::init()->set_flops_amount(200 * write_size);
+    else
+      parity_block_comp = s4u::Exec::init()->set_flops_amount(write_size);
+  }
+
+  comm->set_payload_size(size)->start();
+  return JbodIoPtr(new JbodIo(this, comm, parity_block_comp, pending_ios, s4u::Io::OpType::WRITE));
+}
+
+sg_size_t Jbod::write(sg_size_t size)
+{
+  write_async(size)->wait();
+  return size;
+}
+
+void JbodIo::wait()
+{
+  if (type_ == s4u::Io::OpType::WRITE) {
+    transfer_->wait();
+    XBT_DEBUG("Data received on JBOD");
+    if (parity_block_comp_) {
+      parity_block_comp_->set_host(jbod_->get_controller())->wait();
+      XBT_DEBUG("Parity block computed");
+    }
+    XBT_DEBUG("Start writing");
+    for (const auto& io : pending_ios_)
+      io->start();
+  }
+
+  for (const auto& io : pending_ios_) {
+    XBT_DEBUG("Wait for I/O on %s", io->get_cname());
+    io->wait();
+  }
+
+  if (type_ == s4u::Io::OpType::READ) {
+    XBT_DEBUG("Data read on JBOD, send it to %s", s4u::Host::current()->get_cname());
+    transfer_->set_destination(s4u::Host::current())->wait();
+  }
+}
+} // namespace simgrid::plugin
index 29b3700..e163799 100644 (file)
@@ -6,6 +6,7 @@
 #include "simgrid/Exception.hpp"
 #include "simgrid/host.h"
 #include "simgrid/plugins/energy.h"
+#include "simgrid/s4u/Comm.hpp"
 #include "simgrid/s4u/Engine.hpp"
 #include "simgrid/s4u/Link.hpp"
 #include "src/kernel/activity/CommImpl.hpp"
@@ -128,7 +129,7 @@ double LinkEnergy::get_power() const
 
   double power_slope = busy_ - idle_;
 
-  double normalized_link_usage = link_->get_usage() / link_->get_bandwidth();
+  double normalized_link_usage = link_->get_load() / link_->get_bandwidth();
   double dynamic_power         = power_slope * normalized_link_usage;
 
   return idle_ + dynamic_power;
@@ -161,15 +162,17 @@ static void on_simulation_end()
   XBT_INFO("Total energy over all links: %f", total_energy);
 }
 
-static void on_communication(const simgrid::kernel::activity::CommImpl& comm)
+static void on_communication(const simgrid::s4u::Comm& comm)
 {
-  for (auto const* link : comm.get_traversed_links()) {
+  const auto* pimpl = static_cast<simgrid::kernel::activity::CommImpl*>(comm.get_impl());
+  for (auto const* link : pimpl->get_traversed_links()) {
     if (link != nullptr && link->get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI) {
       XBT_DEBUG("Update %s on Comm Start/End", link->get_cname());
       link->extension<LinkEnergy>()->update();
     }
   }
 }
+
 /* **************************** Public interface *************************** */
 
 int sg_link_energy_is_inited()
@@ -198,7 +201,7 @@ void sg_link_energy_plugin_init()
     }
   });
 
-  simgrid::s4u::Link::on_state_change_cb([](simgrid::s4u::Link const& link) {
+  simgrid::s4u::Link::on_onoff_cb([](simgrid::s4u::Link const& link) {
     if (link.get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI)
       link.extension<LinkEnergy>()->update();
   });
@@ -209,8 +212,8 @@ void sg_link_energy_plugin_init()
                link.extension<LinkEnergy>()->get_consumed_energy());
   });
 
-  simgrid::kernel::activity::CommImpl::on_start.connect(&on_communication);
-  simgrid::kernel::activity::CommImpl::on_completion.connect(&on_communication);
+  simgrid::s4u::Comm::on_start_cb(&on_communication);
+  simgrid::s4u::Comm::on_completion_cb(&on_communication);
 
   simgrid::s4u::Engine::on_simulation_end_cb(&on_simulation_end);
 }
index 481f1f2..ec2e84c 100644 (file)
@@ -4,6 +4,7 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include <simgrid/plugins/energy.h>
+#include <simgrid/s4u/Comm.hpp>
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/s4u/Link.hpp>
 
@@ -187,7 +188,7 @@ void LinkEnergyWifi::update()
    *  - if idle i.e. get_usage = 0, update P_{stat}
    * P_{tot} = P_{dyn}+P_{stat}
    */
-  if (link_->get_usage() != 0.0) {
+  if (link_->get_load() != 0.0) {
     eDyn_ += /*duration * */ durUsage * ((host_count * pRx_) + pTx_);
     eStat_ += (duration - durUsage) * pIdle_ * (host_count + 1);
     XBT_DEBUG("eDyn +=  %f * ((%f * %f) + %f) | eDyn = %f (durusage =%f)", durUsage, host_count, pRx_, pTx_, eDyn_,
@@ -265,9 +266,10 @@ void LinkEnergyWifi::init_watts_range_list()
 
 using simgrid::plugin::LinkEnergyWifi;
 /* **************************** events  callback *************************** */
-static void on_communication(const simgrid::kernel::activity::CommImpl& comm)
+static void on_communication(const simgrid::s4u::Comm& comm)
 {
-  for (const auto* link : comm.get_traversed_links()) {
+  const auto* pimpl = static_cast<simgrid::kernel::activity::CommImpl*>(comm.get_impl());
+  for (auto const* link : pimpl->get_traversed_links()) {
     if (link != nullptr && link->get_sharing_policy() == simgrid::s4u::Link::SharingPolicy::WIFI) {
       auto* link_energy = link->extension<LinkEnergyWifi>();
       XBT_DEBUG("Update %s on Comm Start/End", link->get_cname());
@@ -324,6 +326,6 @@ void sg_wifi_energy_plugin_init()
     }
   });
 
-  simgrid::kernel::activity::CommImpl::on_start.connect(&on_communication);
-  simgrid::kernel::activity::CommImpl::on_completion.connect(&on_communication);
+  simgrid::s4u::Comm::on_start_cb(&on_communication);
+  simgrid::s4u::Comm::on_completion_cb(&on_communication);
 }
index 1afdd6e..d2df784 100644 (file)
@@ -4,6 +4,7 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include <simgrid/plugins/load.h>
+#include <simgrid/s4u/Comm.hpp>
 #include <simgrid/s4u/Engine.hpp>
 
 #include "src/kernel/activity/CommImpl.hpp"
@@ -111,7 +112,7 @@ void LinkLoad::update()
              " Please track your link with sg_link_load_track before trying to access any of its load metrics.",
              link_->get_cname());
 
-  double current_instantaneous_bytes_per_second = link_->get_usage();
+  double current_instantaneous_bytes_per_second = link_->get_load();
   double now                                    = simgrid::s4u::Engine::get_clock();
 
   // Update minimum/maximum observed values if needed
@@ -161,9 +162,10 @@ double LinkLoad::get_average_bytes()
 using simgrid::plugin::LinkLoad;
 
 /* **************************** events  callback *************************** */
-static void on_communication(const simgrid::kernel::activity::CommImpl& comm)
+static void on_communication(const simgrid::s4u::Comm& comm)
 {
-  for (const auto* link : comm.get_traversed_links()) {
+  const auto* pimpl = static_cast<simgrid::kernel::activity::CommImpl*>(comm.get_impl());
+  for (auto const* link : pimpl->get_traversed_links()) {
     if (link != nullptr && link->get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI) {
       auto* link_load = link->extension<LinkLoad>();
       XBT_DEBUG("Update %s on Comm Start/End", link->get_cname());
@@ -199,12 +201,12 @@ void sg_link_load_plugin_init()
   });
 
   // Call this plugin on some of the links' events.
-  simgrid::kernel::activity::CommImpl::on_start.connect(&on_communication);
-  simgrid::kernel::activity::CommImpl::on_completion.connect(&on_communication);
+  simgrid::s4u::Comm::on_start_cb(&on_communication);
+  simgrid::s4u::Comm::on_completion_cb(&on_communication);
 
-  simgrid::s4u::Link::on_state_change_cb([](simgrid::s4u::Link const& link) {
+  simgrid::s4u::Link::on_onoff_cb([](simgrid::s4u::Link const& link) {
     if (link.get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI) {
-      auto link_load = link.extension<LinkLoad>();
+      auto* link_load = link.extension<LinkLoad>();
       if (link_load->is_tracked())
         link_load->update();
     }
@@ -213,7 +215,7 @@ void sg_link_load_plugin_init()
                                                           simgrid::kernel::resource::Action::State /* previous */) {
     for (auto const* link : action.get_links()) {
       if (link != nullptr && link->get_sharing_policy() != simgrid::s4u::Link::SharingPolicy::WIFI) {
-        auto link_load = link->get_iface()->extension<LinkLoad>();
+        auto* link_load = link->get_iface()->extension<LinkLoad>();
         if (link_load->is_tracked())
           link_load->update();
       }
diff --git a/src/plugins/solar_panel.cpp b/src/plugins/solar_panel.cpp
new file mode 100644 (file)
index 0000000..c6f2581
--- /dev/null
@@ -0,0 +1,181 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+#include <simgrid/Exception.hpp>
+#include <simgrid/plugins/solar_panel.hpp>
+#include <simgrid/simix.hpp>
+#include <xbt/asserts.h>
+#include <xbt/log.h>
+
+#include "src/kernel/resource/CpuImpl.hpp"
+#include "src/simgrid/module.hpp"
+
+SIMGRID_REGISTER_PLUGIN(solar_panel, "Solar Panel management", nullptr)
+
+/** @defgroup plugin_solar_panel Plugin Solar Panel
+
+  @beginrst
+
+This is the solar panel plugin, enabling management of solar panels on hosts.
+
+This plugin allows the use of solar panels to generate power during simulation depending on size, solar
+irradiance and conversion factor.
+
+The power model is taken from the paper `"Reinforcement Learning Based Load Balancing for
+Geographically Distributed Data Centres" <https://dro.dur.ac.uk/33395/1/33395.pdf?DDD280+kkgc95+vbdv77>`_ by Max Mackie
+et. al.
+
+Solar Panel
+....................
+
+A solar panel has an area :math:`A` in m², a conversion efficiency :math:`\eta` and a solar irradiance :math:`S` in
+W/m². The power generated :math:`P` in W by a solar panel is given by the following equation:
+
+.. math::
+
+  P = A \times \eta \times S
+
+  @endrst
+ */
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(SolarPanel, kernel, "Logging specific to the solar panel plugin");
+
+namespace simgrid::plugins {
+
+xbt::signal<void(SolarPanel*)> SolarPanel::on_power_change;
+
+/* SolarPanel */
+
+void SolarPanel::update()
+{
+  simgrid::kernel::actor::simcall_answered([this] {
+    double power_w = conversion_efficiency_ * area_m2_ * solar_irradiance_w_per_m2_;
+    if (power_w < min_power_w_)
+      power_w = 0;
+    if (power_w > max_power_w_)
+      power_w = max_power_w_;
+    auto previous_power_w = power_w_;
+    power_w_              = power_w;
+    if (previous_power_w != power_w_) {
+      on_this_power_change(this);
+      on_power_change(this);
+    }
+  });
+}
+
+SolarPanel::SolarPanel(std::string name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2,
+                       double min_power_w, double max_power_w)
+    : name_(name)
+    , area_m2_(area_m2)
+    , conversion_efficiency_(conversion_efficiency)
+    , solar_irradiance_w_per_m2_(solar_irradiance_w_per_m2)
+    , min_power_w_(min_power_w)
+    , max_power_w_(max_power_w)
+{
+  xbt_assert(area_m2 >= 0, " : area must be >= 0 (provided: %f)", area_m2);
+  xbt_assert(conversion_efficiency >= 0 and conversion_efficiency <= 1,
+             " : conversion efficiency must be in [0,1] (provided: %f)", conversion_efficiency);
+  xbt_assert(solar_irradiance_w_per_m2 >= 0, " : solar irradiance must be >= 0 (provided: %f)",
+             solar_irradiance_w_per_m2);
+  xbt_assert(min_power_w >= 0, " : minimal power must be >= 0 (provided: %f)", min_power_w);
+  xbt_assert(max_power_w > 0, " : maximal power must be > 0 (provided: %f)", max_power_w);
+  xbt_assert(max_power_w > min_power_w, " : maximal power must be above minimal power (provided: %f, %f)", max_power_w,
+             min_power_w);
+}
+
+/** @ingroup plugin_solar_panel
+ *  @param name The name of the Solar Panel.
+ *  @param area_m2 The area of the Solar Panel in m² (> 0).
+ *  @param conversion_efficiency The conversion efficiency of the Solar Panel [0,1].
+ *  @param solar_irradiance_w_per_m2 The solar irradiance of the Solar Panel in W/m² (> 0).
+ *  @param min_power_w The minimal power delivered by the Solar Panel in W (> 0 and < max_power_w).
+ *  @param max_power_w The maximal power delivered by the Solar Panel in W (> 0 and > min_power_w).
+ *  @return A SolarPanelPtr pointing to the new SolarPanel.
+ */
+SolarPanelPtr SolarPanel::init(const std::string& name, double area_m2, double conversion_efficiency,
+                               double solar_irradiance_w_per_m2, double min_power_w, double max_power_w)
+{
+  auto solar_panel = SolarPanelPtr(
+      new SolarPanel(name, area_m2, conversion_efficiency, solar_irradiance_w_per_m2, min_power_w, max_power_w));
+  solar_panel->update();
+  return solar_panel;
+}
+
+/** @ingroup plugin_solar_panel
+ *  @param name The new name of the Solar Panel.
+ *  @return A SolarPanelPtr pointing to the modified SolarPanel.
+ */
+SolarPanelPtr SolarPanel::set_name(std::string name)
+{
+  kernel::actor::simcall_answered([this, name] { name_ = name; });
+  return this;
+}
+
+/** @ingroup plugin_solar_panel
+ *  @param area_m2 The new area of the Solar Panel in m².
+ *  @return A SolarPanelPtr pointing to the modified SolarPanel.
+ */
+SolarPanelPtr SolarPanel::set_area(double area_m2)
+{
+  xbt_assert(area_m2 >= 0, " : area must be > 0 (provided: %f)", area_m2);
+  kernel::actor::simcall_answered([this, area_m2] { area_m2_ = area_m2; });
+  update();
+  return this;
+}
+
+/** @ingroup plugin_solar_panel
+ *  @param e The new convesion efficiency of the Solar Panel.
+ *  @return A SolarPanelPtr pointing to the modified SolarPanel.
+ */
+SolarPanelPtr SolarPanel::set_conversion_efficiency(double e)
+{
+  xbt_assert(e >= 0 and e <= 1, " : conversion efficiency must be in [0,1] (provided: %f)", e);
+  kernel::actor::simcall_answered([this, e] { conversion_efficiency_ = e; });
+  update();
+  return this;
+}
+
+/** @ingroup plugin_solar_panel
+ *  @param solar_irradiance_w_per_m2 The new solar irradiance of the Solar Panel in W/m².
+ *  @return A SolarPanelPtr pointing to the modified SolarPanel.
+ */
+SolarPanelPtr SolarPanel::set_solar_irradiance(double solar_irradiance_w_per_m2)
+{
+  xbt_assert(solar_irradiance_w_per_m2 >= 0, " : solar irradiance must be >= 0 (provided: %f)",
+             solar_irradiance_w_per_m2);
+  kernel::actor::simcall_answered(
+      [this, solar_irradiance_w_per_m2] { solar_irradiance_w_per_m2_ = solar_irradiance_w_per_m2; });
+  update();
+  return this;
+}
+
+/** @ingroup plugin_solar_panel
+ *  @param power_w The new minimal power of the Solar Panel in W.
+ *  @return A SolarPanelPtr pointing to the modified SolarPanel.
+ */
+SolarPanelPtr SolarPanel::set_min_power(double power_w)
+{
+  xbt_assert(power_w >= 0, " : minimal power must be >= 0 (provided: %f)", power_w);
+  xbt_assert(max_power_w_ > power_w, " : maximal power must be above minimal power (provided: %f, max: %f)", power_w,
+             max_power_w_);
+  kernel::actor::simcall_answered([this, power_w] { min_power_w_ = power_w; });
+  update();
+  return this;
+}
+
+/** @ingroup plugin_solar_panel
+ *  @param power_w The new maximal power of the Solar Panel in W.
+ *  @return A SolarPanelPtr pointing to the modified SolarPanel.
+ */
+SolarPanelPtr SolarPanel::set_max_power(double power_w)
+{
+  xbt_assert(power_w > 0, " : maximal power must be > 0 (provided: %f)", power_w);
+  xbt_assert(min_power_w_ < power_w, " : maximal power must be above minimal power (provided: %f, min: %f)", power_w,
+             min_power_w_);
+  kernel::actor::simcall_answered([this, power_w] { max_power_w_ = power_w; });
+  update();
+  return this;
+}
+
+} // namespace simgrid::plugins
\ No newline at end of file
index d5a7443..d30a1b0 100644 (file)
@@ -76,7 +76,7 @@ static void on_virtual_machine_creation(const simgrid::s4u::VirtualMachine& vm)
 
 static void on_exec_creation(simgrid::s4u::Exec const& e)
 {
-  auto exec                              = static_cast<simgrid::kernel::activity::ExecImpl*>(e.get_impl());
+  const auto* exec                       = static_cast<simgrid::kernel::activity::ExecImpl*>(e.get_impl());
   const simgrid::s4u::VirtualMachine* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(exec->get_host());
   if (vm == nullptr)
     return;
@@ -88,9 +88,9 @@ static void on_exec_creation(simgrid::s4u::Exec const& e)
   }
 }
 
-static void on_exec_completion(const simgrid::s4u::Activity& e)
+static void on_exec_completion(const simgrid::s4u::Exec& e)
 {
-  const auto exec = dynamic_cast<simgrid::kernel::activity::ExecImpl*>(e.get_impl());
+  const auto* exec = dynamic_cast<simgrid::kernel::activity::ExecImpl*>(e.get_impl());
   if (exec == nullptr)
     return;
   const simgrid::s4u::VirtualMachine* vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(exec->get_host());
@@ -113,7 +113,7 @@ void sg_vm_dirty_page_tracking_init()
         simgrid::kernel::resource::VirtualMachineImpl::extension_create<DirtyPageTrackingExt>();
     simgrid::s4u::VirtualMachine::on_creation_cb(&on_virtual_machine_creation);
     simgrid::s4u::Exec::on_start_cb(&on_exec_creation);
-    simgrid::s4u::Activity::on_completion_cb(&on_exec_completion);
+    simgrid::s4u::Exec::on_completion_cb(&on_exec_completion);
   }
 }
 
index 7b38f61..a1711b5 100644 (file)
@@ -9,6 +9,7 @@
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/s4u/Exec.hpp>
 #include <simgrid/s4u/Io.hpp>
+#include <simgrid/s4u/Mess.hpp>
 #include <xbt/log.h>
 
 #include "src/kernel/activity/ActivityImpl.hpp"
@@ -24,11 +25,6 @@ template class xbt::Extendable<s4u::Activity>;
 
 namespace s4u {
 
-xbt::signal<void(Activity&)> Activity::on_veto;
-xbt::signal<void(Activity const&)> Activity::on_completion;
-xbt::signal<void(Activity const&)> Activity::on_suspended;
-xbt::signal<void(Activity const&)> Activity::on_resumed;
-
 std::set<Activity*>* Activity::vetoed_activities_ = nullptr;
 
 void Activity::destroy()
@@ -57,6 +53,8 @@ Activity* Activity::wait_for(double timeout)
   if (state_ == State::FAILED) {
     if (dynamic_cast<Comm*>(this))
       throw NetworkFailureException(XBT_THROW_POINT, "Cannot wait for a failed comm");
+    if (dynamic_cast<Mess*>(this))
+      throw NetworkFailureException(XBT_THROW_POINT, "Cannot wait for a failed mess");
     if (dynamic_cast<Exec*>(this))
       throw HostFailureException(XBT_THROW_POINT, "Cannot wait for a failed exec");
     if (dynamic_cast<Io*>(this))
@@ -65,7 +63,7 @@ Activity* Activity::wait_for(double timeout)
   }
 
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::ActivityWaitSimcall observer{issuer, pimpl_.get(), timeout};
+  kernel::actor::ActivityWaitSimcall observer{issuer, pimpl_.get(), timeout, "wait_for"};
   if (kernel::actor::simcall_blocking(
           [&observer] { observer.get_activity()->wait_for(observer.get_issuer(), observer.get_timeout()); }, &observer))
     throw TimeoutException(XBT_THROW_POINT, "Timeouted");
@@ -85,7 +83,7 @@ bool Activity::test()
     this->start();
 
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::ActivityTestSimcall observer{issuer, pimpl_.get()};
+  kernel::actor::ActivityTestSimcall observer{issuer, pimpl_.get(), "test"};
   if (kernel::actor::simcall_answered([&observer] { return observer.get_activity()->test(observer.get_issuer()); },
                                       &observer)) {
     complete(State::FINISHED);
@@ -94,14 +92,14 @@ bool Activity::test()
   return false;
 }
 
-ssize_t Activity::test_any(const std::vector<ActivityPtr>& activities)
+ssize_t Activity::test_any(const std::vector<ActivityPtr>& activities) // XBT_ATTRIB_DEPRECATED_v339
 {
   std::vector<kernel::activity::ActivityImpl*> ractivities(activities.size());
   std::transform(begin(activities), end(activities), begin(ractivities),
                  [](const ActivityPtr& act) { return act->pimpl_.get(); });
 
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::ActivityTestanySimcall observer{issuer, ractivities};
+  kernel::actor::ActivityTestanySimcall observer{issuer, ractivities, "test_any"};
   ssize_t changed_pos = kernel::actor::simcall_answered(
       [&observer] {
         return kernel::activity::ActivityImpl::test_any(observer.get_issuer(), observer.get_activities());
@@ -112,14 +110,14 @@ ssize_t Activity::test_any(const std::vector<ActivityPtr>& activities)
   return changed_pos;
 }
 
-ssize_t Activity::wait_any_for(const std::vector<ActivityPtr>& activities, double timeout)
+ssize_t Activity::deprecated_wait_any_for(const std::vector<ActivityPtr>& activities, double timeout) // XBT_ATTRIB_DEPRECATED_v339
 {
   std::vector<kernel::activity::ActivityImpl*> ractivities(activities.size());
   std::transform(begin(activities), end(activities), begin(ractivities),
                  [](const ActivityPtr& activity) { return activity->pimpl_.get(); });
 
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::ActivityWaitanySimcall observer{issuer, ractivities, timeout};
+  kernel::actor::ActivityWaitanySimcall observer{issuer, ractivities, timeout, "wait_any_for"};
   ssize_t changed_pos = kernel::actor::simcall_blocking(
       [&observer] {
         kernel::activity::ActivityImpl::wait_any_for(observer.get_issuer(), observer.get_activities(),
diff --git a/src/s4u/s4u_ActivitySet.cpp b/src/s4u/s4u_ActivitySet.cpp
new file mode 100644 (file)
index 0000000..61957a3
--- /dev/null
@@ -0,0 +1,190 @@
+/* Copyright (c) 2023-. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/kernel/activity/ActivityImpl.hpp"
+#include "src/kernel/actor/ActorImpl.hpp"
+#include "src/kernel/actor/CommObserver.hpp"
+#include <simgrid/Exception.hpp>
+#include <simgrid/activity_set.h>
+#include <simgrid/s4u/ActivitySet.hpp>
+#include <simgrid/s4u/Engine.hpp>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_activityset, s4u_activity, "S4U set of activities");
+
+namespace simgrid {
+
+template class xbt::Extendable<s4u::ActivitySet>;
+
+namespace s4u {
+
+void ActivitySet::erase(ActivityPtr a)
+{
+  for (auto it = activities_.begin(); it != activities_.end(); it++)
+    if (*it == a) {
+      activities_.erase(it);
+      return;
+    }
+}
+
+void ActivitySet::wait_all_for(double timeout)
+{
+  if (timeout < 0.0) {
+    for (const auto& act : activities_)
+      act->wait();
+
+  } else {
+
+    double deadline = Engine::get_clock() + timeout;
+    for (const auto& act : activities_)
+      act->wait_until(deadline);
+  }
+}
+
+ActivityPtr ActivitySet::test_any()
+{
+  std::vector<kernel::activity::ActivityImpl*> act_impls(activities_.size());
+  std::transform(begin(activities_), end(activities_), begin(act_impls),
+                 [](const ActivityPtr& act) { return act->pimpl_.get(); });
+
+  kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
+  kernel::actor::ActivityTestanySimcall observer{issuer, act_impls, "test_any"};
+  ssize_t changed_pos = kernel::actor::simcall_answered(
+      [&observer] {
+        return kernel::activity::ActivityImpl::test_any(observer.get_issuer(), observer.get_activities());
+      },
+      &observer);
+  if (changed_pos == -1)
+    return ActivityPtr(nullptr);
+
+  auto ret = activities_.at(changed_pos);
+  erase(ret);
+  ret->complete(Activity::State::FINISHED);
+  return ret;
+}
+
+void ActivitySet::handle_failed_activities()
+{
+  for (size_t i = 0; i < activities_.size(); i++) {
+    auto act = activities_[i];
+    if (act->pimpl_->get_state() == kernel::activity::State::FAILED) {
+      act->complete(Activity::State::FAILED);
+
+      failed_activities_.push_back(act);
+      activities_[i] = activities_[activities_.size() - 1];
+      activities_.resize(activities_.size() - 1);
+      i--; // compensate the i++ occuring at the end of the loop
+    }
+  }
+}
+
+ActivityPtr ActivitySet::wait_any_for(double timeout)
+{
+  std::vector<kernel::activity::ActivityImpl*> act_impls(activities_.size());
+  std::transform(begin(activities_), end(activities_), begin(act_impls),
+                 [](const ActivityPtr& activity) { return activity->pimpl_.get(); });
+
+  kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
+  kernel::actor::ActivityWaitanySimcall observer{issuer, act_impls, timeout, "wait_any_for"};
+  try {
+    ssize_t changed_pos = kernel::actor::simcall_blocking(
+        [&observer] {
+          kernel::activity::ActivityImpl::wait_any_for(observer.get_issuer(), observer.get_activities(),
+                                                       observer.get_timeout());
+        },
+        &observer);
+    if (changed_pos == -1)
+      throw TimeoutException(XBT_THROW_POINT, "Timeouted");
+
+    auto ret = activities_.at(changed_pos);
+    erase(ret);
+    ret->complete(Activity::State::FINISHED);
+    return ret;
+  } catch (const HostFailureException& e) {
+    handle_failed_activities();
+    throw;
+  } catch (const NetworkFailureException& e) {
+    handle_failed_activities();
+    throw;
+  } catch (const StorageFailureException& e) {
+    handle_failed_activities();
+    throw;
+  }
+}
+
+ActivityPtr ActivitySet::get_failed_activity()
+{
+  if (failed_activities_.empty())
+    return ActivityPtr(nullptr);
+  auto ret = failed_activities_.back();
+  failed_activities_.pop_back();
+  return ret;
+}
+
+} // namespace s4u
+} // namespace simgrid
+
+SG_BEGIN_DECL
+
+sg_activity_set_t sg_activity_set_init()
+{
+  return new simgrid::s4u::ActivitySet();
+}
+void sg_activity_set_push(sg_activity_set_t as, sg_activity_t acti)
+{
+  as->push(acti);
+}
+void sg_activity_set_erase(sg_activity_set_t as, sg_activity_t acti)
+{
+  as->erase(acti);
+}
+size_t sg_activity_set_size(sg_activity_set_t as)
+{
+  return as->size();
+}
+int sg_activity_set_empty(sg_activity_set_t as)
+{
+  return as->empty();
+}
+
+sg_activity_t sg_activity_set_test_any(sg_activity_set_t as)
+{
+  return as->test_any().get();
+}
+void sg_activity_set_wait_all(sg_activity_set_t as)
+{
+  as->wait_all();
+}
+int sg_activity_set_wait_all_for(sg_activity_set_t as, double timeout)
+{
+  try {
+    as->wait_all_for(timeout);
+    return 1;
+  } catch (const simgrid::TimeoutException& e) {
+    return 0;
+  }
+}
+sg_activity_t sg_activity_set_wait_any(sg_activity_set_t as)
+{
+  return as->wait_any().get();
+}
+sg_activity_t sg_activity_set_wait_any_for(sg_activity_set_t as, double timeout)
+{
+  try {
+    return as->wait_any_for(timeout).get();
+  } catch (const simgrid::TimeoutException& e) {
+    return nullptr;
+  }
+}
+
+void sg_activity_set_delete(sg_activity_set_t as)
+{
+  delete as;
+}
+void sg_activity_unref(sg_activity_t acti)
+{
+  acti->unref();
+}
+
+SG_END_DECL
index 3e84903..573d708 100644 (file)
@@ -164,6 +164,7 @@ void Actor::set_host(Host* new_host)
   });
 
   s4u::Actor::on_host_change(*this, *previous_location);
+  s4u::Actor::on_this_host_change(*this, *previous_location);
 }
 
 s4u::Host* Actor::get_host() const
@@ -213,6 +214,7 @@ void Actor::suspend()
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
   kernel::actor::ActorImpl* target = pimpl_;
   s4u::Actor::on_suspend(*this);
+  s4u::Actor::on_this_suspend(*this);
   kernel::actor::simcall_blocking([issuer, target]() {
     target->suspend();
     if (target != issuer) {
@@ -226,6 +228,7 @@ void Actor::resume()
 {
   kernel::actor::simcall_answered([this] { pimpl_->resume(); });
   s4u::Actor::on_resume(*this);
+  s4u::Actor::on_this_resume(*this);
 }
 
 bool Actor::is_suspended() const
@@ -325,19 +328,25 @@ void sleep_for(double duration)
   }
 
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
+  kernel::actor::ActorSleepSimcall observer(issuer);
+
   Actor::on_sleep(*issuer->get_ciface());
+  issuer->get_ciface()->on_this_sleep(*issuer->get_ciface());
 
-  kernel::actor::simcall_blocking([issuer, duration]() {
-    if (MC_is_active() || MC_record_replay_is_active()) {
-      MC_process_clock_add(issuer, duration);
-      issuer->simcall_answer();
-      return;
-    }
-    kernel::activity::ActivityImplPtr sync = issuer->sleep(duration);
-    sync->register_simcall(&issuer->simcall_);
-  });
+  kernel::actor::simcall_blocking(
+      [issuer, duration]() {
+        if (MC_is_active() || MC_record_replay_is_active()) {
+          // MC_process_clock_add(issuer, duration); // BUG: Makes the exploration loop
+          issuer->simcall_answer();
+        } else {
+          kernel::activity::ActivityImplPtr sync = issuer->sleep(duration);
+          sync->register_simcall(&issuer->simcall_);
+        }
+      },
+      &observer);
 
   Actor::on_wake_up(*issuer->get_ciface());
+  issuer->get_ciface()->on_this_wake_up(*issuer->get_ciface());
 }
 
 void yield()
@@ -442,6 +451,7 @@ void suspend()
 {
   kernel::actor::ActorImpl* self = simgrid::kernel::actor::ActorImpl::self();
   s4u::Actor::on_suspend(*self->get_ciface());
+  self->get_ciface()->on_this_suspend(*self->get_ciface());
   kernel::actor::simcall_blocking([self] { self->suspend(); });
 }
 
index 6ec1ecd..aec421b 100644 (file)
@@ -6,6 +6,7 @@
 #include <cmath>
 #include <simgrid/Exception.hpp>
 #include <simgrid/comm.h>
+#include <simgrid/s4u/ActivitySet.hpp>
 #include <simgrid/s4u/Comm.hpp>
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/s4u/Mailbox.hpp>
@@ -29,7 +30,7 @@ CommPtr Comm::set_copy_data_callback(const std::function<void(kernel::activity::
 }
 
 void Comm::copy_buffer_callback(kernel::activity::CommImpl* comm, void* buff,
-                                size_t buff_size) // XBT_ATTRIB_DEPRECATED_v337
+                                size_t buff_size) // XBT_ATTRIB_DEPRECATED_v338
 {
   XBT_DEBUG("Copy the data over");
   memcpy(comm->dst_buff_, buff, buff_size);
@@ -41,7 +42,7 @@ void Comm::copy_buffer_callback(kernel::activity::CommImpl* comm, void* buff,
 }
 
 void Comm::copy_pointer_callback(kernel::activity::CommImpl* comm, void* buff,
-                                 size_t buff_size) // XBT_ATTRIB_DEPRECATED_v337
+                                 size_t buff_size) // XBT_ATTRIB_DEPRECATED_v338
 {
   xbt_assert((buff_size == sizeof(void*)), "Cannot copy %zu bytes: must be sizeof(void*)", buff_size);
   *(void**)(comm->dst_buff_) = buff;
@@ -78,12 +79,13 @@ void Comm::send(kernel::actor::ActorImpl* sender, const Mailbox* mbox, double ta
     simgrid::kernel::activity::ActivityImplPtr comm = nullptr;
 
     simgrid::kernel::actor::CommIsendSimcall send_observer{
-        sender,  mbox->get_impl(), task_size, rate, static_cast<unsigned char*>(src_buff), src_buff_size, match_fun,
-        nullptr, copy_data_fun,    data,      false};
+        sender,        mbox->get_impl(), task_size, rate,          static_cast<unsigned char*>(src_buff),
+        src_buff_size, match_fun,        nullptr,   copy_data_fun, data,
+        false,         "Isend"};
     comm = simgrid::kernel::actor::simcall_answered(
         [&send_observer] { return simgrid::kernel::activity::CommImpl::isend(&send_observer); }, &send_observer);
 
-    if (simgrid::kernel::actor::ActivityWaitSimcall wait_observer{sender, comm.get(), timeout};
+    if (simgrid::kernel::actor::ActivityWaitSimcall wait_observer{sender, comm.get(), timeout, "Wait"};
         simgrid::kernel::actor::simcall_blocking(
             [&wait_observer] {
               wait_observer.get_activity()->wait_for(wait_observer.get_issuer(), wait_observer.get_timeout());
@@ -95,7 +97,7 @@ void Comm::send(kernel::actor::ActorImpl* sender, const Mailbox* mbox, double ta
   } else {
     simgrid::kernel::actor::CommIsendSimcall observer(sender, mbox->get_impl(), task_size, rate,
                                                       static_cast<unsigned char*>(src_buff), src_buff_size, match_fun,
-                                                      nullptr, copy_data_fun, data, false);
+                                                      nullptr, copy_data_fun, data, false, "Isend");
     simgrid::kernel::actor::simcall_blocking([&observer, timeout] {
       simgrid::kernel::activity::ActivityImplPtr comm = simgrid::kernel::activity::CommImpl::isend(&observer);
       comm->wait_for(observer.get_issuer(), timeout);
@@ -122,11 +124,12 @@ void Comm::recv(kernel::actor::ActorImpl* receiver, const Mailbox* mbox, void* d
                                                       match_fun,
                                                       copy_data_fun,
                                                       data,
-                                                      rate};
+                                                      rate,
+                                                      "Irecv"};
     comm = simgrid::kernel::actor::simcall_answered(
         [&observer] { return simgrid::kernel::activity::CommImpl::irecv(&observer); }, &observer);
 
-    if (simgrid::kernel::actor::ActivityWaitSimcall wait_observer{receiver, comm.get(), timeout};
+    if (simgrid::kernel::actor::ActivityWaitSimcall wait_observer{receiver, comm.get(), timeout, "wait"};
         simgrid::kernel::actor::simcall_blocking(
             [&wait_observer] {
               wait_observer.get_activity()->wait_for(wait_observer.get_issuer(), wait_observer.get_timeout());
@@ -137,7 +140,7 @@ void Comm::recv(kernel::actor::ActorImpl* receiver, const Mailbox* mbox, void* d
     comm = nullptr;
   } else {
     simgrid::kernel::actor::CommIrecvSimcall observer(receiver, mbox->get_impl(), static_cast<unsigned char*>(dst_buff),
-                                                      dst_buff_size, match_fun, copy_data_fun, data, rate);
+                                                      dst_buff_size, match_fun, copy_data_fun, data, rate, "Irecv");
     simgrid::kernel::actor::simcall_blocking([&observer, timeout] {
       simgrid::kernel::activity::ActivityImplPtr comm = simgrid::kernel::activity::CommImpl::irecv(&observer);
       comm->wait_for(observer.get_issuer(), timeout);
@@ -211,7 +214,7 @@ Host* Comm::get_destination() const
 CommPtr Comm::set_rate(double rate)
 {
   xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)",
-             __FUNCTION__);
+             __func__);
   rate_ = rate;
   return this;
 }
@@ -219,7 +222,7 @@ CommPtr Comm::set_rate(double rate)
 CommPtr Comm::set_mailbox(Mailbox* mailbox)
 {
   xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)",
-             __FUNCTION__);
+             __func__);
   mailbox_ = mailbox;
   return this;
 }
@@ -227,7 +230,7 @@ CommPtr Comm::set_mailbox(Mailbox* mailbox)
 CommPtr Comm::set_src_data(void* buff)
 {
   xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)",
-             __FUNCTION__);
+             __func__);
   xbt_assert(dst_buff_ == nullptr, "Cannot set the src and dst buffers at the same time");
   src_buff_ = buff;
   return this;
@@ -236,7 +239,7 @@ CommPtr Comm::set_src_data(void* buff)
 CommPtr Comm::set_src_data_size(size_t size)
 {
   xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)",
-             __FUNCTION__);
+             __func__);
   src_buff_size_ = size;
   return this;
 }
@@ -244,7 +247,7 @@ CommPtr Comm::set_src_data_size(size_t size)
 CommPtr Comm::set_src_data(void* buff, size_t size)
 {
   xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)",
-             __FUNCTION__);
+             __func__);
 
   xbt_assert(dst_buff_ == nullptr, "Cannot set the src and dst buffers at the same time");
   src_buff_      = buff;
@@ -255,7 +258,7 @@ CommPtr Comm::set_src_data(void* buff, size_t size)
 CommPtr Comm::set_dst_data(void** buff)
 {
   xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)",
-             __FUNCTION__);
+             __func__);
   xbt_assert(src_buff_ == nullptr, "Cannot set the src and dst buffers at the same time");
   dst_buff_ = buff;
   return this;
@@ -264,7 +267,7 @@ CommPtr Comm::set_dst_data(void** buff)
 CommPtr Comm::set_dst_data(void** buff, size_t size)
 {
   xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)",
-             __FUNCTION__);
+             __func__);
 
   xbt_assert(src_buff_ == nullptr, "Cannot set the src and dst buffers at the same time");
   dst_buff_      = buff;
@@ -281,6 +284,14 @@ CommPtr Comm::set_payload_size(uint64_t bytes)
   return this;
 }
 
+void* Comm::get_payload() const
+{
+  xbt_assert(get_state() == State::FINISHED,
+             "You can only retrieve the payload of a communication that gracefully terminated, but its state is %s.",
+             get_state_str());
+  return static_cast<kernel::activity::CommImpl*>(pimpl_.get())->payload_;
+}
+
 Actor* Comm::get_sender() const
 {
   kernel::actor::ActorImplPtr sender = nullptr;
@@ -289,6 +300,14 @@ Actor* Comm::get_sender() const
   return sender ? sender->get_ciface() : nullptr;
 }
 
+Actor* Comm::get_receiver() const
+{
+  kernel::actor::ActorImplPtr receiver = nullptr;
+  if (pimpl_)
+    receiver = boost::static_pointer_cast<kernel::activity::CommImpl>(pimpl_)->dst_actor_;
+  return receiver ? receiver->get_ciface() : nullptr;
+}
+
 bool Comm::is_assigned() const
 {
   return (pimpl_ && boost::static_pointer_cast<kernel::activity::CommImpl>(pimpl_)->is_assigned()) ||
@@ -298,7 +317,10 @@ bool Comm::is_assigned() const
 Comm* Comm::do_start()
 {
   xbt_assert(get_state() == State::INITED || get_state() == State::STARTING,
-             "You cannot use %s() once your communication started (not implemented)", __FUNCTION__);
+             "You cannot use %s() once your communication started (not implemented)", __func__);
+
+  auto myself = kernel::actor::ActorImpl::self();
+
   if (get_source() != nullptr || get_destination() != nullptr) {
     xbt_assert(is_assigned(), "When either from_ or to_ is specified, both must be.");
     xbt_assert(src_buff_ == nullptr && dst_buff_ == nullptr,
@@ -308,8 +330,11 @@ Comm* Comm::do_start()
       pimpl_->set_state(kernel::activity::State::READY);
       boost::static_pointer_cast<kernel::activity::CommImpl>(pimpl_)->start();
     });
-  } else if (src_buff_ != nullptr) { // Sender side
+    fire_on_start();
+    fire_on_this_start();
+  } else if (myself == sender_) {
     on_send(*this);
+    on_this_send(*this);
     kernel::actor::CommIsendSimcall observer{sender_,
                                              mailbox_->get_impl(),
                                              remains_,
@@ -320,12 +345,14 @@ Comm* Comm::do_start()
                                              clean_fun_,
                                              copy_data_function_,
                                              get_data<void>(),
-                                             detached_};
+                                             detached_,
+                                             "Isend"};
     pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::CommImpl::isend(&observer); },
                                              &observer);
-  } else if (dst_buff_ != nullptr) { // Receiver side
+  } else if (myself == receiver_) {
     xbt_assert(not detached_, "Receive cannot be detached");
     on_recv(*this);
+    on_this_recv(*this);
     kernel::actor::CommIrecvSimcall observer{receiver_,
                                              mailbox_->get_impl(),
                                              static_cast<unsigned char*>(dst_buff_),
@@ -333,7 +360,8 @@ Comm* Comm::do_start()
                                              match_fun_,
                                              copy_data_function_,
                                              get_data<void>(),
-                                             rate_};
+                                             rate_,
+                                             "Irecv"};
     pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::CommImpl::irecv(&observer); },
                                              &observer);
   } else {
@@ -346,6 +374,11 @@ Comm* Comm::do_start()
   if (not detached_) {
     pimpl_->set_iface(this);
     pimpl_->set_actor(sender_);
+    // Only throw the signal when both sides are here and the status is READY
+    if (pimpl_->get_state() != kernel::activity::State::WAITING) {
+      fire_on_start();
+      fire_on_this_start();
+    }
   }
 
   state_ = State::STARTED;
@@ -355,19 +388,28 @@ Comm* Comm::do_start()
 Comm* Comm::detach()
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
-             "You cannot use %s() once your communication is %s (not implemented)", __FUNCTION__, get_state_str());
+             "You cannot use %s() once your communication is %s (not implemented)", __func__, get_state_str());
   xbt_assert(dst_buff_ == nullptr && dst_buff_size_ == 0, "You can only detach sends, not recvs");
   detached_ = true;
   start();
   return this;
 }
 
-ssize_t Comm::test_any(const std::vector<CommPtr>& comms)
+ssize_t Comm::test_any(const std::vector<CommPtr>& comms) // XBT_ATTRIB_DEPRECATED_v339
 {
-  std::vector<ActivityPtr> activities;
-  for (const auto& comm : comms)
-    activities.push_back(boost::dynamic_pointer_cast<Activity>(comm));
-  return Activity::test_any(activities);
+  std::vector<kernel::activity::ActivityImpl*> ractivities(comms.size());
+  std::transform(begin(comms), end(comms), begin(ractivities), [](const CommPtr& act) { return act->pimpl_.get(); });
+
+  kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
+  kernel::actor::ActivityTestanySimcall observer{issuer, ractivities, "test_any"};
+  ssize_t changed_pos = kernel::actor::simcall_answered(
+      [&observer] {
+        return kernel::activity::ActivityImpl::test_any(observer.get_issuer(), observer.get_activities());
+      },
+      &observer);
+  if (changed_pos != -1)
+    comms.at(changed_pos)->complete(State::FINISHED);
+  return changed_pos;
 }
 
 /** @brief Block the calling actor until the communication is finished, or until timeout
@@ -391,11 +433,13 @@ Comm* Comm::wait_for(double timeout)
         return start()->wait_for(timeout); // In the case of host2host comm, do it in two simcalls
       } else if (src_buff_ != nullptr) {
         on_send(*this);
+        on_this_send(*this);
         send(sender_, mailbox_, remains_, rate_, src_buff_, src_buff_size_, match_fun_, copy_data_function_,
              get_data<void>(), timeout);
 
       } else { // Receiver
         on_recv(*this);
+        on_this_recv(*this);
         recv(receiver_, mailbox_, dst_buff_, &dst_buff_size_, match_fun_, copy_data_function_, get_data<void>(),
              timeout, rate_);
       }
@@ -403,7 +447,7 @@ Comm* Comm::wait_for(double timeout)
     case State::STARTED:
       try {
         issuer = kernel::actor::ActorImpl::self();
-        kernel::actor::ActivityWaitSimcall observer{issuer, pimpl_.get(), timeout};
+        kernel::actor::ActivityWaitSimcall observer{issuer, pimpl_.get(), timeout, "Wait"};
         if (kernel::actor::simcall_blocking(
                 [&observer] { observer.get_activity()->wait_for(observer.get_issuer(), observer.get_timeout()); },
                 &observer)) {
@@ -426,55 +470,60 @@ Comm* Comm::wait_for(double timeout)
   return this;
 }
 
-ssize_t Comm::wait_any_for(const std::vector<CommPtr>& comms, double timeout)
+ssize_t Comm::deprecated_wait_any_for(const std::vector<CommPtr>& comms, double timeout) // XBT_ATTRIB_DEPRECATED_v339
 {
-  std::vector<ActivityPtr> activities;
+  if (comms.empty())
+    return -1;
+  ActivitySet set;
   for (const auto& comm : comms)
-    activities.push_back(boost::dynamic_pointer_cast<Activity>(comm));
-  ssize_t changed_pos;
+    set.push(comm);
   try {
-    changed_pos = Activity::wait_any_for(activities, timeout);
+    auto* ret = set.wait_any_for(timeout).get();
+    for (size_t i = 0; i < comms.size(); i++)
+      if (comms[i].get() == ret)
+        return i;
+
+  } catch (TimeoutException& e) {
+    return -1;
   } catch (const NetworkFailureException& e) {
-    changed_pos = -1;
-    for (auto c : comms) {
-      if (c->pimpl_->get_state() == kernel::activity::State::FAILED) {
+    for (auto c : comms)
+      if (c->pimpl_->get_state() == kernel::activity::State::FAILED)
         c->complete(State::FAILED);
-      }
-    }
+
     e.rethrow_nested(XBT_THROW_POINT, boost::core::demangle(typeid(e).name()) + " raised in kernel mode.");
   }
-  return changed_pos;
+  return -1;
 }
 
-void Comm::wait_all(const std::vector<CommPtr>& comms)
+void Comm::wait_all(const std::vector<CommPtr>& comms) // XBT_ATTRIB_DEPRECATED_v339
 {
   // TODO: this should be a simcall or something
-  for (auto& comm : comms)
+  for (const auto& comm : comms)
     comm->wait();
 }
 
-size_t Comm::wait_all_for(const std::vector<CommPtr>& comms, double timeout)
+size_t Comm::wait_all_for(const std::vector<CommPtr>& comms, double timeout) // XBT_ATTRIB_DEPRECATED_v339
 {
   if (timeout < 0.0) {
-    wait_all(comms);
+    for (const auto& comm : comms)
+      comm->wait();
     return comms.size();
   }
 
-  double deadline = Engine::get_clock() + timeout;
-  std::vector<CommPtr> waited_comm(1, nullptr);
-  for (size_t i = 0; i < comms.size(); i++) {
-    double wait_timeout = std::max(0.0, deadline - Engine::get_clock());
-    waited_comm[0]      = comms[i];
-    // Using wait_any_for() here (and not wait_for) because we don't want comms to be invalidated on timeout
-    if (wait_any_for(waited_comm, wait_timeout) == -1) {
-      XBT_DEBUG("Timeout (%g): i = %zu", wait_timeout, i);
-      return i;
-    }
-  }
-  return comms.size();
+  ActivitySet set;
+  for (auto comm : comms)
+    set.push(comm);
+  set.wait_all_for(timeout);
+
+  return set.size();
 }
 } // namespace simgrid::s4u
 /* **************************** Public C interface *************************** */
+int sg_comm_isinstance(sg_activity_t acti)
+{
+  return dynamic_cast<simgrid::s4u::Comm*>(acti) != nullptr;
+}
+
 void sg_comm_detach(sg_comm_t comm, void (*clean_function)(void*))
 {
   comm->detach(clean_function);
@@ -514,35 +563,36 @@ sg_error_t sg_comm_wait_for(sg_comm_t comm, double timeout)
   return status;
 }
 
-void sg_comm_wait_all(sg_comm_t* comms, size_t count)
+void sg_comm_wait_all(sg_comm_t* comms, size_t count) // XBT_ATTRIB_DEPRECATED_v339
 {
-  sg_comm_wait_all_for(comms, count, -1);
+  simgrid::s4u::ActivitySet as;
+  for (size_t i = 0; i < count; i++)
+    as.push(comms[i]);
+
+  as.wait_all();
 }
 
-size_t sg_comm_wait_all_for(sg_comm_t* comms, size_t count, double timeout)
+ssize_t sg_comm_wait_any(sg_comm_t* comms, size_t count) // XBT_ATTRIB_DEPRECATED_v339
 {
   std::vector<simgrid::s4u::CommPtr> s4u_comms;
   for (size_t i = 0; i < count; i++)
     s4u_comms.emplace_back(comms[i], false);
 
-  size_t pos = simgrid::s4u::Comm::wait_all_for(s4u_comms, timeout);
-  for (size_t i = pos; i < count; i++)
-    s4u_comms[i]->add_ref();
+  ssize_t pos = simgrid::s4u::Comm::deprecated_wait_any_for(s4u_comms, -1);
+  for (size_t i = 0; i < count; i++) {
+    if (pos != -1 && static_cast<size_t>(pos) != i)
+      s4u_comms[i]->add_ref();
+  }
   return pos;
 }
 
-ssize_t sg_comm_wait_any(sg_comm_t* comms, size_t count)
-{
-  return sg_comm_wait_any_for(comms, count, -1);
-}
-
-ssize_t sg_comm_wait_any_for(sg_comm_t* comms, size_t count, double timeout)
+ssize_t sg_comm_wait_any_for(sg_comm_t* comms, size_t count, double timeout) // XBT_ATTRIB_DEPRECATED_v339
 {
   std::vector<simgrid::s4u::CommPtr> s4u_comms;
   for (size_t i = 0; i < count; i++)
     s4u_comms.emplace_back(comms[i], false);
 
-  ssize_t pos = simgrid::s4u::Comm::wait_any_for(s4u_comms, timeout);
+  ssize_t pos = simgrid::s4u::Comm::deprecated_wait_any_for(s4u_comms, timeout);
   for (size_t i = 0; i < count; i++) {
     if (pos != -1 && static_cast<size_t>(pos) != i)
       s4u_comms[i]->add_ref();
index db0e182..74ae59b 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "src/kernel/activity/ActivityImpl.hpp"
 #include "src/kernel/activity/ConditionVariableImpl.hpp"
-#include "src/kernel/actor/SimcallObserver.hpp"
+#include "src/kernel/actor/SynchroObserver.hpp"
 
 #include <mutex>
 
@@ -28,7 +28,7 @@ ConditionVariablePtr ConditionVariable::create()
 void ConditionVariable::wait(MutexPtr lock)
 {
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::ConditionWaitSimcall observer{issuer, pimpl_, lock->pimpl_};
+  kernel::actor::ConditionVariableObserver observer{issuer, pimpl_, lock->pimpl_};
   kernel::actor::simcall_blocking(
       [&observer] { observer.get_cond()->wait(observer.get_mutex(), -1.0, observer.get_issuer()); }, &observer);
 }
@@ -36,7 +36,7 @@ void ConditionVariable::wait(MutexPtr lock)
 void ConditionVariable::wait(const std::unique_lock<Mutex>& lock)
 {
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::ConditionWaitSimcall observer{issuer, pimpl_, lock.mutex()->pimpl_};
+  kernel::actor::ConditionVariableObserver observer{issuer, pimpl_, lock.mutex()->pimpl_};
   kernel::actor::simcall_blocking(
       [&observer] { observer.get_cond()->wait(observer.get_mutex(), -1.0, observer.get_issuer()); }, &observer);
 }
@@ -48,7 +48,7 @@ std::cv_status s4u::ConditionVariable::wait_for(const std::unique_lock<Mutex>& l
     timeout = 0.0;
 
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::ConditionWaitSimcall observer{issuer, pimpl_, lock.mutex()->pimpl_, timeout};
+  kernel::actor::ConditionVariableObserver observer{issuer, pimpl_, lock.mutex()->pimpl_, timeout};
   bool timed_out = kernel::actor::simcall_blocking(
       [&observer] { observer.get_cond()->wait(observer.get_mutex(), observer.get_timeout(), observer.get_issuer()); },
       &observer);
index 9e3d59f..c97f72b 100644 (file)
@@ -17,7 +17,7 @@ namespace s4u {
 
 xbt::signal<void(Disk&)> Disk::on_creation;
 xbt::signal<void(Disk const&)> Disk::on_destruction;
-xbt::signal<void(Disk const&)> Disk::on_state_change;
+xbt::signal<void(Disk const&)> Disk::on_onoff;
 
 const std::string& Disk::get_name() const
 {
@@ -112,6 +112,16 @@ Disk* Disk::set_write_bandwidth_profile(kernel::profile::Profile* profile)
                                        [this, profile]() { this->pimpl_->set_write_bandwidth_profile(profile); });
   return this;
 }
+int Disk::get_concurrency_limit() const
+{
+  return pimpl_->get_concurrency_limit();
+}
+
+Disk* Disk::set_concurrency_limit(int limit)
+{
+  kernel::actor::simcall_object_access(pimpl_, [this, limit] { pimpl_->set_concurrency_limit(limit); });
+  return this;
+}
 
 IoPtr Disk::io_init(sg_size_t size, Io::OpType type) const
 {
index a782de7..094e831 100644 (file)
@@ -22,7 +22,7 @@
 #include <algorithm>
 #include <string>
 
-XBT_LOG_NEW_CATEGORY(s4u, "Log channels of the S4U (Simgrid for you) interface");
+XBT_LOG_NEW_CATEGORY(s4u, "Log channels of the S4U (SimGrid for you) interface");
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_engine, s4u, "Logging specific to S4U (engine)");
 
 static simgrid::kernel::actor::ActorCode maestro_code;
@@ -76,7 +76,7 @@ Engine* Engine::get_instance()
 Engine* Engine::get_instance(int* argc, char** argv)
 {
   if (Engine::instance_ == nullptr) {
-    auto e = new Engine(argc, argv);
+    const auto* e = new Engine(argc, argv);
     xbt_assert(Engine::instance_ == e);
   }
   return Engine::instance_;
@@ -86,11 +86,6 @@ const std::vector<std::string>& Engine::get_cmdline() const
   return pimpl_->get_cmdline();
 }
 
-void Engine::shutdown() // XBT_ATTRIB_DEPRECATED_v335
-{
-  delete Engine::instance_;
-}
-
 double Engine::get_clock()
 {
   if (MC_is_active() || MC_record_replay_is_active()) {
@@ -248,13 +243,13 @@ std::string Engine::flatify_platform() const
   ss << "<?xml version='1.0'?>\n";
   ss << "<!DOCTYPE platform SYSTEM \"https://simgrid.org/simgrid.dtd\">\n";
   ss << "<platform version=\"" << version << "\">\n";
-  ss << "<AS id=\"" << get_netzone_root()->get_name() << "\" routing=\"Full\">\n";
+  ss << "<zone id=\"" << get_netzone_root()->get_name() << "\" routing=\"Full\">\n";
 
   flatify_hosts(*this, ss);
   flatify_links(*this, ss);
   flatify_routes(*this, ss);
 
-  ss << "</AS>\n";
+  ss << "</zone>\n";
   ss << "</platform>\n";
   return ss.str();
 }
@@ -405,6 +400,20 @@ Mailbox* Engine::mailbox_by_name_or_create(const std::string& name) const
   return mbox->get_iface();
 }
 
+MessageQueue* Engine::message_queue_by_name_or_create(const std::string& name) const
+{
+  /* two actors may have pushed the same mbox_create simcall at the same time */
+  kernel::activity::MessageQueueImpl* queue = kernel::actor::simcall_answered([&name, this] {
+    auto [m, inserted] = pimpl_->mqueues_.try_emplace(name, nullptr);
+    if (inserted) {
+      m->second = new kernel::activity::MessageQueueImpl(name);
+      XBT_DEBUG("Creating a message queue at %p with name %s", m->second, name.c_str());
+    }
+    return m->second;
+  });
+  return queue->get_iface();
+}
+
 /** @brief Returns the amount of links in the platform */
 size_t Engine::get_link_count() const
 {
@@ -525,7 +534,7 @@ kernel::routing::NetPoint* Engine::netpoint_by_name_or_null(const std::string& n
 
 kernel::routing::NetPoint* Engine::netpoint_by_name(const std::string& name) const
 {
-  auto netp = netpoint_by_name_or_null(name);
+  auto* netp = netpoint_by_name_or_null(name);
   if (netp == nullptr) {
     throw std::invalid_argument("Netpoint not found: " + name);
   }
index 3a87ef2..caa7466 100644 (file)
@@ -6,6 +6,7 @@
 #include "simgrid/simix.hpp"
 #include <simgrid/Exception.hpp>
 #include <simgrid/exec.h>
+#include <simgrid/s4u/ActivitySet.hpp>
 #include <simgrid/s4u/Exec.hpp>
 #include <simgrid/s4u/Host.hpp>
 
@@ -16,7 +17,6 @@
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_exec, s4u_activity, "S4U asynchronous executions");
 
 namespace simgrid::s4u {
-xbt::signal<void(Exec const&)> Exec::on_start;
 
 Exec::Exec(kernel::activity::ExecImplPtr pimpl)
 {
@@ -47,16 +47,28 @@ Exec* Exec::do_start()
     pimpl_->suspend();
 
   state_      = State::STARTED;
-  on_start(*this);
+  fire_on_start();
+  fire_on_this_start();
   return this;
 }
 
-ssize_t Exec::wait_any_for(const std::vector<ExecPtr>& execs, double timeout)
+ssize_t Exec::deprecated_wait_any_for(const std::vector<ExecPtr>& execs, double timeout) // XBT_ATTRIB_DEPRECATED_v339
 {
-  std::vector<ActivityPtr> activities;
+  if (execs.empty())
+    return -1;
+  ActivitySet set;
   for (const auto& exec : execs)
-    activities.push_back(boost::dynamic_pointer_cast<Activity>(exec));
-  return Activity::wait_any_for(activities, timeout);
+    set.push(exec);
+  try {
+    auto* ret = set.wait_any_for(timeout).get();
+    for (size_t i = 0; i < execs.size(); i++)
+      if (execs[i].get() == ret)
+        return i;
+
+  } catch (TimeoutException& e) {
+    return -1;
+  }
+  return -1;
 }
 
 /** @brief change the execution bound
@@ -247,6 +259,11 @@ bool Exec::is_assigned() const
 } // namespace simgrid::s4u
 
 /* **************************** Public C interface *************************** */
+int sg_exec_isinstance(sg_activity_t acti)
+{
+  return dynamic_cast<simgrid::s4u::Exec*>(acti) != nullptr;
+}
+
 void sg_exec_set_bound(sg_exec_t exec, double bound)
 {
   exec->set_bound(bound);
@@ -319,18 +336,27 @@ sg_error_t sg_exec_wait_for(sg_exec_t exec, double timeout)
   return status;
 }
 
-ssize_t sg_exec_wait_any(sg_exec_t* execs, size_t count)
+ssize_t sg_exec_wait_any(sg_exec_t* execs, size_t count) // XBT_ATTRIB_DEPRECATED_v339
 {
-  return sg_exec_wait_any_for(execs, count, -1.0);
+  std::vector<simgrid::s4u::ExecPtr> s4u_execs;
+  for (size_t i = 0; i < count; i++)
+    s4u_execs.emplace_back(execs[i], false);
+
+  ssize_t pos = simgrid::s4u::Exec::deprecated_wait_any_for(s4u_execs, -1.0);
+  for (size_t i = 0; i < count; i++) {
+    if (pos != -1 && static_cast<size_t>(pos) != i)
+      s4u_execs[i]->add_ref();
+  }
+  return pos;
 }
 
-ssize_t sg_exec_wait_any_for(sg_exec_t* execs, size_t count, double timeout)
+ssize_t sg_exec_wait_any_for(sg_exec_t* execs, size_t count, double timeout) // XBT_ATTRIB_DEPRECATED_v339
 {
   std::vector<simgrid::s4u::ExecPtr> s4u_execs;
   for (size_t i = 0; i < count; i++)
     s4u_execs.emplace_back(execs[i], false);
 
-  ssize_t pos = simgrid::s4u::Exec::wait_any_for(s4u_execs, timeout);
+  ssize_t pos = simgrid::s4u::Exec::deprecated_wait_any_for(s4u_execs, timeout);
   for (size_t i = 0; i < count; i++) {
     if (pos != -1 && static_cast<size_t>(pos) != i)
       s4u_execs[i]->add_ref();
index ba4a844..670882c 100644 (file)
@@ -32,8 +32,9 @@ namespace s4u {
 #ifndef DOXYGEN
 xbt::signal<void(Host&)> Host::on_creation;
 xbt::signal<void(Host const&)> Host::on_destruction;
-xbt::signal<void(Host const&)> Host::on_state_change;
+xbt::signal<void(Host const&)> Host::on_onoff;
 xbt::signal<void(Host const&)> Host::on_speed_change;
+xbt::signal<void(kernel::resource::CpuAction&, kernel::resource::Action::State)> Host::on_exec_state_change;
 #endif
 
 Host* Host::set_cpu(kernel::resource::CpuImpl* cpu)
@@ -101,7 +102,8 @@ void Host::turn_on()
     kernel::actor::simcall_answered([this] {
       this->pimpl_cpu_->turn_on();
       this->pimpl_->turn_on();
-      on_state_change(*this);
+      on_onoff(*this);
+      on_this_onoff(*this);
     });
   }
 }
@@ -115,7 +117,8 @@ void Host::turn_off()
       this->pimpl_cpu_->turn_off();
       this->pimpl_->turn_off(self);
 
-      on_state_change(*this);
+      on_onoff(*this);
+      on_this_onoff(*this);
     });
   }
 }
@@ -164,6 +167,16 @@ void Host::route_to(const Host* dest, std::vector<Link*>& links, double* latency
   for (auto* l : linkImpls)
     links.push_back(l->get_iface());
 }
+std::pair<std::vector<Link*>, double> Host::route_to(const Host* dest) const
+{
+  std::vector<kernel::resource::StandardLinkImpl*> linkImpls;
+  std::vector<Link*> links;
+  double latency = 0;
+  this->route_to(dest, linkImpls, &latency);
+  for (auto* l : linkImpls)
+    links.push_back(l->get_iface());
+  return std::make_pair(links, latency);
+}
 
 /** @brief Just like Host::routeTo, but filling an array of link implementations */
 void Host::route_to(const Host* dest, std::vector<kernel::resource::StandardLinkImpl*>& links, double* latency) const
@@ -207,6 +220,17 @@ Host* Host::set_properties(const std::unordered_map<std::string, std::string>& p
   return this;
 }
 
+int Host::get_concurrency_limit() const
+{
+  return pimpl_cpu_->get_concurrency_limit();
+}
+
+Host* Host::set_concurrency_limit(int limit)
+{
+  kernel::actor::simcall_object_access(pimpl_cpu_, [this, limit] { pimpl_cpu_->set_concurrency_limit(limit); });
+  return this;
+}
+
 /** Specify a profile turning the host on and off according to an exhaustive list or a stochastic law.
  * The profile must contain boolean values. */
 Host* Host::set_state_profile(kernel::profile::Profile* p)
@@ -396,7 +420,7 @@ void Host::execute(double flops) const
 
 void Host::execute(double flops, double priority) const
 {
-  this_actor::exec_init(flops)->set_priority(1 / priority)->start()->wait();
+  Exec::init()->set_flops_amount(flops)->set_host(const_cast<Host*>(this))->set_priority(1 / priority)->wait();
 }
 
 Host* Host::seal()
@@ -657,22 +681,6 @@ void sg_host_sendto(sg_host_t from, sg_host_t to, double byte_amount)
   simgrid::s4u::Comm::sendto(from, to, byte_amount);
 }
 
-/** @brief Displays debugging information about a host */
-void sg_host_dump(const_sg_host_t host) // XBT_ATTRIB_DEPRECATED_v335
-{
-  XBT_INFO("Displaying host %s", host->get_cname());
-  XBT_INFO("  - speed: %.0f", host->get_speed());
-  XBT_INFO("  - available speed: %.2f", sg_host_get_available_speed(host));
-  const std::unordered_map<std::string, std::string>* props = host->get_properties();
-
-  if (not props->empty()) {
-    XBT_INFO("  - properties:");
-    for (auto const& [key, value] : *props) {
-      XBT_INFO("    %s->%s", key.c_str(), value.c_str());
-    }
-  }
-}
-
 /** @brief Return the list of actors attached to a host.
  *
  * @param host a host
index 191abc1..c20e891 100644 (file)
@@ -3,6 +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 <simgrid/s4u/ActivitySet.hpp>
 #include <simgrid/s4u/Disk.hpp>
 #include <simgrid/s4u/Io.hpp>
 #include <xbt/log.h>
@@ -14,7 +15,6 @@
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_io, s4u_activity, "S4U asynchronous I/Os");
 
 namespace simgrid::s4u {
-xbt::signal<void(Io const&)> Io::on_start;
 
 Io::Io(kernel::activity::IoImplPtr pimpl)
 {
@@ -90,16 +90,23 @@ Io* Io::do_start()
     pimpl_->suspend();
 
   state_ = State::STARTED;
-  on_start(*this);
+  fire_on_start();
+  fire_on_this_start();
   return this;
 }
 
-ssize_t Io::wait_any_for(const std::vector<IoPtr>& ios, double timeout)
+ssize_t Io::deprecated_wait_any_for(const std::vector<IoPtr>& ios, double timeout) // XBT_ATTRIB_DEPRECATED_v339
 {
-  std::vector<ActivityPtr> activities;
+  ActivitySet set;
   for (const auto& io : ios)
-    activities.push_back(boost::dynamic_pointer_cast<Activity>(io));
-  return Activity::wait_any_for(activities, timeout);
+    set.push(io);
+
+  auto* ret = set.wait_any_for(timeout).get();
+  for (size_t i = 0; i < ios.size(); i++)
+    if (ios[i].get() == ret)
+      return i;
+
+  return -1;
 }
 
 IoPtr Io::set_disk(const_sg_disk_t disk)
index 8d41270..0a42518 100644 (file)
@@ -22,7 +22,7 @@ namespace s4u {
 
 xbt::signal<void(Link&)> Link::on_creation;
 xbt::signal<void(Link const&)> Link::on_destruction;
-xbt::signal<void(Link const&)> Link::on_state_change;
+xbt::signal<void(Link const&)> Link::on_onoff;
 xbt::signal<void(Link const&)> Link::on_bandwidth_change;
 xbt::signal<void(kernel::resource::NetworkAction&, kernel::resource::Action::State)>
     Link::on_communication_state_change;
@@ -130,9 +130,9 @@ Link* Link::set_concurrency_limit(int limit)
   return this;
 }
 
-double Link::get_usage() const
+double Link::get_load() const
 {
-  return this->pimpl_->get_constraint()->get_usage();
+  return this->pimpl_->get_constraint()->get_load();
 }
 
 void Link::turn_on()
index 6ce4a03..76613fb 100644 (file)
@@ -127,6 +127,13 @@ CommPtr Mailbox::get_init()
   return res;
 }
 
+CommPtr Mailbox::get_async()
+{
+  CommPtr res = get_init()->set_dst_data(nullptr, sizeof(void*));
+  res->start();
+  return res;
+}
+
 kernel::activity::ActivityImplPtr
 Mailbox::iprobe(int type, const std::function<bool(void*, void*, kernel::activity::CommImpl*)>& match_fun, void* data)
 {
diff --git a/src/s4u/s4u_Mess.cpp b/src/s4u/s4u_Mess.cpp
new file mode 100644 (file)
index 0000000..0a8da79
--- /dev/null
@@ -0,0 +1,153 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <cmath>
+#include <simgrid/Exception.hpp>
+#include <simgrid/s4u/ActivitySet.hpp>
+#include <simgrid/s4u/Mess.hpp>
+#include <simgrid/s4u/Engine.hpp>
+#include <simgrid/s4u/MessageQueue.hpp>
+
+#include "src/kernel/activity/MessImpl.hpp"
+#include "src/kernel/actor/ActorImpl.hpp"
+#include "src/kernel/actor/SimcallObserver.hpp"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_mess, s4u_activity, "S4U asynchronous messaging");
+
+namespace simgrid::s4u {
+xbt::signal<void(Mess const&)> Mess::on_send;
+xbt::signal<void(Mess const&)> Mess::on_recv;
+
+MessPtr Mess::set_queue(MessageQueue* queue)
+{
+  queue_ = queue;
+  return this;
+}
+
+MessPtr Mess::set_payload(void* payload)
+{
+  payload_ = payload;
+  return this;
+}
+
+MessPtr Mess::set_dst_data(void** buff, size_t size)
+{
+  xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)",
+             __func__);
+
+  dst_buff_      = buff;
+  dst_buff_size_ = size;
+  return this;
+}
+
+Actor* Mess::get_sender() const
+{
+  kernel::actor::ActorImplPtr sender = nullptr;
+  if (pimpl_)
+    sender = boost::static_pointer_cast<kernel::activity::MessImpl>(pimpl_)->src_actor_;
+  return sender ? sender->get_ciface() : nullptr;
+}
+
+Actor* Mess::get_receiver() const
+{
+  kernel::actor::ActorImplPtr receiver = nullptr;
+  if (pimpl_)
+    receiver = boost::static_pointer_cast<kernel::activity::MessImpl>(pimpl_)->dst_actor_;
+  return receiver ? receiver->get_ciface() : nullptr;
+}
+
+Mess* Mess::do_start()
+{
+  xbt_assert(get_state() == State::INITED || get_state() == State::STARTING,
+             "You cannot use %s() once your message exchange has started (not implemented)", __func__);
+
+  auto myself = kernel::actor::ActorImpl::self();
+  if (myself == sender_) {
+    on_send(*this);
+    on_this_send(*this);
+    kernel::actor::MessIputSimcall observer{sender_, queue_->get_impl(), get_payload()};
+    pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::MessImpl::iput(&observer); },
+                                             &observer);
+  } else if (myself == receiver_) {
+    on_recv(*this);
+    on_this_recv(*this);
+    kernel::actor::MessIgetSimcall observer{receiver_,
+                                            queue_->get_impl(),
+                                            static_cast<unsigned char*>(dst_buff_),
+                                            &dst_buff_size_,
+                                            get_payload()};
+    pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::MessImpl::iget(&observer); },
+                                             &observer);
+  } else {
+    xbt_die("Cannot start a message exchange before specifying whether we are the sender or the receiver");
+  }
+
+  pimpl_->set_iface(this);
+  pimpl_->set_actor(sender_);
+  // Only throw the signal when both sides are here and the status is READY
+  if (pimpl_->get_state() != kernel::activity::State::WAITING) {
+    fire_on_start();
+    fire_on_this_start();
+  }
+  state_ = State::STARTED;
+  return this;
+}
+
+Mess* Mess::wait_for(double timeout)
+{
+  XBT_DEBUG("Calling Mess::wait_for with state %s", get_state_str());
+  kernel::actor::ActorImpl* issuer = nullptr;
+  switch (state_) {
+    case State::FINISHED:
+      break;
+    case State::FAILED:
+      throw NetworkFailureException(XBT_THROW_POINT, "Cannot wait for a failed communication");
+    case State::INITED:
+    case State::STARTING:
+      if (get_payload() != nullptr) {
+        on_send(*this);
+        on_this_send(*this);
+        kernel::actor::MessIputSimcall observer{sender_, queue_->get_impl(), get_payload()};
+        pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::MessImpl::iput(&observer); },
+                                                 &observer);
+      } else { // Receiver
+        on_recv(*this);
+        on_this_recv(*this);
+        kernel::actor::MessIgetSimcall observer{receiver_,
+                                                queue_->get_impl(),
+                                                static_cast<unsigned char*>(dst_buff_),
+                                                &dst_buff_size_,
+                                                get_payload()};
+        pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::MessImpl::iget(&observer); },
+                                                 &observer);
+      }
+      break;
+    case State::STARTED:
+      try {
+        issuer = kernel::actor::ActorImpl::self();
+        kernel::actor::ActivityWaitSimcall observer{issuer, pimpl_.get(), timeout, "Wait"};
+        if (kernel::actor::simcall_blocking(
+                [&observer] { observer.get_activity()->wait_for(observer.get_issuer(), observer.get_timeout()); },
+                &observer)) {
+          throw TimeoutException(XBT_THROW_POINT, "Timeouted");
+        }
+      } catch (const NetworkFailureException& e) {
+        issuer->simcall_.observer_ = nullptr; // Comm failed on network failure, reset the observer to nullptr
+        complete(State::FAILED);
+        e.rethrow_nested(XBT_THROW_POINT, boost::core::demangle(typeid(e).name()) + " raised in kernel mode.");
+      }
+      break;
+
+    case State::CANCELED:
+      throw CancelException(XBT_THROW_POINT, "Message canceled");
+
+    default:
+      THROW_IMPOSSIBLE;
+  }
+  complete(State::FINISHED);
+  return this;
+}
+
+} // namespace simgrid::s4u
diff --git a/src/s4u/s4u_MessageQueue.cpp b/src/s4u/s4u_MessageQueue.cpp
new file mode 100644 (file)
index 0000000..8fe34ac
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright (c) 2023. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <simgrid/s4u/Engine.hpp>
+#include <simgrid/s4u/Mess.hpp>
+#include <simgrid/s4u/MessageQueue.hpp>
+
+#include "src/kernel/activity/MessageQueueImpl.hpp"
+
+XBT_LOG_EXTERNAL_CATEGORY(s4u);
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_mqueue, s4u, "S4U Message Queues");
+
+namespace simgrid::s4u {
+
+const std::string& MessageQueue::get_name() const
+{
+  return pimpl_->get_name();
+}
+
+const char* MessageQueue::get_cname() const
+{
+  return pimpl_->get_cname();
+}
+
+MessageQueue* MessageQueue::by_name(const std::string& name)
+{
+  return Engine::get_instance()->message_queue_by_name_or_create(name);
+}
+
+bool MessageQueue::empty() const
+{
+  return pimpl_->empty();
+}
+
+size_t MessageQueue::size() const
+{
+  return pimpl_->size();
+}
+
+kernel::activity::MessImplPtr MessageQueue::front() const
+{
+  return pimpl_->empty() ? nullptr : pimpl_->front();
+}
+
+MessPtr MessageQueue::put_init()
+{
+  MessPtr res(new Mess());
+  res->set_queue(this);
+  res->sender_ = kernel::actor::ActorImpl::self();
+  return res;
+}
+
+MessPtr MessageQueue::put_init(void* payload)
+{
+  return put_init()->set_payload(payload);
+}
+
+MessPtr MessageQueue::put_async(void* payload)
+{
+  xbt_assert(payload != nullptr, "You cannot send nullptr");
+  MessPtr res = put_init(payload);
+  res->start();
+  return res;
+}
+
+void MessageQueue::put(void* payload)
+{
+  xbt_assert(payload != nullptr, "You cannot send nullptr");
+
+  put_async(payload)->wait();
+}
+
+/** Blocking send with timeout */
+void MessageQueue::put(void* payload, double timeout)
+{
+  xbt_assert(payload != nullptr, "You cannot send nullptr");
+
+  put_init()->set_payload(payload)->start()->wait_for(timeout);
+}
+
+MessPtr MessageQueue::get_init()
+{
+  MessPtr res(new Mess());
+  res->set_queue(this);
+  res->receiver_ = kernel::actor::ActorImpl::self();
+  return res;
+}
+
+MessPtr MessageQueue::get_async()
+{
+  MessPtr res = get_init()->set_payload(nullptr);
+  res->start();
+  return res;
+}
+
+} // namespace simgrid::s4u
index 051f11c..72c2481 100644 (file)
@@ -55,10 +55,18 @@ bool Mutex::try_lock()
  *
  * See @ref s4u_raii.
  */
-MutexPtr Mutex::create()
+MutexPtr Mutex::create(bool recursive)
 {
-  auto* mutex = new kernel::activity::MutexImpl();
-  return MutexPtr(&mutex->mutex(), false);
+  auto* mutex = new kernel::activity::MutexImpl(recursive);
+  return MutexPtr(&mutex->get_iface(), false);
+}
+
+Actor* Mutex::get_owner()
+{
+  auto* owner = pimpl_->get_owner();
+  if (owner == nullptr)
+    return nullptr;
+  return owner->get_ciface();
 }
 
 /* refcounting of the intrusive_ptr is delegated to the implementation object */
index 356524b..b62e620 100644 (file)
@@ -39,7 +39,7 @@ void NetZone::set_property(const std::string& key, const std::string& value)
 std::vector<NetZone*> NetZone::get_children() const
 {
   std::vector<NetZone*> res;
-  for (auto child : pimpl_->get_children())
+  for (auto* child : pimpl_->get_children())
     res.push_back(child->get_iface());
   return res;
 }
@@ -85,13 +85,71 @@ unsigned long NetZone::add_component(kernel::routing::NetPoint* elm)
   return pimpl_->add_component(elm);
 }
 
+void NetZone::add_route(const NetZone* src, const NetZone* dst, const std::vector<const Link*>& links)
+{
+  std::vector<LinkInRoute> links_direct;
+  std::vector<LinkInRoute> links_reverse;
+  for (auto* l : links) {
+    links_direct.emplace_back(LinkInRoute(l, LinkInRoute::Direction::UP));
+    links_reverse.emplace_back(LinkInRoute(l, LinkInRoute::Direction::DOWN));
+  }
+  pimpl_->add_route(src ? src->get_netpoint() : nullptr, dst ? dst->get_netpoint(): nullptr,
+                    src ? src->get_gateway() : nullptr, dst ? dst->get_gateway() : nullptr,
+                    links_direct, false);
+  pimpl_->add_route(dst ? dst->get_netpoint(): nullptr, src ? src->get_netpoint() : nullptr,
+                    dst ? dst->get_gateway() : nullptr, src ? src->get_gateway() : nullptr,
+                    links_reverse, false);
+}
+
+void NetZone::add_route(const NetZone* src, const NetZone* dst, const std::vector<LinkInRoute>& link_list, bool symmetrical)
+{
+  pimpl_->add_route(src ? src->get_netpoint() : nullptr, dst ? dst->get_netpoint(): nullptr,
+                    src ? src->get_gateway() : nullptr, dst ? dst->get_gateway() : nullptr,
+                    link_list, symmetrical);
+}
+
 void NetZone::add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                         kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
-                        const std::vector<LinkInRoute>& link_list, bool symmetrical)
+                        const std::vector<LinkInRoute>& link_list, bool symmetrical) // XBT_ATTRIB_DEPRECATED_v339
 {
   pimpl_->add_route(src, dst, gw_src, gw_dst, link_list, symmetrical);
 }
 
+void NetZone::add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
+                        kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
+                        const std::vector<const Link*>& links) // XBT_ATTRIB_DEPRECATED_v339
+{
+  std::vector<LinkInRoute> links_direct;
+  std::vector<LinkInRoute> links_reverse;
+  for (auto* l : links) {
+    links_direct.emplace_back(LinkInRoute(l, LinkInRoute::Direction::UP));
+    links_reverse.emplace_back(LinkInRoute(l, LinkInRoute::Direction::DOWN));
+  }
+  pimpl_->add_route(src, dst, gw_src, gw_dst, links_direct, false);
+  pimpl_->add_route(dst, src, gw_dst, gw_src, links_reverse, false);
+}
+
+void NetZone::add_route(const Host* src, const Host* dst, const std::vector<LinkInRoute>& link_list, bool symmetrical)
+{
+  pimpl_->add_route(src ? src->get_netpoint(): nullptr, dst ? dst->get_netpoint(): nullptr, nullptr, nullptr,
+                    link_list, symmetrical);
+
+}
+
+void NetZone::add_route(const Host* src, const Host* dst, const std::vector<const Link*>& links)
+{
+  std::vector<LinkInRoute> links_direct;
+  std::vector<LinkInRoute> links_reverse;
+  for (auto* l : links) {
+    links_direct.emplace_back(LinkInRoute(l, LinkInRoute::Direction::UP));
+    links_reverse.emplace_back(LinkInRoute(l, LinkInRoute::Direction::DOWN));
+  }
+  pimpl_->add_route(src ? src->get_netpoint(): nullptr, dst ? dst->get_netpoint(): nullptr, nullptr, nullptr,
+                    links_direct, false);
+  pimpl_->add_route(dst ? dst->get_netpoint(): nullptr, src ? src->get_netpoint(): nullptr, nullptr, nullptr,
+                    links_reverse, false);
+}
+
 void NetZone::add_bypass_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                                kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
                                const std::vector<LinkInRoute>& link_list)
@@ -202,11 +260,31 @@ kernel::routing::NetPoint* NetZone::create_router(const std::string& name)
   return kernel::actor::simcall_answered([this, &name] { return pimpl_->create_router(name); });
 }
 
-kernel::routing::NetPoint* NetZone::get_netpoint()
+kernel::routing::NetPoint* NetZone::get_netpoint() const
 {
   return pimpl_->get_netpoint();
 }
 
+kernel::routing::NetPoint* NetZone::get_gateway() const
+{
+  return pimpl_->get_gateway();
+}
+
+kernel::routing::NetPoint* NetZone::get_gateway(const std::string& name) const
+{
+  return pimpl_->get_gateway(name);
+}
+
+void NetZone::set_gateway(kernel::routing::NetPoint* router)
+{
+  set_gateway("default", router);
+}
+
+void NetZone::set_gateway(const std::string& name, kernel::routing::NetPoint* router)
+{
+  kernel::actor::simcall_answered([this, name, router] { pimpl_->set_gateway(name, router); });
+}
+
 kernel::resource::NetworkModel* NetZone::get_network_model() const
 {
   return pimpl_->get_network_model().get();
diff --git a/src/s4u/s4u_Task.cpp b/src/s4u/s4u_Task.cpp
new file mode 100644 (file)
index 0000000..bcc2f4e
--- /dev/null
@@ -0,0 +1,530 @@
+#include <cstddef>
+#include <memory>
+#include <simgrid/Exception.hpp>
+#include <simgrid/s4u/Activity.hpp>
+#include <simgrid/s4u/Comm.hpp>
+#include <simgrid/s4u/Disk.hpp>
+#include <simgrid/s4u/Exec.hpp>
+#include <simgrid/s4u/Io.hpp>
+#include <simgrid/s4u/Task.hpp>
+#include <simgrid/simix.hpp>
+#include <string>
+#include <xbt/asserts.h>
+
+#include "src/simgrid/module.hpp"
+
+SIMGRID_REGISTER_PLUGIN(task, "Battery management", nullptr)
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Task, kernel, "Logging specific to the task plugin");
+
+namespace simgrid::s4u {
+
+Task::Task(const std::string& name) : name_(name) {}
+
+/** @param instance The Task instance to check.
+ *  @brief Return True if this Task instance can start.
+ */
+bool Task::ready_to_run(std::string instance)
+{
+  return running_instances_[instance] < parallelism_degree_[instance] && queued_firings_[instance] > 0;
+}
+
+/** @param source The sender.
+ *  @brief Receive a token from another Task.
+ *  @note Check upon reception if the Task has received a token from each of its predecessors,
+ * and in this case consumes those tokens and enqueue an execution.
+ */
+void Task::receive(Task* source)
+{
+  XBT_DEBUG("Task %s received a token from %s", name_.c_str(), source->name_.c_str());
+  predecessors_[source]++;
+  if (source->token_ != nullptr)
+    tokens_received_[source].push_back(source->token_);
+  bool enough_tokens = true;
+  for (auto const& [key, val] : predecessors_)
+    if (val < 1) {
+      enough_tokens = false;
+      break;
+    }
+  if (enough_tokens) {
+    for (auto& [key, val] : predecessors_)
+      val--;
+    enqueue_firings(1);
+  }
+}
+
+/** @param instance The Taks instance to complete.
+ *  @brief Task instance routine when finishing an execution of an instance.
+ *  @note The dispatcher instance enqueues a firing for the next instance.
+ *        The collector instance triggers the on_completion signals and sends tokens to successors.
+ *        Others instances enqueue a firing of the collector instance.
+ */
+void Task::complete(std::string instance)
+{
+  xbt_assert(Actor::is_maestro());
+  running_instances_[instance]--;
+  count_[instance]++;
+  if (instance == "collector") {
+    on_this_completion(this);
+    on_completion(this);
+    for (auto const& t : successors_)
+      t->receive(this);
+  } else if (instance == "dispatcher") {
+    auto next_instance = load_balancing_function_();
+    xbt_assert(next_instance != "dispatcher" and next_instance != "collector", "Invalid instance selected: %s",
+               next_instance.c_str());
+    queued_firings_[next_instance] = queued_firings_.at(next_instance) + 1;
+    while (ready_to_run(next_instance))
+      fire(next_instance);
+  } else {
+    queued_firings_["collector"]++;
+    while (ready_to_run("collector"))
+      fire("collector");
+  }
+  if (ready_to_run(instance))
+    fire(instance);
+}
+
+/** @param n The new parallelism degree of the Task instance.
+ *  @param instance The Task instance to modify.
+ *  @note You can use instance "all" to modify the parallelism degree of all instances of this Task.
+ *        When increasing the degree new executions are started if there is queued firings.
+ *        When decreasing the degree instances already running are NOT stopped.
+ */
+void Task::set_parallelism_degree(int n, std::string instance)
+{
+  xbt_assert(n > 0, "Parallelism degree must be above 0.");
+  simgrid::kernel::actor::simcall_answered([this, n, &instance] {
+    if (instance == "all") {
+      for (auto& [key, value] : parallelism_degree_) {
+        parallelism_degree_[key] = n;
+        while (ready_to_run(key))
+          fire(key);
+      }
+    } else {
+      parallelism_degree_[instance] = n;
+      while (ready_to_run(instance))
+        fire(instance);
+    }
+  });
+}
+
+/** @param bytes The internal bytes of the Task instance.
+ *  @param instance The Task instance to modify.
+ *  @note Internal bytes are used for Comms between the dispatcher and instance_n,
+ *        and between instance_n and the collector if they are not on the same host.
+ */
+void Task::set_internal_bytes(int bytes, std::string instance)
+{
+  simgrid::kernel::actor::simcall_answered([this, bytes, &instance] { internal_bytes_to_send_[instance] = bytes; });
+}
+
+/** @param func The load balancing function.
+ *  @note The dispatcher uses this function to determine which instance to trigger next.
+ */
+void Task::set_load_balancing_function(std::function<std::string()> func)
+{
+  simgrid::kernel::actor::simcall_answered([this, func] { load_balancing_function_ = func; });
+}
+
+/** @param n The number of firings to enqueue.
+ */
+void Task::enqueue_firings(int n)
+{
+  simgrid::kernel::actor::simcall_answered([this, n] {
+    queued_firings_["dispatcher"] += n;
+    while (ready_to_run("dispatcher"))
+      fire("dispatcher");
+  });
+}
+
+/** @param name The new name to set.
+ *  @brief Set the name of the Task.
+ */
+void Task::set_name(std::string name)
+{
+  name_ = name;
+}
+
+/** @param amount The amount to set.
+ *  @param instance The Task instance to modify.
+ *  @note Amount in flop for ExecTask and in bytes for CommTask.
+ */
+void Task::set_amount(double amount, std::string instance)
+{
+  simgrid::kernel::actor::simcall_answered([this, amount, &instance] { amount_[instance] = amount; });
+}
+
+/** @param token The token to set.
+ *  @brief Set the token to send to successors.
+ *  @note The token is passed to each successor after the Task instance collector end, i.e., after the on_completion
+ * callback.
+ */
+void Task::set_token(std::shared_ptr<Token> token)
+{
+  simgrid::kernel::actor::simcall_answered([this, token] { token_ = token; });
+}
+
+/** @param t The Task to deque a token from.
+ */
+void Task::deque_token_from(TaskPtr t)
+{
+  simgrid::kernel::actor::simcall_answered([this, &t] { tokens_received_[t].pop_front(); });
+}
+
+void Task::fire(std::string instance)
+{
+  if ((int)current_activities_[instance].size() > parallelism_degree_[instance]) {
+    current_activities_[instance].pop_front();
+  }
+  if (instance != "dispatcher" and instance != "collector") {
+    on_this_start(this);
+    on_start(this);
+  }
+  running_instances_[instance]++;
+  queued_firings_[instance] = std::max(queued_firings_[instance] - 1, 0);
+}
+
+/** @param successor The Task to add as a successor.
+ *  @note It also adds this as a predecessor of successor.
+ */
+void Task::add_successor(TaskPtr successor)
+{
+  simgrid::kernel::actor::simcall_answered([this, successor_p = successor.get()] {
+    successors_.insert(successor_p);
+    successor_p->predecessors_.try_emplace(this, 0);
+  });
+}
+
+/** @param successor The Task to remove from the successors of this Task.
+ *  @note It also remove this from the predecessors of successor.
+ */
+void Task::remove_successor(TaskPtr successor)
+{
+  simgrid::kernel::actor::simcall_answered([this, successor_p = successor.get()] {
+    successor_p->predecessors_.erase(this);
+    successors_.erase(successor_p);
+  });
+}
+
+/** @brief Remove all successors from this Task.
+ */
+void Task::remove_all_successors()
+{
+  simgrid::kernel::actor::simcall_answered([this] {
+    while (not successors_.empty()) {
+      auto* successor = *(successors_.begin());
+      successor->predecessors_.erase(this);
+      successors_.erase(successor);
+    }
+  });
+}
+
+/** @param n The number of instances to add to this Task (>=0).
+ *  @note Instances goes always from instance_0 to instance_x,
+ *        where x is the current number of instance.
+ */
+void Task::add_instances(int n)
+{
+  xbt_assert(n >= 0, "Cannot add a negative number of instances (provided: %d)", n);
+  int instance_count = (int)amount_.size() - 2;
+  for (int i = instance_count; i < n + instance_count; i++) {
+    amount_["instance_" + std::to_string(i)]                 = amount_.at("instance_0");
+    queued_firings_["instance_" + std::to_string(i)]         = 0;
+    running_instances_["instance_" + std::to_string(i)]      = 0;
+    count_["instance_" + std::to_string(i)]                  = 0;
+    parallelism_degree_["instance_" + std::to_string(i)]     = parallelism_degree_.at("instance_0");
+    current_activities_["instance_" + std::to_string(i)]     = {};
+    internal_bytes_to_send_["instance_" + std::to_string(i)] = internal_bytes_to_send_.at("instance_0");
+    ;
+  }
+}
+
+/** @param n The number of instances to remove from this Task (>=0).
+ *  @note Instances goes always from instance_0 to instance_x,
+ *        where x is the current number of instance.
+ *        Running instances cannot be removed.
+ */
+void Task::remove_instances(int n)
+{
+  int instance_count = (int)amount_.size() - 2;
+  xbt_assert(n >= 0, "Cannot remove a negative number of instances (provided: %d)", n);
+  xbt_assert(instance_count - n > 0, "The number of instances must be above 0 (instances: %d, provided: %d)",
+             instance_count, n);
+  for (int i = instance_count - 1; i >= instance_count - n; i--) {
+    xbt_assert(running_instances_.at("instance_" + std::to_string(i)) == 0,
+               "Cannot remove a running instance (instances: %d)", i);
+    amount_.erase("instance_" + std::to_string(i));
+    queued_firings_.erase("instance_" + std::to_string(i));
+    running_instances_.erase("instance_" + std::to_string(i));
+    count_.erase("instance_" + std::to_string(i));
+    parallelism_degree_.erase("instance_" + std::to_string(i));
+    current_activities_.erase("instance_" + std::to_string(i));
+  }
+}
+
+/**
+ *  @brief Default constructor.
+ */
+ExecTask::ExecTask(const std::string& name) : Task(name)
+{
+  set_load_balancing_function([]() { return "instance_0"; });
+}
+
+/**
+ *  @brief Smart Constructor.
+ */
+ExecTaskPtr ExecTask::init(const std::string& name)
+{
+  return ExecTaskPtr(new ExecTask(name));
+}
+
+/**
+ *  @brief Smart Constructor.
+ */
+ExecTaskPtr ExecTask::init(const std::string& name, double flops, Host* host)
+{
+  return init(name)->set_flops(flops)->set_host(host);
+}
+
+/** @param instance The Task instance to fire.
+ *  @note Only the dispatcher instance triggers the on_start signal.
+ *        Comms are created if hosts differ between dispatcher and the instance to fire,
+ *        or between the instance and the collector.
+ */
+void ExecTask::fire(std::string instance)
+{
+  Task::fire(instance);
+  if (instance == "dispatcher" or instance == "collector") {
+    auto exec = Exec::init()
+                    ->set_name(get_name() + "_" + instance)
+                    ->set_flops_amount(get_amount(instance))
+                    ->set_host(host_[instance]);
+    exec->start();
+    exec->on_this_completion_cb([this, instance](Exec const&) { complete(instance); });
+    store_activity(exec, instance);
+  } else {
+    auto exec = Exec::init()->set_name(get_name())->set_flops_amount(get_amount())->set_host(host_[instance]);
+    if (host_["dispatcher"] == host_[instance]) {
+      exec->start();
+      store_activity(exec, instance);
+    } else {
+      auto comm = Comm::sendto_init(host_["dispatcher"], host_[instance])
+                      ->set_name(get_name() + "_dispatcher_to_" + instance)
+                      ->set_payload_size(get_internal_bytes("dispatcher"));
+      comm->add_successor(exec);
+      comm->start();
+      store_activity(comm, instance);
+    }
+    if (host_[instance] == host_["collector"]) {
+      exec->on_this_completion_cb([this, instance](Exec const&) { complete(instance); });
+      if (host_["dispatcher"] != host_[instance])
+        store_activity(exec, instance);
+    } else {
+      auto comm = Comm::sendto_init(host_[instance], host_["collector"])
+                      ->set_name(get_name() + instance + "_to_collector")
+                      ->set_payload_size(get_internal_bytes(instance));
+      exec->add_successor(comm);
+      comm->on_this_completion_cb([this, instance](Comm const&) { complete(instance); });
+      comm.detach();
+    }
+  }
+}
+
+/** @param host The host to set.
+ *  @param instance The Task instance to modify.
+ *  @brief Set a new host.
+ */
+ExecTaskPtr ExecTask::set_host(Host* host, std::string instance)
+{
+  kernel::actor::simcall_answered([this, host, &instance] {
+    if (instance == "all")
+      for (auto& [key, value] : host_)
+        host_[key] = host;
+    else
+      host_[instance] = host;
+  });
+  return this;
+}
+
+/** @param flops The amount of flops to set.
+ *  @param instance The Task instance to modify.
+ */
+ExecTaskPtr ExecTask::set_flops(double flops, std::string instance)
+{
+  kernel::actor::simcall_answered([this, flops, &instance] { set_amount(flops, instance); });
+  return this;
+}
+
+/** @param n The number of instances to add to this Task (>=0).
+    @note Instances goes always from instance_0 to instance_x,
+          where x is the current number of instance.
+ */
+void ExecTask::add_instances(int n)
+{
+  Task::add_instances(n);
+  int instance_count = (int)host_.size() - 2;
+  for (int i = instance_count; i < n + instance_count; i++)
+    host_["instance_" + std::to_string(i)] = host_.at("instance_0");
+}
+
+/** @param n The number of instances to remove from this Task (>=0).
+    @note Instances goes always from instance_0 to instance_x,
+          where x is the current number of instance.
+          Running instance cannot be removed.
+ */
+void ExecTask::remove_instances(int n)
+{
+  Task::remove_instances(n);
+  int instance_count = (int)host_.size() - 2;
+  for (int i = instance_count - 1; i >= instance_count - n; i--)
+    host_.erase("instance_" + std::to_string(i));
+}
+
+/**
+ *  @brief Default constructor.
+ */
+CommTask::CommTask(const std::string& name) : Task(name)
+{
+  set_load_balancing_function([]() { return "instance_0"; });
+}
+
+/**
+ *  @brief Smart constructor.
+ */
+CommTaskPtr CommTask::init(const std::string& name)
+{
+  return CommTaskPtr(new CommTask(name));
+}
+
+/**
+ *  @brief Smart constructor.
+ */
+CommTaskPtr CommTask::init(const std::string& name, double bytes, Host* source, Host* destination)
+{
+  return init(name)->set_bytes(bytes)->set_source(source)->set_destination(destination);
+}
+
+/** @param instance The Task instance to fire.
+ *  @note Only the dispatcher instance triggers the on_start signal.
+ */
+void CommTask::fire(std::string instance)
+{
+  Task::fire(instance);
+  if (instance == "dispatcher" or instance == "collector") {
+    auto exec = Exec::init()
+                    ->set_name(get_name() + "_" + instance)
+                    ->set_flops_amount(get_amount(instance))
+                    ->set_host(instance == "dispatcher" ? source_ : destination_);
+    exec->start();
+    exec->on_this_completion_cb([this, instance](Exec const&) { complete(instance); });
+    store_activity(exec, instance);
+  } else {
+    auto comm = Comm::sendto_init(source_, destination_)->set_name(get_name())->set_payload_size(get_amount());
+    comm->start();
+    comm->on_this_completion_cb([this, instance](Comm const&) { complete(instance); });
+    store_activity(comm, instance);
+  }
+}
+
+/**
+ *  @param source The host to set.
+ *  @brief Set a new source host.
+ */
+CommTaskPtr CommTask::set_source(Host* source)
+{
+  kernel::actor::simcall_answered([this, source] { source_ = source; });
+  return this;
+}
+
+/**
+ *  @param destination The host to set.
+ *  @brief Set a new destination host.
+ */
+CommTaskPtr CommTask::set_destination(Host* destination)
+{
+  kernel::actor::simcall_answered([this, destination] { destination_ = destination; });
+  return this;
+}
+
+/**
+ *  @param bytes The amount of bytes to set.
+ */
+CommTaskPtr CommTask::set_bytes(double bytes)
+{
+  kernel::actor::simcall_answered([this, bytes] { set_amount(bytes); });
+  return this;
+}
+
+/**
+ *  @brief Default constructor.
+ */
+IoTask::IoTask(const std::string& name) : Task(name)
+{
+  set_load_balancing_function([]() { return "instance_0"; });
+}
+
+/**
+ *  @brief Smart Constructor.
+ */
+IoTaskPtr IoTask::init(const std::string& name)
+{
+  return IoTaskPtr(new IoTask(name));
+}
+
+/**
+ *  @brief Smart Constructor.
+ */
+IoTaskPtr IoTask::init(const std::string& name, double bytes, Disk* disk, Io::OpType type)
+{
+  return init(name)->set_bytes(bytes)->set_disk(disk)->set_op_type(type);
+}
+
+/**
+ *  @param disk The disk to set.
+ */
+IoTaskPtr IoTask::set_disk(Disk* disk)
+{
+  kernel::actor::simcall_answered([this, disk] { disk_ = disk; });
+  return this;
+}
+
+/**
+ *  @param bytes The amount of bytes to set.
+ */
+IoTaskPtr IoTask::set_bytes(double bytes)
+{
+  kernel::actor::simcall_answered([this, bytes] { set_amount(bytes); });
+  return this;
+}
+
+/**
+ *  @param type The op type to set.
+ */
+IoTaskPtr IoTask::set_op_type(Io::OpType type)
+{
+  kernel::actor::simcall_answered([this, type] { type_ = type; });
+  return this;
+}
+
+/** @param instance The Task instance to fire.
+ *  @note Only the dispatcher instance triggers the on_start signal.
+ */
+void IoTask::fire(std::string instance)
+{
+  Task::fire(instance);
+  if (instance == "dispatcher" or instance == "collector") {
+    auto exec = Exec::init()
+                    ->set_name(get_name() + "_" + instance)
+                    ->set_flops_amount(get_amount(instance))
+                    ->set_host(disk_->get_host());
+    exec->start();
+    exec->on_this_completion_cb([this, instance](Exec const&) { complete(instance); });
+    store_activity(exec, instance);
+  } else {
+    auto io = Io::init()->set_name(get_name())->set_size(get_amount())->set_disk(disk_)->set_op_type(type_);
+    io->start();
+    io->on_this_completion_cb([this, instance](Io const&) { complete(instance); });
+    store_activity(io, instance);
+  }
+}
+} // namespace simgrid::s4u
index 1c305be..415b1f7 100644 (file)
@@ -32,13 +32,6 @@ void VmHostExt::ensureVmExtInstalled()
     EXTENSION_ID = Host::extension_create<VmHostExt>();
 }
 
-VirtualMachine::VirtualMachine(const std::string& name, s4u::Host* physical_host, int core_amount, size_t ramsize)
-    : Host(new kernel::resource::VirtualMachineImpl(name, this, physical_host, core_amount, ramsize))
-    , pimpl_vm_(dynamic_cast<kernel::resource::VirtualMachineImpl*>(Host::get_impl()))
-{
-  physical_host->get_impl()->create_vm(name, this);
-}
-
 VirtualMachine::VirtualMachine(kernel::resource::VirtualMachineImpl* impl)
     : Host(impl), pimpl_vm_(dynamic_cast<kernel::resource::VirtualMachineImpl*>(Host::get_impl()))
 {
@@ -74,6 +67,7 @@ void VirtualMachine::destroy()
 
     XBT_DEBUG("destroy %s", get_cname());
     on_vm_destruction(*this);
+    on_this_vm_destruction(*this);
     /* Then, destroy the VM object */
     kernel::actor::simcall_answered(
         [this]() { get_vm_impl()->get_physical_host()->get_impl()->destroy_vm(get_name()); });
index 9694c6b..7152419 100644 (file)
@@ -31,7 +31,7 @@ void ForcefulKillException::do_throw()
   throw ForcefulKillException();
 }
 
-bool ForcefulKillException::try_n_catch(const std::function<void()>& try_block) // XBT_ATTRIB_DEPRECATED_v337
+bool ForcefulKillException::try_n_catch(const std::function<void()>& try_block) // XBT_ATTRIB_DEPRECATED_v338
 {
   bool res;
   try {
index 5724971..e3095bc 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/simgrid/module.hpp"
 #include "src/simgrid/sg_config.hpp"
 
+#include <algorithm>
 #include <sstream>
 
 XBT_LOG_NEW_CATEGORY(plugin, "Common category for the logging of all plugins");
index fb1df9d..5902d70 100644 (file)
@@ -20,7 +20,6 @@
 #include "src/simgrid/module.hpp"
 #include "src/simgrid/sg_config.hpp"
 #include "src/smpi/include/smpi_config.hpp"
-#include "src/xbt/mmalloc/mmalloc.h"
 
 #include <string_view>
 
@@ -31,9 +30,9 @@ static simgrid::config::Flag<bool> cfg_continue_after_help
 
 /** @brief Allow other libraries to react to the --help flag, too
  *
- * When finding --help on the command line, simgrid usually stops right after displaying its help message.
- * If you are writing a library using simgrid, you may want to display your own help message before everything stops.
- * If so, just call this function before having simgrid parsing the command line, and you will be given the control
+ * When finding --help on the command line, SimGrid usually stops right after displaying its help message.
+ * If you are writing a library using SimGrid, you may want to display your own help message before everything stops.
+ * If so, just call this function before having SimGrid parsing the command line, and you will be given the control
  * even if the user is asking for help.
  */
 void sg_config_continue_after_help()
@@ -202,15 +201,8 @@ void sg_config_init(int *argc, char **argv)
       [](int value) { simgrid::kernel::context::Context::guard_size = value * xbt_pagesize; }};
 
   static simgrid::config::Flag<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 || not malloc_use_mmalloc(),
-            "Parallel simulation is forbidden in the verified program, as there is no protection against race "
-            "conditions in mmalloc itself. Please don't be so greedy and show some mercy for our implementation.");
-#endif
-        simgrid::kernel::context::Context::set_nthreads(nthreads);
-      }};
+      "contexts/nthreads", "Number of parallel threads used to execute user contexts", 1,
+      [](int nthreads) { simgrid::kernel::context::Context::set_nthreads(nthreads); }};
 
   /* synchronization mode for parallel user contexts */
 #if HAVE_FUTEX_H
index 10dbe7b..25e4a16 100644 (file)
@@ -10,7 +10,7 @@
 
 /** Config Globals */
 
-XBT_PUBLIC_DATA int _sg_cfg_init_status;
+XBT_PUBLIC_DATA int _sg_cfg_init_status; /* 0: not inited; 1: config module inited; 2: root zone of platform created */
 
 XBT_PUBLIC void sg_config_init(int* argc, char** argv);
 XBT_PUBLIC void sg_config_finalize();
index 3452c3b..953f6b1 100644 (file)
@@ -50,12 +50,6 @@ void sg_version()
   XBT_HELP("This program was linked against %s (git: %s), found in %s.", SIMGRID_VERSION_STRING, SIMGRID_GIT_VERSION,
            SIMGRID_INSTALL_PREFIX);
 
-#if SIMGRID_HAVE_MC
-  XBT_HELP("   Model-checking support compiled in.");
-#else
-  XBT_HELP("   Model-checking support disabled at compilation.");
-#endif
-
 #if SIMGRID_HAVE_NS3
   XBT_HELP("   ns-3 support compiled in.");
 #else
index 3bd52c7..4b9095c 100644 (file)
@@ -258,7 +258,9 @@ WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Scatter,(const void *sendbuf, int send
 WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Scatterv,(const void *sendbuf, const int *sendcounts, const int *displs, MPI_Datatype sendtype, void *recvbuf, int recvcount,MPI_Datatype recvtype, int root, MPI_Comm comm),(sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, recvtype, root, comm))
 WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Send_init,(const void *buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm, MPI_Request * request),(buf, count, datatype, dst, tag, comm, request))
 WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Sendrecv_replace,(void *buf, int count, MPI_Datatype datatype, int dst, int sendtag, int src, int recvtag,MPI_Comm comm, MPI_Status * status),(buf, count, datatype, dst, sendtag, src, recvtag, comm, status))
+WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Isendrecv_replace,(void *buf, int count, MPI_Datatype datatype, int dst, int sendtag, int src, int recvtag,MPI_Comm comm, MPI_Request* req),(buf, count, datatype, dst, sendtag, src, recvtag, comm, req))
 WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Sendrecv,(const void *sendbuf, int sendcount, MPI_Datatype sendtype,int dst, int sendtag, void *recvbuf, int recvcount,MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Status * status),(sendbuf, sendcount, sendtype, dst, sendtag, recvbuf, recvcount, recvtype, src, recvtag,comm, status))
+WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Isendrecv,(const void *sendbuf, int sendcount, MPI_Datatype sendtype,int dst, int sendtag, void *recvbuf, int recvcount,MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Request* req),(sendbuf, sendcount, sendtype, dst, sendtag, recvbuf, recvcount, recvtype, src, recvtag,comm, req))
 WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Send,(const void *buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm),(buf, count, datatype, dst, tag, comm))
 WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Ssend_init,(const void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request* request),(buf, count, datatype, dest, tag, comm, request))
 WRAPPED_PMPI_CALL_ERRHANDLER_COMM(int,MPI_Ssend,(const void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) ,(buf, count, datatype, dest, tag, comm))
@@ -501,3 +503,9 @@ UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Unpack_external,(char *datarep, void *in
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Unpublish_name,( char *service_name, MPI_Info info, char *port_name),( service_name, info, port_name))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Win_test,(MPI_Win win, int *flag),(win, flag))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL_NOFAIL(int,MPI_Win_sync,(MPI_Win win),(win))
+UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Parrived, (MPI_Request request, int partition, int *flag), (request, partition, flag))
+UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Pready, (int partitions, MPI_Request request), (partitions, request))
+UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Pready_range, (int partition_low, int partition_high, MPI_Request request),(partition_low, partition_high, request))
+UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Pready_list, (int length, int partition_list[], MPI_Request request), (length, partition_list, request))
+UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Precv_init, (void* buf, int partitions, MPI_Count count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Info info, MPI_Request *request), (buf, partitions, count, datatype, source, tag, comm, info, request))
+UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Psend_init, (const void* buf, int partitions, MPI_Count count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Info info, MPI_Request *request), (buf, partitions, count, datatype, dest, tag, comm, info, request))
index 3168044..93dca48 100644 (file)
@@ -136,9 +136,9 @@ int PMPI_Abort(MPI_Comm comm, int /*errorcode*/)
   smpi_bench_end();
   CHECK_COMM(1)
   XBT_WARN("MPI_Abort was called, something went probably wrong in this simulation ! Killing all processes sharing the same MPI_COMM_WORLD");
-  auto myself = simgrid::kernel::actor::ActorImpl::self();
+  auto* myself = simgrid::kernel::actor::ActorImpl::self();
   for (int i = 0; i < comm->size(); i++){
-    auto actor = simgrid::kernel::EngineImpl::get_instance()->get_actor_by_pid(comm->group()->actor(i));
+    auto* actor = simgrid::kernel::EngineImpl::get_instance()->get_actor_by_pid(comm->group()->actor(i));
     if (actor != nullptr && actor != myself)
       simgrid::kernel::actor::simcall_answered([actor] { actor->exit(); });
   }
index d7efa43..c30dfda 100644 (file)
@@ -6,9 +6,10 @@
 #include <climits>
 
 #include "private.hpp"
+#include "simgrid/s4u/Engine.hpp"
 #include "smpi_comm.hpp"
-#include "smpi_info.hpp"
 #include "smpi_errhandler.hpp"
+#include "smpi_info.hpp"
 #include "src/smpi/include/smpi_actor.hpp"
 
 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(smpi_pmpi);
@@ -248,7 +249,7 @@ int PMPI_Attr_get(MPI_Comm comm, int keyval, void* attr_value, int* flag) {
     return MPI_SUCCESS;
   case MPI_UNIVERSE_SIZE:
     *flag = 1;
-    universe_size                   = smpi_get_universe_size();
+    universe_size                   = simgrid::s4u::Engine::get_instance()->get_host_count();
     *static_cast<int**>(attr_value) = &universe_size;
     return MPI_SUCCESS;
   case MPI_LASTUSEDCODE:
index 94bb62b..0dc9e32 100644 (file)
@@ -381,6 +381,8 @@ int PMPI_Sendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, int
   CHECK_TYPE(8, recvtype)
   CHECK_BUFFER(1, sendbuf, sendcount, sendtype)
   CHECK_BUFFER(6, recvbuf, recvcount, recvtype)
+  CHECK_ARGS(sendbuf == recvbuf && sendcount > 0 && recvcount > 0, MPI_ERR_BUFFER,
+             "%s: Invalid parameters 1 and 6: sendbuf and recvbuf must be disjoint", __func__)
   CHECK_TAG(10, recvtag)
   CHECK_COMM(11)
   const SmpiBenchGuard suspend_bench;
@@ -427,6 +429,66 @@ int PMPI_Sendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, int
   return retval;
 }
 
+int PMPI_Isendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, int dst, int sendtag, void* recvbuf,
+                  int recvcount, MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Request* request)
+{
+  int retval = 0;
+  SET_BUF1(sendbuf)
+  SET_BUF2(recvbuf)
+  CHECK_COUNT(2, sendcount)
+  CHECK_TYPE(3, sendtype)
+  CHECK_TAG(5, sendtag)
+  CHECK_COUNT(7, recvcount)
+  CHECK_TYPE(8, recvtype)
+  CHECK_BUFFER(1, sendbuf, sendcount, sendtype)
+  CHECK_BUFFER(6, recvbuf, recvcount, recvtype)
+  CHECK_ARGS(sendbuf == recvbuf && sendcount > 0 && recvcount > 0, MPI_ERR_BUFFER,
+             "%s: Invalid parameters 1 and 6: sendbuf and recvbuf must be disjoint", __func__)
+  CHECK_TAG(10, recvtag)
+  CHECK_COMM(11)
+  CHECK_REQUEST(12)
+  *request = MPI_REQUEST_NULL;
+  const SmpiBenchGuard suspend_bench;
+
+  if (src == MPI_PROC_NULL && dst != MPI_PROC_NULL){
+    *request=simgrid::smpi::Request::isend(sendbuf, sendcount, sendtype, dst, sendtag, comm);
+    retval = MPI_SUCCESS;
+  } else if (dst == MPI_PROC_NULL){
+    *request = simgrid::smpi::Request::irecv(recvbuf, recvcount, recvtype, src, recvtag, comm);
+    retval = MPI_SUCCESS;
+  } else if (dst >= comm->group()->size() || dst <0 ||
+      (src!=MPI_ANY_SOURCE && (src >= comm->group()->size() || src <0))){
+    retval = MPI_ERR_RANK;
+  } else {
+    aid_t my_proc_id = simgrid::s4u::this_actor::get_pid();
+    aid_t dst_traced = MPI_COMM_WORLD->group()->rank(getPid(comm, dst));
+    aid_t src_traced = MPI_COMM_WORLD->group()->rank(getPid(comm, src));
+
+    // 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(
+                           "isendRecv", -1, sendcount,
+                           dst_hack, recvcount, src_hack,
+                           simgrid::smpi::Datatype::encode(sendtype), simgrid::smpi::Datatype::encode(recvtype)));
+
+    TRACE_smpi_send(my_proc_id, my_proc_id, dst_traced, sendtag, sendcount * sendtype->size());
+
+    simgrid::smpi::Request::isendrecv(sendbuf, sendcount, sendtype, dst, sendtag, recvbuf, recvcount, recvtype, src,
+                                     recvtag, comm, request);
+    retval = MPI_SUCCESS;
+
+    TRACE_smpi_recv(src_traced, my_proc_id, recvtag);
+    TRACE_smpi_comm_out(my_proc_id);
+  }
+
+  return retval;
+}
+
+
 int PMPI_Sendrecv_replace(void* buf, int count, MPI_Datatype datatype, int dst, int sendtag, int src, int recvtag,
                           MPI_Comm comm, MPI_Status* status)
 {
@@ -450,6 +512,29 @@ int PMPI_Sendrecv_replace(void* buf, int count, MPI_Datatype datatype, int dst,
   return retval;
 }
 
+int PMPI_Isendrecv_replace(void* buf, int count, MPI_Datatype datatype, int dst, int sendtag, int src, int recvtag,
+                          MPI_Comm comm, MPI_Request* request)
+{
+  int retval = 0;
+  SET_BUF1(buf)
+  CHECK_COUNT(2, count)
+  CHECK_TYPE(3, datatype)
+  CHECK_BUFFER(1, buf, count, datatype)
+  CHECK_REQUEST(10)
+  *request = MPI_REQUEST_NULL;
+
+  int size = datatype->get_extent() * count;
+  if (size == 0)
+    return MPI_SUCCESS;
+  else if (size <0)
+    return MPI_ERR_ARG;
+  std::vector<char> sendbuf(size);
+  simgrid::smpi::Datatype::copy(buf, count, datatype, sendbuf.data(), count, datatype);
+  retval =
+      MPI_Isendrecv(sendbuf.data(), count, datatype, dst, sendtag, buf, count, datatype, src, recvtag, comm, request);
+  return retval;
+}
+
 int PMPI_Test(MPI_Request * request, int *flag, MPI_Status * status)
 {
   int retval = 0;
index b9d1680..cf22e98 100644 (file)
 #include "smpi_request.hpp"
 #include "xbt/config.hpp"
 
+#include <iomanip>
 #include <map>
+#include <numeric>
+#include <sstream>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_coll, smpi, "Logging specific to SMPI collectives.");
 
@@ -242,6 +245,29 @@ std::vector<s_mpi_coll_description_t>* colls::get_smpi_coll_descriptions(const s
   return &iter->second;
 }
 
+std::string colls::get_smpi_coll_help()
+{
+  size_t max_name_len =
+      std::accumulate(begin(smpi_coll_descriptions), end(smpi_coll_descriptions), 0, [](auto len, auto const& coll) {
+        return std::max(len, std::accumulate(begin(coll.second), end(coll.second), 0, [](auto len, auto const& descr) {
+                          return std::max<size_t>(len, descr.name.length());
+                        }));
+      });
+  std::ostringstream oss;
+  std::string title = "Available collective algorithms (select them with \"smpi/collective_name:algo_name\"):";
+  oss << title << '\n' << std::setfill('=') << std::setw(title.length() + 1) << '\n';
+  for (auto const& [coll, algos] : smpi_coll_descriptions) {
+    std::string line = "Collective: \"" + coll + "\"";
+    oss << line << '\n' << std::setfill('-') << std::setw(line.length() + 1) << '\n';
+    oss << std::setfill(' ') << std::left;
+    for (auto const& [name, descr, _] : algos)
+      oss << "  " << std::setw(max_name_len) << name << " " << descr << "\n";
+    oss << std::right << '\n';
+  }
+  oss << "Please see https://simgrid.org/doc/latest/app_smpi.html#available-algorithms for more information.\n";
+  return oss.str();
+}
+
 static s_mpi_coll_description_t* find_coll_description(const std::string& collective, const std::string& algo)
 {
   std::vector<s_mpi_coll_description_t>* table = colls::get_smpi_coll_descriptions(collective);
@@ -258,7 +284,8 @@ static s_mpi_coll_description_t* find_coll_description(const std::string& collec
   std::string name_list = table->at(0).name;
   for (unsigned long i = 1; i < table->size(); i++)
     name_list = name_list + ", " + table->at(i).name;
-  xbt_die("Collective '%s' has no algorithm '%s'! Valid algorithms: %s.", collective.c_str(), algo.c_str(), name_list.c_str());
+  xbt_die("Collective '%s' has no algorithm '%s'! Valid algorithms: %s. Please use --help-coll for details.",
+          collective.c_str(), algo.c_str(), name_list.c_str());
 }
 
 int (*colls::gather)(const void* send_buff, int send_count, MPI_Datatype send_type, void* recv_buff, int recv_count,
index 684bcb6..d3419b2 100644 (file)
@@ -1,4 +1,4 @@
-/* selector with default/naive Simgrid algorithms. These should not be trusted for performance evaluations */
+/* selector with default/naive SimGrid algorithms. These should not be trusted for performance evaluations */
 
 /* Copyright (c) 2009-2023. The SimGrid Team. All rights reserved.          */
 
index 2133849..cae46b9 100644 (file)
@@ -74,7 +74,6 @@ using MPIR_Dist_Graph_Topology = SMPI_Dist_Graph_topology*;
 
 XBT_PRIVATE simgrid::smpi::ActorExt* smpi_process();
 XBT_PRIVATE simgrid::smpi::ActorExt* smpi_process_remote(simgrid::s4u::ActorPtr actor);
-XBT_PRIVATE int smpi_get_universe_size();
 
 XBT_PRIVATE void smpi_deployment_register_process(const std::string& instance_id, int rank,
                                                   const simgrid::s4u::Actor* actor);
index f6194db..cb097d2 100644 (file)
@@ -68,8 +68,8 @@ public:
   smpi_trace_call_location_t* call_location();
   void set_privatized_region(smpi_privatization_region_t region);
   smpi_privatization_region_t privatized_region() const;
-  s4u::Mailbox* mailbox() const { return mailbox_; }
-  s4u::Mailbox* mailbox_small() const { return mailbox_small_; }
+  s4u::Mailbox* mailbox();
+  s4u::Mailbox* mailbox_small();
   s4u::MutexPtr mailboxes_mutex() const;
 #if HAVE_PAPI
   int papi_event_set() const;
index b882209..786a5e8 100644 (file)
@@ -57,6 +57,7 @@ struct s_mpi_coll_description_t {
 namespace colls {
 void set_collectives();
 XBT_PUBLIC std::vector<s_mpi_coll_description_t>* get_smpi_coll_descriptions(const std::string& name);
+std::string get_smpi_coll_help();
 
 void set_gather(const std::string& name);
 void set_allgather(const std::string& name);
index 03e03e8..10fbc85 100644 (file)
@@ -25,7 +25,7 @@
       for (const auto& elem : (action)) {                                                                              \
         ss << elem << " ";                                                                                             \
       }                                                                                                                \
-      ss << "\nPlease contact the Simgrid team if support is needed";                                                  \
+      ss << "\nPlease contact the SimGrid team if support is needed";                                                  \
       throw std::invalid_argument(ss.str());                                                                           \
     }                                                                                                                  \
   }
index a8b26a6..9b0a6cc 100644 (file)
@@ -47,11 +47,11 @@ class Request : public F2C {
   bool detached_;
   MPI_Request detached_sender_;
   int refcount_;
-  unsigned int message_id_;
+  std::vector<unsigned int> message_id_;
   MPI_Op op_;
   std::unique_ptr<smpi_mpi_generalized_request_funcs_t> generalized_funcs;
   std::vector<MPI_Request> nbc_requests_;
-  s4u::Host* src_host_ = nullptr; //!< save simgrid's source host since it can finished before the recv
+  s4u::Host* src_host_ = nullptr; //!< save SimGrid's source host since it can finished before the recv
   static bool match_common(MPI_Request req, MPI_Request sender, MPI_Request receiver);
   static bool match_types(MPI_Datatype stype, MPI_Datatype rtype);
 
@@ -102,6 +102,8 @@ public:
 
   static void sendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, int dst, int sendtag, void* recvbuf,
                        int recvcount, MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Status* status);
+  static void isendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, int dst, int sendtag, void* recvbuf,
+                       int recvcount, MPI_Datatype recvtype, int src, int recvtag, MPI_Comm comm, MPI_Request* request);
 
   static void startall(int count, MPI_Request* requests);
 
index f1b6524..e46d67e 100644 (file)
@@ -6,7 +6,6 @@
 #ifndef SMPI_TOPO_HPP_INCLUDED
 #define SMPI_TOPO_HPP_INCLUDED
 
-#include "smpi_comm.hpp"
 #include "smpi_status.hpp"
 #include <memory>
 
index 993c728..63e8f33 100644 (file)
@@ -147,7 +147,7 @@ void TRACE_smpi_init(aid_t pid, const std::string& calling_func)
   if (not TRACE_smpi_is_enabled())
     return;
 
-  auto self = simgrid::s4u::Actor::self();
+  const auto* self = simgrid::s4u::Actor::self();
 
   TRACE_smpi_setup_container(pid, sg_host_self());
   simgrid::s4u::this_actor::on_exit([self](bool) { smpi_container(self->get_pid())->remove_from_parent(); });
index 66917b4..056cecf 100644 (file)
@@ -26,13 +26,12 @@ ActorExt::ActorExt(s4u::Actor* actor) : actor_(actor)
   if (not simgrid::smpi::ActorExt::EXTENSION_ID.valid())
     simgrid::smpi::ActorExt::EXTENSION_ID = simgrid::s4u::Actor::extension_create<simgrid::smpi::ActorExt>();
 
-  mailbox_         = s4u::Mailbox::by_name("SMPI-" + std::to_string(actor_->get_pid()));
-  mailbox_small_   = s4u::Mailbox::by_name("small-" + std::to_string(actor_->get_pid()));
+  mailbox_         = nullptr;
+  mailbox_small_   = nullptr;
   mailboxes_mutex_ = s4u::Mutex::create();
   timer_           = xbt_os_timer_new();
   state_           = SmpiProcessState::UNINITIALIZED;
   info_env_        = MPI_INFO_NULL;
-  MC_ignore_heap(timer_, xbt_os_timer_size());
 
 #if HAVE_PAPI
   if (not smpi_cfg_papi_events_file().empty()) {
@@ -91,6 +90,22 @@ int ActorExt::initialized() const
   return (state_ == SmpiProcessState::INITIALIZED);
 }
 
+/** @brief Return main mailbox of the process */
+s4u::Mailbox* ActorExt::mailbox()
+{
+  if(mailbox_==nullptr)
+    mailbox_=s4u::Mailbox::by_name("SMPI-" + std::to_string(actor_->get_pid()));
+  return mailbox_;
+}
+
+/** @brief Return mailbox for small messages */
+s4u::Mailbox* ActorExt::mailbox_small()
+{
+  if(mailbox_small_==nullptr)
+    mailbox_small_=s4u::Mailbox::by_name("small-" + std::to_string(actor_->get_pid()));
+  return mailbox_small_;
+}
+
 /** @brief Mark a process as initialized (=MPI_Init called) */
 void ActorExt::mark_as_initialized()
 {
@@ -224,9 +239,6 @@ int ActorExt::sampling() const
 
 void ActorExt::init()
 {
-  xbt_assert(smpi_get_universe_size() != 0, "SimGrid was not initialized properly before entering MPI_Init. "
-                                            "Aborting, please check compilation process and use smpirun.");
-
   ActorExt* ext = smpi_process();
   // if we are in MPI_Init and argc handling has already been done.
   if (ext->initialized())
@@ -245,7 +257,7 @@ void ActorExt::init()
   ext->comm_world_ = smpi_deployment_comm_world(ext->instance_id_);
 
   // set the process attached to the mailbox
-  ext->mailbox_small_->set_receiver(ext->actor_);
+  ext->mailbox_small()->set_receiver(ext->actor_);
   XBT_DEBUG("<%ld> SMPI process has been initialized: %p", ext->actor_->get_pid(), ext->actor_);
 }
 
index d79504f..542c0ee 100644 (file)
@@ -420,7 +420,7 @@ smpi_trace_call_location_t* smpi_trace_get_call_location()
   return smpi_process()->call_location();
 }
 
-void smpi_trace_set_call_location(const char* file, const int line)
+void smpi_trace_set_call_location(const char* file, const int line, const char* call_name)
 {
   smpi_trace_call_location_t* loc = smpi_process()->call_location();
 
@@ -430,19 +430,21 @@ void smpi_trace_set_call_location(const char* file, const int line)
     loc->filename = simgrid::xbt::Path(file).get_base_name();
   else
     loc->filename = file;
+  std::replace(loc->filename.begin(), loc->filename.end(), ' ', '_');
   loc->linenumber = line;
+  loc->func_call  = call_name;
 }
 
 /** Required for Fortran bindings */
-void smpi_trace_set_call_location_(const char* file, const int* line)
+void smpi_trace_set_call_location_(const char* file, const int* line, const char* call_name)
 {
-  smpi_trace_set_call_location(file, *line);
+  smpi_trace_set_call_location(file, *line, call_name);
 }
 
 /** Required for Fortran if -fsecond-underscore is activated */
-void smpi_trace_set_call_location__(const char* file, const int* line)
+void smpi_trace_set_call_location__(const char* file, const int* line, const char* call_name)
 {
-  smpi_trace_set_call_location(file, *line);
+  smpi_trace_set_call_location(file, *line, call_name);
 }
 
 void smpi_bench_destroy()
index 614a00e..513694b 100644 (file)
 #include <boost/algorithm/string.hpp> /* trim */
 #include <boost/tokenizer.hpp>
 
-#if SIMGRID_HAVE_MC
 #include "src/mc/mc_config.hpp"
 #include "src/mc/mc_replay.hpp"
-#endif
 
 #if defined(__APPLE__)
 # include <AvailabilityMacros.h>
@@ -257,9 +255,9 @@ void smpi_init_options_internal(bool called_by_smpi_main)
   simgrid::config::declare_flag<std::string>(
       "smpi/privatization", "How we should privatize global variable at runtime (no, yes, mmap, dlopen).",
       default_privatization, [](const std::string& smpi_privatize_option) {
-        if (smpi_privatize_option == "no" || smpi_privatize_option == "0")
+        if (smpi_privatize_option == "no" || smpi_privatize_option == "0" || smpi_privatize_option == "OFF")
           _smpi_cfg_privatization = SmpiPrivStrategies::NONE;
-        else if (smpi_privatize_option == "yes" || smpi_privatize_option == "1")
+        else if (smpi_privatize_option == "yes" || smpi_privatize_option == "1" || smpi_privatize_option == "ON")
           _smpi_cfg_privatization = SmpiPrivStrategies::DEFAULT;
         else if (smpi_privatize_option == "mmap")
           _smpi_cfg_privatization = SmpiPrivStrategies::MMAP;
@@ -308,7 +306,6 @@ void smpi_init_options_internal(bool called_by_smpi_main)
 
 void smpi_check_options()
 {
-#if SIMGRID_HAVE_MC
   if (MC_is_active() || MC_record_replay_is_active()) {
     if (_sg_mc_buffering == "zero")
       simgrid::config::set_value<int>("smpi/send-is-detached-thresh", 0);
@@ -317,7 +314,6 @@ void smpi_check_options()
     else
       THROW_IMPOSSIBLE;
   }
-#endif
 
   xbt_assert(smpi_cfg_async_small_thresh() <= smpi_cfg_detached_send_thresh(),
              "smpi/async-small-thresh (=%d) should be smaller or equal to smpi/send-is-detached-thresh (=%d)",
@@ -336,4 +332,3 @@ void smpi_check_options()
   simgrid::smpi::colls::set_collectives();
   simgrid::smpi::colls::smpi_coll_cleanup_callback = nullptr;
 }
-
index e73865c..9c9d7c8 100644 (file)
@@ -15,15 +15,12 @@ XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(smpi);
 
 namespace simgrid::smpi::app {
 
-static int universe_size = 0;
-
 class Instance {
 public:
   explicit Instance(int max_no_processes) : size_(max_no_processes)
   {
     auto* group = new simgrid::smpi::Group(size_);
     comm_world_ = new simgrid::smpi::Comm(group, nullptr, false, -1);
-    universe_size += max_no_processes;
     bar_ = s4u::Barrier::create(size_);
   }
   s4u::BarrierPtr bar_;
@@ -75,6 +72,17 @@ void SMPI_app_instance_start(const char* name, const std::function<void()>& code
     rank++;
   }
 }
+void SMPI_app_instance_join(const std::string& instance_id)
+{
+  std::vector<simgrid::s4u::ActorPtr> actors =
+      simgrid::s4u::Engine::get_instance()->get_filtered_actors([instance_id](simgrid::s4u::ActorPtr act) {
+        auto* actor_instance = act->get_property("instance_id");
+        return actor_instance != nullptr && strcmp(actor_instance, instance_id.c_str()) == 0;
+      });
+
+  for (auto& act : actors)
+    act->join();
+}
 
 void smpi_deployment_register_process(const std::string& instance_id, int rank, const simgrid::s4u::Actor* actor)
 {
@@ -113,11 +121,6 @@ void smpi_deployment_cleanup_instances(){
   smpi_instances.clear();
 }
 
-int smpi_get_universe_size()
-{
-  return simgrid::smpi::app::universe_size;
-}
-
 /** @brief Auxiliary method to get list of hosts to deploy app */
 static std::vector<simgrid::s4u::Host*> smpi_get_hosts(const simgrid::s4u::Engine* e, const std::string& hostfile)
 {
index b7d4dce..10203cb 100644 (file)
@@ -59,51 +59,51 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_kernel, smpi, "Logging specific to SMPI (ke
  * See https://www.akkadia.org/drepper/dsohowto.pdf
  * and https://lists.freebsd.org/pipermail/freebsd-current/2016-March/060284.html
 */
-#if !RTLD_DEEPBIND || HAVE_SANITIZER_ADDRESS || HAVE_SANITIZER_THREAD
+#if !defined(RTLD_DEEPBIND) || !RTLD_DEEPBIND || HAVE_SANITIZER_ADDRESS || HAVE_SANITIZER_THREAD
 #define WANT_RTLD_DEEPBIND 0
 #else
 #define WANT_RTLD_DEEPBIND RTLD_DEEPBIND
 #endif
 
 #if HAVE_PAPI
-std::map</* computation unit name */ std::string, papi_process_data, std::less<>> units2papi_setup;
+  std::map</* computation unit name */ std::string, papi_process_data, std::less<>> units2papi_setup;
 #endif
 
-std::unordered_map<std::string, double> location2speedup;
+  std::unordered_map<std::string, double> location2speedup;
 
-static int smpi_exit_status = 0;
-static xbt_os_timer_t global_timer;
-static std::vector<std::string> privatize_libs_paths;
+  static int smpi_exit_status = 0;
+  static xbt_os_timer_t global_timer;
+  static std::vector<std::string> privatize_libs_paths;
 
-// No instance gets manually created; check also the smpirun.in script as
-// this default name is used there as well (when the <actor> tag is generated).
-static const std::string smpi_default_instance_name("smpirun");
+  // No instance gets manually created; check also the smpirun.in script as
+  // this default name is used there as well (when the <actor> tag is generated).
+  static const std::string smpi_default_instance_name("smpirun");
 
-static simgrid::config::Flag<std::string>
-    smpi_hostfile("smpi/hostfile",
-                  "Classical MPI hostfile containing list of machines to dispatch "
-                  "the processes, one per line",
-                  "");
+  static simgrid::config::Flag<std::string>
+      smpi_hostfile("smpi/hostfile",
+                    "Classical MPI hostfile containing list of machines to dispatch "
+                    "the processes, one per line",
+                    "");
 
-static simgrid::config::Flag<std::string> smpi_replay("smpi/replay",
-                                                      "Replay a trace instead of executing the application", "");
+  static simgrid::config::Flag<std::string> smpi_replay("smpi/replay",
+                                                        "Replay a trace instead of executing the application", "");
 
-static simgrid::config::Flag<int> smpi_np("smpi/np", "Number of processes to be created", 0);
+  static simgrid::config::Flag<int> smpi_np("smpi/np", "Number of processes to be created", 0);
 
-static simgrid::config::Flag<int> smpi_map("smpi/map", "Display the mapping between nodes and processes", 0);
+  static simgrid::config::Flag<int> smpi_map("smpi/map", "Display the mapping between nodes and processes", 0);
 
-std::function<void(simgrid::kernel::activity::CommImpl*, void*, size_t)> smpi_comm_copy_data_callback =
-    &smpi_comm_copy_buffer_callback;
+  std::function<void(simgrid::kernel::activity::CommImpl*, void*, size_t)> smpi_comm_copy_data_callback =
+      &smpi_comm_copy_buffer_callback;
 
-simgrid::smpi::ActorExt* smpi_process()
-{
-  simgrid::s4u::ActorPtr me = simgrid::s4u::Actor::self();
+  simgrid::smpi::ActorExt* smpi_process()
+  {
+    simgrid::s4u::ActorPtr me = simgrid::s4u::Actor::self();
 
-  if (me == nullptr) // This happens sometimes (eg, when linking against NS3 because it pulls openMPI...)
-    return nullptr;
+    if (me == nullptr) // This happens sometimes (eg, when linking against NS3 because it pulls openMPI...)
+      return nullptr;
 
-  return me->extension<simgrid::smpi::ActorExt>();
-}
+    return me->extension<simgrid::smpi::ActorExt>();
+  }
 
 simgrid::smpi::ActorExt* smpi_process_remote(simgrid::s4u::ActorPtr actor)
 {
@@ -520,6 +520,10 @@ int smpi_main(const char* executable, int argc, char* argv[])
      * configuration tools */
     return 0;
   }
+  if (argv[0] == std::string("--help-coll")) {
+    std::cerr << simgrid::smpi::colls::get_smpi_coll_help();
+    return 0;
+  }
 
   smpi_init_options_internal(true);
   simgrid::s4u::Engine engine(&argc, argv);
index fdfcb18..77ea460 100644 (file)
@@ -52,7 +52,7 @@ void smpi_prepare_global_memory_segment()
 
 static void smpi_get_executable_global_size()
 {
-  auto* binary_name = simgrid::kernel::EngineImpl::get_instance()->get_cmdline().front().c_str();
+  const auto* binary_name = simgrid::kernel::EngineImpl::get_instance()->get_cmdline().front().c_str();
   char* buffer      = realpath(binary_name, nullptr);
   xbt_assert(buffer != nullptr, "Could not resolve real path of binary file '%s'", binary_name);
   std::string full_name = buffer;
@@ -95,7 +95,7 @@ static void* asan_safe_memcpy(void* dest, void* src, size_t n)
     while (i < n && __asan_address_is_poisoned(psrc + i))
       ++i;
     if (i < n) {
-      char* p  = static_cast<char*>(__asan_region_is_poisoned(psrc + i, n - i));
+      const char* p = static_cast<char*>(__asan_region_is_poisoned(psrc + i, n - i));
       size_t j = p ? (p - psrc) : n;
       memcpy(pdest + i, psrc + i, j - i);
       i = j;
index 93ca639..701323f 100644 (file)
@@ -39,7 +39,7 @@ template <class T> inline void hash_combine(std::size_t& seed, T const& v)
 }
 
 // Recursive template code derived from Matthieu M.
-template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1> class HashValueImpl {
+template <class Tuple, size_t Index = std::tuple_size_v<Tuple> - 1> class HashValueImpl {
 public:
   static void apply(size_t& seed, Tuple const& tuple)
   {
@@ -117,7 +117,7 @@ public:
   {
     for (auto const& [_, reqs] : store) {
       aid_t my_proc_id = simgrid::s4u::this_actor::get_pid();
-      for (auto& req: reqs){
+      for (const auto& req : reqs) {
         if (req != MPI_REQUEST_NULL && (req->src() == my_proc_id || req->dst() == my_proc_id)) {
           vec.push_back(req);
           req->print_request("MM");
@@ -564,7 +564,7 @@ void SleepAction::kernel(simgrid::xbt::ReplayAction&)
 void LocationAction::kernel(simgrid::xbt::ReplayAction&)
 {
   const LocationParser& args = get_args();
-  smpi_trace_set_call_location(args.filename.c_str(), args.line);
+  smpi_trace_set_call_location(args.filename.c_str(), args.line, "replay_action");
 }
 
 void TestAction::kernel(simgrid::xbt::ReplayAction&)
@@ -920,7 +920,7 @@ void smpi_replay_main(int rank, const char* private_trace_filename)
     unsigned int i=0;
 
     for (auto const& [_, reqs] : storage[simgrid::s4u::this_actor::get_pid()].get_store()) {
-      for (auto& req : reqs) {
+      for (const auto& req : reqs) {
         requests[i] = req; // FIXME: overwritten at each iteration?
       }
       i++;
index 10ab0ad..42108cd 100644 (file)
@@ -33,6 +33,7 @@
  *                                                                    \ |  |
  *                                                                      ----
  */
+#include <algorithm>
 #include <array>
 #include <cstring>
 #include <map>
index 642aa24..539e567 100644 (file)
@@ -116,7 +116,6 @@ Datatype::Datatype(int ident, int size, MPI_Aint lb, MPI_Aint ub, int flags) : D
 Datatype::Datatype(int size, MPI_Aint lb, MPI_Aint ub, int flags) : size_(size), lb_(lb), ub_(ub), flags_(flags)
 {
   this->add_f();
-  MC_ignore(&refcount_, sizeof refcount_);
 }
 
 // for predefined types, so refcount_ = 0.
@@ -124,7 +123,6 @@ Datatype::Datatype(const char* name, int ident, int size, MPI_Aint lb, MPI_Aint
     : name_(name), id(std::to_string(ident)), size_(size), lb_(lb), ub_(ub), flags_(flags), refcount_(0)
 {
   id2type_lookup.try_emplace(id, this);
-  MC_ignore(&refcount_, sizeof refcount_);
 }
 
 Datatype::Datatype(Datatype* datatype, int* ret)
@@ -205,14 +203,12 @@ int Datatype::clone(MPI_Datatype* type){
 void Datatype::ref()
 {
   refcount_++;
-  MC_ignore(&refcount_, sizeof refcount_);
 }
 
 void Datatype::unref(MPI_Datatype datatype)
 {
   if (datatype->refcount_ > 0)
     datatype->refcount_--;
-  MC_ignore(&datatype->refcount_, sizeof datatype->refcount_);
 
   if (datatype->refcount_ == 0 && not(datatype->flags_ & DT_FLAG_PREDEFINED))
     delete datatype;
index bdec55b..a1e6be7 100644 (file)
@@ -25,7 +25,7 @@ F2C::F2C() = default;
 int F2C::add_f()
 {
   allocate_lookup();
-  if (auto loc = smpi_process()->call_location(); loc && loc->linenumber != 0)
+  if (auto const* loc = smpi_process()->call_location(); loc && loc->linenumber != 0)
     call_location_= std::string (loc->filename + ":" + std::to_string(loc->linenumber));
   my_f2c_id_                 = global_f2c_id();
   (*f2c_lookup_)[my_f2c_id_] = this;
index 05c2e70..64008cd 100644 (file)
@@ -69,7 +69,6 @@ Request::Request(const void* buf, int count, MPI_Datatype datatype, aid_t src, a
     refcount_ = 1;
   else
     refcount_ = 0;
-  message_id_ = 0;
   init_buffer(count);
   this->add_f();
 }
@@ -181,15 +180,16 @@ void Request::init_buffer(int count){
 
 bool Request::match_recv(void* a, void* b, simgrid::kernel::activity::CommImpl*)
 {
-  auto ref = static_cast<MPI_Request>(a);
-  auto req = static_cast<MPI_Request>(b);
+  auto* ref  = static_cast<MPI_Request>(a);
+  auto* req  = static_cast<MPI_Request>(b);
   bool match = match_common(req, req, ref);
   if (not match || ref->comm_ == MPI_COMM_UNINITIALIZED || ref->comm_->is_smp_comm())
     return match;
-
-  if (ref->comm_->get_received_messages_count(ref->comm_->group()->rank(req->src_),
-                                              ref->comm_->group()->rank(req->dst_), req->tag_) == req->message_id_) {
+  auto it = std::find(req->message_id_.begin(), req->message_id_.end(), ref->comm_->get_received_messages_count(ref->comm_->group()->rank(req->src_),
+                                              ref->comm_->group()->rank(req->dst_), req->tag_));
+  if (it != req->message_id_.end()) {
     if (((ref->flags_ & MPI_REQ_PROBE) == 0) && ((req->flags_ & MPI_REQ_PROBE) == 0)) {
+      req->message_id_.erase(it);
       XBT_DEBUG("increasing count in comm %p, which was %u from pid %ld, to pid %ld with tag %d", ref->comm_,
                 ref->comm_->get_received_messages_count(ref->comm_->group()->rank(req->src_),
                                                         ref->comm_->group()->rank(req->dst_), req->tag_),
@@ -204,20 +204,20 @@ bool Request::match_recv(void* a, void* b, simgrid::kernel::activity::CommImpl*)
     match = false;
     req->flags_ &= ~MPI_REQ_MATCHED;
     ref->detached_sender_ = nullptr;
-    XBT_DEBUG("Refusing to match message, as its ID is not the one I expect. in comm %p, %u != %u, "
+    XBT_DEBUG("Refusing to match message, as its ID is not the one I expect. in comm %p, %u, "
               "from pid %ld to pid %ld, with tag %d",
               ref->comm_,
               ref->comm_->get_received_messages_count(ref->comm_->group()->rank(req->src_),
                                                       ref->comm_->group()->rank(req->dst_), req->tag_),
-              req->message_id_, req->src_, req->dst_, req->tag_);
+              req->src_, req->dst_, req->tag_);
   }
   return match;
 }
 
 bool Request::match_send(void* a, void* b, simgrid::kernel::activity::CommImpl*)
 {
-  auto ref = static_cast<MPI_Request>(a);
-  auto req = static_cast<MPI_Request>(b);
+  auto* ref = static_cast<MPI_Request>(a);
+  auto* req = static_cast<MPI_Request>(b);
   return match_common(req, ref, req);
 }
 
@@ -323,9 +323,9 @@ MPI_Request Request::irecv_init(void *buf, int count, MPI_Datatype datatype, int
 
 MPI_Request Request::ibsend(const void *buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm)
 {
-  auto request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
-                             dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
-                             MPI_REQ_NON_PERSISTENT | MPI_REQ_ISEND | MPI_REQ_SEND | MPI_REQ_BSEND);
+  auto* request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
+                              dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
+                              MPI_REQ_NON_PERSISTENT | MPI_REQ_ISEND | MPI_REQ_SEND | MPI_REQ_BSEND);
   if(dst != MPI_PROC_NULL)
     request->start();
   return request;
@@ -333,9 +333,9 @@ MPI_Request Request::ibsend(const void *buf, int count, MPI_Datatype datatype, i
 
 MPI_Request Request::isend(const void *buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm)
 {
-  auto request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
-                             dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
-                             MPI_REQ_NON_PERSISTENT | MPI_REQ_ISEND | MPI_REQ_SEND);
+  auto* request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
+                              dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
+                              MPI_REQ_NON_PERSISTENT | MPI_REQ_ISEND | MPI_REQ_SEND);
   if(dst != MPI_PROC_NULL)
     request->start();
   return request;
@@ -343,9 +343,9 @@ MPI_Request Request::isend(const void *buf, int count, MPI_Datatype datatype, in
 
 MPI_Request Request::issend(const void *buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm)
 {
-  auto request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
-                             dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
-                             MPI_REQ_NON_PERSISTENT | MPI_REQ_ISEND | MPI_REQ_SSEND | MPI_REQ_SEND);
+  auto* request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
+                              dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
+                              MPI_REQ_NON_PERSISTENT | MPI_REQ_ISEND | MPI_REQ_SSEND | MPI_REQ_SEND);
   if(dst != MPI_PROC_NULL)
     request->start();
   return request;
@@ -358,8 +358,8 @@ MPI_Request Request::irecv(void *buf, int count, MPI_Datatype datatype, int src,
     source = MPI_ANY_SOURCE;
   else if (src != MPI_PROC_NULL)
     source = comm->group()->actor(src);
-  auto request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, source,
-                             simgrid::s4u::this_actor::get_pid(), tag, comm, MPI_REQ_NON_PERSISTENT | MPI_REQ_RECV);
+  auto* request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, source,
+                              simgrid::s4u::this_actor::get_pid(), tag, comm, MPI_REQ_NON_PERSISTENT | MPI_REQ_RECV);
   if(src != MPI_PROC_NULL)
     request->start();
   return request;
@@ -374,9 +374,9 @@ int Request::recv(void *buf, int count, MPI_Datatype datatype, int src, int tag,
 
 void Request::bsend(const void *buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm)
 {
-  auto request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
-                             dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
-                             MPI_REQ_NON_PERSISTENT | MPI_REQ_SEND | MPI_REQ_BSEND);
+  auto* request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
+                              dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
+                              MPI_REQ_NON_PERSISTENT | MPI_REQ_SEND | MPI_REQ_BSEND);
 
   if(dst != MPI_PROC_NULL)
    request->start();
@@ -385,9 +385,9 @@ void Request::bsend(const void *buf, int count, MPI_Datatype datatype, int dst,
 
 void Request::send(const void *buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm)
 {
-  auto request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
-                             dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
-                             MPI_REQ_NON_PERSISTENT | MPI_REQ_SEND);
+  auto* request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
+                              dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
+                              MPI_REQ_NON_PERSISTENT | MPI_REQ_SEND);
   if(dst != MPI_PROC_NULL)
    request->start();
   wait(&request, MPI_STATUS_IGNORE);
@@ -395,9 +395,9 @@ void Request::send(const void *buf, int count, MPI_Datatype datatype, int dst, i
 
 void Request::ssend(const void *buf, int count, MPI_Datatype datatype, int dst, int tag, MPI_Comm comm)
 {
-  auto request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
-                             dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
-                             MPI_REQ_NON_PERSISTENT | MPI_REQ_SSEND | MPI_REQ_SEND);
+  auto* request = new Request(buf == MPI_BOTTOM ? nullptr : buf, count, datatype, simgrid::s4u::this_actor::get_pid(),
+                              dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL, tag, comm,
+                              MPI_REQ_NON_PERSISTENT | MPI_REQ_SSEND | MPI_REQ_SEND);
 
   if(dst != MPI_PROC_NULL)
    request->start();
@@ -439,6 +439,29 @@ void Request::sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype
   }
 }
 
+void Request::isendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,int dst, int sendtag,
+                       void *recvbuf, int recvcount, MPI_Datatype recvtype, int src, int recvtag,
+                       MPI_Comm comm, MPI_Request* request)
+{
+  aid_t source = MPI_PROC_NULL;
+  if (src == MPI_ANY_SOURCE)
+    source = MPI_ANY_SOURCE;
+  else if (src != MPI_PROC_NULL)
+    source = comm->group()->actor(src);
+  aid_t destination = dst != MPI_PROC_NULL ? comm->group()->actor(dst) : MPI_PROC_NULL;
+  
+  (*request) = new Request( nullptr, 0, MPI_BYTE,
+                         src,dst, sendtag, comm, MPI_REQ_PERSISTENT|MPI_REQ_NBC);
+  std::vector<MPI_Request> requests;
+  if (aid_t myid = simgrid::s4u::this_actor::get_pid(); (destination == myid) && (source == myid)) {
+    Datatype::copy(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype);
+    return;
+  }
+  requests.push_back(isend_init(sendbuf, sendcount, sendtype, dst, sendtag, comm));
+  requests.push_back(irecv_init(recvbuf, recvcount, recvtype, src, recvtag, comm));
+  (*request)->start_nbc_requests(requests);
+}
+
 void Request::start()
 {
   s4u::Mailbox* mailbox;
@@ -510,7 +533,8 @@ void Request::start()
                                              process->replaying() ? &smpi_comm_null_copy_buffer_callback
                                                                   : smpi_comm_copy_data_callback,
                                              this,
-                                             -1.0};
+                                             -1.0,
+                                             process->call_location()->get_call_location()};
     observer.set_tag(tag_);
 
     action_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::CommImpl::irecv(&observer); },
@@ -518,19 +542,18 @@ void Request::start()
 
     XBT_DEBUG("recv simcall posted");
   } else { /* the RECV flag was not set, so this is a send */
-    const simgrid::smpi::ActorExt* process = smpi_process_remote(simgrid::s4u::Actor::by_pid(dst_));
+    simgrid::smpi::ActorExt* process = smpi_process_remote(simgrid::s4u::Actor::by_pid(dst_));
     xbt_assert(process, "Actor pid=%ld is gone??", dst_);
     if (TRACE_smpi_view_internals())
       TRACE_smpi_send(src_, src_, dst_, tag_, size_);
     this->print_request("New send");
 
-    message_id_=comm_->get_sent_messages_count(comm_->group()->rank(src_), comm_->group()->rank(dst_), tag_);
+    message_id_.push_back(comm_->get_sent_messages_count(comm_->group()->rank(src_), comm_->group()->rank(dst_), tag_));
     comm_->increment_sent_messages_count(comm_->group()->rank(src_), comm_->group()->rank(dst_), tag_);
 
     void* buf = buf_;
-    if ((flags_ & MPI_REQ_SSEND) == 0 &&
-        ((flags_ & MPI_REQ_RMA) != 0 || (flags_ & MPI_REQ_BSEND) != 0 ||
-         static_cast<int>(size_) < smpi_cfg_detached_send_thresh())) {
+    if ((flags_ & MPI_REQ_SSEND) == 0 && ((flags_ & MPI_REQ_RMA) != 0 || (flags_ & MPI_REQ_BSEND) != 0 ||
+                                          static_cast<int>(size_) < smpi_cfg_detached_send_thresh())) {
       detached_    = true;
       XBT_DEBUG("Send request %p is detached", this);
       this->ref();
@@ -610,7 +633,7 @@ void Request::start()
         &xbt_free_f, // how to free the userdata if a detached send fails
         process->replaying() ? &smpi_comm_null_copy_buffer_callback : smpi_comm_copy_data_callback, this,
         // detach if msg size < eager/rdv switch limit
-        detached_};
+        detached_, process->call_location()->get_call_location()};
     observer.set_tag(tag_);
     action_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::CommImpl::isend(&observer); },
                                               &observer);
@@ -667,7 +690,9 @@ int Request::test(MPI_Request * request, MPI_Status * status, int* flag) {
     if ((*request)->action_ != nullptr && ((*request)->flags_ & MPI_REQ_CANCELLED) == 0){
       try{
         kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-        kernel::actor::ActivityTestSimcall observer{issuer, (*request)->action_.get()};
+        simgrid::smpi::ActorExt* process = smpi_process_remote(simgrid::s4u::Actor::by_pid(issuer->get_pid()));
+        kernel::actor::ActivityTestSimcall observer{issuer, (*request)->action_.get(),
+                                                    process->call_location()->get_call_location()};
         *flag = kernel::actor::simcall_answered(
             [&observer] { return observer.get_activity()->test(observer.get_issuer()); }, &observer);
       } catch (const Exception&) {
@@ -756,7 +781,8 @@ int Request::testany(int count, MPI_Request requests[], int *index, int* flag, M
     ssize_t i;
     try{
       kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-      kernel::actor::ActivityTestanySimcall observer{issuer, comms};
+      simgrid::smpi::ActorExt* process = smpi_process_remote(simgrid::s4u::Actor::by_pid(issuer->get_pid()));
+      kernel::actor::ActivityTestanySimcall observer{issuer, comms, process->call_location()->get_call_location()};
       i = kernel::actor::simcall_answered(
           [&observer] {
             return kernel::activity::ActivityImpl::test_any(observer.get_issuer(), observer.get_activities());
@@ -858,7 +884,7 @@ void Request::iprobe(int source, int tag, MPI_Comm comm, int* flag, MPI_Status*
   static int nsleeps = 1;
   double speed        = s4u::this_actor::get_host()->get_speed();
   double maxrate      = smpi_cfg_iprobe_cpu_usage();
-  auto request =
+  auto* request =
       new Request(nullptr, 0, MPI_CHAR, source == MPI_ANY_SOURCE ? MPI_ANY_SOURCE : comm->group()->actor(source),
                   simgrid::s4u::this_actor::get_pid(), tag, comm, MPI_REQ_PERSISTENT | MPI_REQ_RECV | MPI_REQ_PROBE);
   if (smpi_iprobe_sleep > 0) {
@@ -1072,7 +1098,9 @@ int Request::wait(MPI_Request * request, MPI_Status * status)
       try{
         // this is not a detached send
         kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-        kernel::actor::ActivityWaitSimcall observer{issuer, (*request)->action_.get(), -1};
+        simgrid::smpi::ActorExt* process = smpi_process_remote(simgrid::s4u::Actor::by_pid(issuer->get_pid()));
+        kernel::actor::ActivityWaitSimcall observer{issuer, (*request)->action_.get(), -1,
+                                                    process->call_location()->get_call_location()};
         kernel::actor::simcall_blocking([issuer, &observer] { observer.get_activity()->wait_for(issuer, -1); },
                                         &observer);
       } catch (const CancelException&) {
@@ -1142,7 +1170,9 @@ int Request::waitany(int count, MPI_Request requests[], MPI_Status * status)
       ssize_t i;
       try{
         kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-        kernel::actor::ActivityWaitanySimcall observer{issuer, comms, -1};
+        simgrid::smpi::ActorExt* process = smpi_process_remote(simgrid::s4u::Actor::by_pid(issuer->get_pid()));
+        kernel::actor::ActivityWaitanySimcall observer{issuer, comms, -1,
+                                                       process->call_location()->get_call_location()};
         i = kernel::actor::simcall_blocking(
             [&observer] {
               kernel::activity::ActivityImpl::wait_any_for(observer.get_issuer(), observer.get_activities(),
index 7b33c80..af63fe6 100644 (file)
@@ -97,6 +97,9 @@ int Win::del(Win* win){
   }
   if (win->allocated_)
     xbt_free(win->base_);
+  for (auto m : {win->mut_, win->lock_mut_, win->atomic_mut_})
+    if (m->get_owner() != nullptr)
+      m->unlock();
 
   F2C::free_f(win->f2c_id());
   win->cleanup_attr<Win>();
index 6a0738d..703ae54 100644 (file)
@@ -18,7 +18,7 @@ int main(int argc, char* argv[])
     return 1;
   }
 
-  auto properties = simgrid::s4u::Actor::self()->get_properties();
+  const auto* properties = simgrid::s4u::Actor::self()->get_properties();
   if (properties->find("smpi_replay") == properties->end()) {
     XBT_ERROR("invalid smpireplaymain execution. Please use smpirun -replay instead.");
     return 1;
index 2e94996..194934f 100755 (executable)
@@ -59,6 +59,8 @@ Options:
 
   -version                   # Displays the SimGrid version (human readable)
   -git-version               # Displays the git hash of SimGrid
+  -help                      # Displays this information
+  -help-coll                 # Displays all available collective algorithms
 
 or (deprecated usage):
   $0 [-keep-temps] [-np <numprocs>] [-bandwidth <bytes/sec>] [-latency <secs>] program [program-options]
@@ -240,6 +242,10 @@ while true; do
             usage
             exit 0
             ;;
+        "-help-coll" | "--help-coll")
+            ${WRAPPER} "@SMPIMAIN@" --help-coll
+            exit 0
+            ;;
         "-version" | "--version" | "-v")
             printf '%b\n' "$SIMGRID_VERSION"
             exit 0
index 6e19b61..25e9b52 100644 (file)
@@ -35,7 +35,6 @@ public:
   }
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
-  bool is_visible() const override { return true; }
 };
 void ObjectAccessObserver::serialize(std::stringstream& stream) const
 {
@@ -52,6 +51,7 @@ struct ObjectOwner {
   simgrid::kernel::actor::ActorImpl* owner = nullptr;
   const char* file                         = nullptr;
   int line                                 = -1;
+  int recursive_depth                      = 0;
   explicit ObjectOwner(simgrid::kernel::actor::ActorImpl* o) : owner(o) {}
 };
 
@@ -67,15 +67,14 @@ static ObjectOwner* get_owner(void* object)
 {
   if (owners.empty())
     std::atexit(clean_owners);
-  auto it = owners.find(object);
-  if (it != owners.end())
+  if (auto it = owners.find(object); it != owners.end())
     return it->second;
   auto* o = new ObjectOwner(nullptr);
-  owners.insert({object, o});
+  owners.emplace(object, o);
   return o;
 }
 
-int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line)
+int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line, const char* func)
 {
   sthread_disable();
   auto* self = simgrid::kernel::actor::ActorImpl::self();
@@ -85,10 +84,23 @@ int sthread_access_begin(void* objaddr, const char* objname, const char* file, i
       [self, objaddr, objname, file, line]() -> bool {
         XBT_INFO("%s takes %s", self->get_cname(), objname);
         auto* ownership = get_owner(objaddr);
-        if (ownership->owner != nullptr) {
+        if (ownership->owner == self) {
+          ownership->recursive_depth++;
+          return true;
+        } else if (ownership->owner != nullptr) {
           auto msg = std::string("Unprotected concurent access to ") + objname + ": " + ownership->owner->get_name();
-          if (not xbt_log_no_loc)
+          if (not xbt_log_no_loc) {
             msg += simgrid::xbt::string_printf(" at %s:%d", ownership->file, ownership->line);
+            if (ownership->recursive_depth > 1) {
+              msg += simgrid::xbt::string_printf(" (and %d other locations)", ownership->recursive_depth - 1);
+              if (ownership->recursive_depth != 2)
+                msg += "s";
+            }
+          } else {
+            msg += simgrid::xbt::string_printf(" from %d location", ownership->recursive_depth);
+            if (ownership->recursive_depth != 1)
+              msg += "s";
+          }
           msg += " vs " + self->get_name();
           if (xbt_log_no_loc)
             msg += std::string(" (locations hidden because of --log=no_loc).");
@@ -100,6 +112,7 @@ int sthread_access_begin(void* objaddr, const char* objname, const char* file, i
         ownership->owner = self;
         ownership->file  = file;
         ownership->line  = line;
+        ownership->recursive_depth = 1;
         return true;
       },
       &observer);
@@ -108,7 +121,7 @@ int sthread_access_begin(void* objaddr, const char* objname, const char* file, i
   sthread_enable();
   return true;
 }
-void sthread_access_end(void* objaddr, const char* objname, const char* file, int line)
+void sthread_access_end(void* objaddr, const char* objname, const char* file, int line, const char* func)
 {
   sthread_disable();
   auto* self = simgrid::kernel::actor::ActorImpl::self();
@@ -118,9 +131,12 @@ void sthread_access_end(void* objaddr, const char* objname, const char* file, in
       [self, objaddr, objname]() -> void {
         XBT_INFO("%s releases %s", self->get_cname(), objname);
         auto* ownership = get_owner(objaddr);
-        xbt_assert(ownership->owner == self, "safety check failed: %s is not owner of the object it's releasing.",
-                   self->get_cname());
-        ownership->owner = nullptr;
+        xbt_assert(ownership->owner == self,
+                   "safety check failed: %s is not owner of the object it's releasing. That object owned by %s.",
+                   self->get_cname(), (ownership->owner == nullptr ? "nobody" : ownership->owner->get_cname()));
+        ownership->recursive_depth--;
+        if (ownership->recursive_depth == 0)
+          ownership->owner = nullptr;
       },
       &observer);
   sthread_enable();
index 4d04e09..ad27e3f 100644 (file)
 #include <valgrind/valgrind.h>
 #endif
 
-/* We don't want to intercept pthread within simgrid. Instead we should provide the real implem to simgrid */
+/* We don't want to intercept pthread within SimGrid. Instead we should provide the real implem to SimGrid */
 static int (*raw_pthread_create)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*);
 static int (*raw_pthread_join)(pthread_t, void**);
-static int (*raw_mutex_init)(pthread_mutex_t*, const pthread_mutexattr_t*);
-static int (*raw_mutex_lock)(pthread_mutex_t*);
-static int (*raw_mutex_trylock)(pthread_mutex_t*);
-static int (*raw_mutex_unlock)(pthread_mutex_t*);
-static int (*raw_mutex_destroy)(pthread_mutex_t*);
+static int (*raw_pthread_mutex_init)(pthread_mutex_t*, const pthread_mutexattr_t*);
+static int (*raw_pthread_mutex_lock)(pthread_mutex_t*);
+static int (*raw_pthread_mutex_trylock)(pthread_mutex_t*);
+static int (*raw_pthread_mutex_unlock)(pthread_mutex_t*);
+static int (*raw_pthread_mutex_destroy)(pthread_mutex_t*);
+
+static int (*raw_pthread_mutexattr_init)(pthread_mutexattr_t*);
+static int (*raw_pthread_mutexattr_settype)(pthread_mutexattr_t*, int);
+static int (*raw_pthread_mutexattr_gettype)(const pthread_mutexattr_t*, int*);
+static int (*raw_pthread_mutexattr_getrobust)(const pthread_mutexattr_t*, int*);
+static int (*raw_pthread_mutexattr_setrobust)(pthread_mutexattr_t*, int);
+
+static int (*raw_pthread_barrier_init)(pthread_barrier_t*, const pthread_barrierattr_t*, unsigned int count);
+static int (*raw_pthread_barrier_wait)(pthread_barrier_t*);
+static int (*raw_pthread_barrier_destroy)(pthread_barrier_t*);
+
+static int (*raw_pthread_cond_init)(pthread_cond_t*, const pthread_condattr_t*);
+static int (*raw_pthread_cond_signal)(pthread_cond_t*);
+static int (*raw_pthread_cond_broadcast)(pthread_cond_t*);
+static int (*raw_pthread_cond_wait)(pthread_cond_t*, pthread_mutex_t*);
+static int (*raw_pthread_cond_timedwait)(pthread_cond_t*, pthread_mutex_t*, const struct timespec* abstime);
+static int (*raw_pthread_cond_destroy)(pthread_cond_t*);
 
 static unsigned int (*raw_sleep)(unsigned int);
 static int (*raw_usleep)(useconds_t);
@@ -44,11 +61,28 @@ static void intercepter_init()
 {
   raw_pthread_create = dlsym(RTLD_NEXT, "pthread_create");
   raw_pthread_join   = dlsym(RTLD_NEXT, "pthread_join");
-  raw_mutex_init     = dlsym(RTLD_NEXT, "pthread_mutex_init");
-  raw_mutex_lock     = dlsym(RTLD_NEXT, "pthread_mutex_lock");
-  raw_mutex_trylock  = dlsym(RTLD_NEXT, "pthread_mutex_trylock");
-  raw_mutex_unlock   = dlsym(RTLD_NEXT, "pthread_mutex_unlock");
-  raw_mutex_destroy  = dlsym(RTLD_NEXT, "pthread_mutex_destroy");
+  raw_pthread_mutex_init    = dlsym(RTLD_NEXT, "pthread_mutex_init");
+  raw_pthread_mutex_lock    = dlsym(RTLD_NEXT, "pthread_mutex_lock");
+  raw_pthread_mutex_trylock = dlsym(RTLD_NEXT, "pthread_mutex_trylock");
+  raw_pthread_mutex_unlock  = dlsym(RTLD_NEXT, "pthread_mutex_unlock");
+  raw_pthread_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy");
+
+  raw_pthread_mutexattr_init      = dlsym(RTLD_NEXT, "pthread_mutexattr_init");
+  raw_pthread_mutexattr_settype   = dlsym(RTLD_NEXT, "pthread_mutexattr_settype");
+  raw_pthread_mutexattr_gettype   = dlsym(RTLD_NEXT, "pthread_mutexattr_gettype");
+  raw_pthread_mutexattr_getrobust = dlsym(RTLD_NEXT, "pthread_mutexattr_getrobust");
+  raw_pthread_mutexattr_setrobust = dlsym(RTLD_NEXT, "pthread_mutexattr_setrobust");
+
+  raw_pthread_barrier_init = dlsym(RTLD_NEXT, "raw_pthread_barrier_init");
+  raw_pthread_barrier_wait = dlsym(RTLD_NEXT, "raw_pthread_barrier_wait");
+  raw_pthread_barrier_destroy = dlsym(RTLD_NEXT, "raw_pthread_barrier_destroy");
+
+  raw_pthread_cond_init      = dlsym(RTLD_NEXT, "raw_pthread_cond_init");
+  raw_pthread_cond_signal    = dlsym(RTLD_NEXT, "raw_pthread_cond_signal");
+  raw_pthread_cond_broadcast = dlsym(RTLD_NEXT, "raw_pthread_cond_broadcast");
+  raw_pthread_cond_wait      = dlsym(RTLD_NEXT, "raw_pthread_cond_wait");
+  raw_pthread_cond_timedwait = dlsym(RTLD_NEXT, "raw_pthread_cond_timedwait");
+  raw_pthread_cond_destroy   = dlsym(RTLD_NEXT, "raw_pthread_cond_destroy");
 
   raw_sleep        = dlsym(RTLD_NEXT, "sleep");
   raw_usleep       = dlsym(RTLD_NEXT, "usleep");
@@ -72,178 +106,80 @@ void sthread_disable(void)
 { // Stop intercepting all pthread calls
   sthread_inside_simgrid = 1;
 }
-int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg)
-{
-  if (raw_pthread_create == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_pthread_create(thread, attr, start_routine, arg);
-
-  sthread_disable();
-  int res = sthread_create((sthread_t*)thread, attr, start_routine, arg);
-  sthread_enable();
-  return res;
-}
-int pthread_join(pthread_t thread, void** retval)
-{
-  if (raw_pthread_join == NULL)
-    intercepter_init();
-  if (sthread_inside_simgrid)
-    return raw_pthread_join(thread, retval);
-
-  sthread_disable();
-  int res = sthread_join((sthread_t)thread, retval);
-  sthread_enable();
-  return res;
-}
-
-int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr)
-{
-  if (raw_mutex_init == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_mutex_init(mutex, attr);
-
-  sthread_disable();
-  int res = sthread_mutex_init((sthread_mutex_t*)mutex, attr);
-  sthread_enable();
-  return res;
-}
-
-int pthread_mutex_lock(pthread_mutex_t* mutex)
-{
-  if (raw_mutex_lock == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_mutex_lock(mutex);
-
-  sthread_disable();
-  int res = sthread_mutex_lock((sthread_mutex_t*)mutex);
-  sthread_enable();
-  return res;
-}
-
-int pthread_mutex_trylock(pthread_mutex_t* mutex)
-{
-  if (raw_mutex_trylock == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_mutex_trylock(mutex);
-
-  sthread_disable();
-  int res = sthread_mutex_trylock((sthread_mutex_t*)mutex);
-  sthread_enable();
-  return res;
-}
-
-int pthread_mutex_unlock(pthread_mutex_t* mutex)
-{
-  if (raw_mutex_unlock == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_mutex_unlock(mutex);
-
-  sthread_disable();
-  int res = sthread_mutex_unlock((sthread_mutex_t*)mutex);
-  sthread_enable();
-  return res;
-}
-int pthread_mutex_destroy(pthread_mutex_t* mutex)
-{
-  if (raw_mutex_destroy == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_mutex_destroy(mutex);
-
-  sthread_disable();
-  int res = sthread_mutex_destroy((sthread_mutex_t*)mutex);
-  sthread_enable();
-  return res;
-}
-int sem_init(sem_t* sem, int pshared, unsigned int value)
-{
-  if (raw_sem_init == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_sem_init(sem, pshared, value);
-
-  sthread_disable();
-  int res = sthread_sem_init((sthread_sem_t*)sem, pshared, value);
-  sthread_enable();
-  return res;
-}
-int sem_destroy(sem_t* sem)
-{
-  if (raw_sem_destroy == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_sem_destroy(sem);
-
-  sthread_disable();
-  int res = sthread_sem_destroy((sthread_sem_t*)sem);
-  sthread_enable();
-  return res;
-}
-int sem_post(sem_t* sem)
-{
-  if (raw_sem_post == NULL)
-    intercepter_init();
 
-  if (sthread_inside_simgrid)
-    return raw_sem_post(sem);
-
-  sthread_disable();
-  int res = sthread_sem_post((sthread_sem_t*)sem);
-  sthread_enable();
-  return res;
-}
-int sem_wait(sem_t* sem)
-{
-  if (raw_sem_wait == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_sem_wait(sem);
-
-  sthread_disable();
-  int res = sthread_sem_wait((sthread_sem_t*)sem);
-  sthread_enable();
-  return res;
-}
-int sem_trywait(sem_t* sem)
-{
-  if (raw_sem_trywait == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_sem_trywait(sem);
-
-  sthread_disable();
-  int res = sthread_sem_trywait((sthread_sem_t*)sem);
-  sthread_enable();
-  return res;
-}
-int sem_timedwait(sem_t* sem, const struct timespec* abs_timeout)
-{
-  if (raw_sem_timedwait == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_sem_timedwait(sem, abs_timeout);
-
-  sthread_disable();
-  int res = sthread_sem_timedwait((sthread_sem_t*)sem, abs_timeout);
-  sthread_enable();
-  return res;
-}
+#define _STHREAD_CONCAT(a, b) a##b
+#define intercepted_pthcall(name, raw_params, call_params, sim_params)                                                 \
+  int _STHREAD_CONCAT(pthread_, name) raw_params                                                                       \
+  {                                                                                                                    \
+    if (_STHREAD_CONCAT(raw_pthread_, name) == NULL)                                                                   \
+      intercepter_init();                                                                                              \
+    if (sthread_inside_simgrid)                                                                                        \
+      return _STHREAD_CONCAT(raw_pthread_, name) call_params;                                                          \
+                                                                                                                       \
+    sthread_disable();                                                                                                 \
+    int res = _STHREAD_CONCAT(sthread_, name) sim_params;                                                              \
+    sthread_enable();                                                                                                  \
+    return res;                                                                                                        \
+  }
+
+intercepted_pthcall(mutexattr_init, (pthread_mutexattr_t * attr), (attr), ((sthread_mutexattr_t*)attr));
+intercepted_pthcall(mutexattr_settype, (pthread_mutexattr_t * attr, int type), (attr, type),
+                    ((sthread_mutexattr_t*)attr, type));
+intercepted_pthcall(mutexattr_gettype, (const pthread_mutexattr_t* attr, int* type), (attr, type),
+                    ((sthread_mutexattr_t*)attr, type));
+intercepted_pthcall(mutexattr_setrobust, (pthread_mutexattr_t * attr, int robustness), (attr, robustness),
+                    ((sthread_mutexattr_t*)attr, robustness));
+intercepted_pthcall(mutexattr_getrobust, (const pthread_mutexattr_t* attr, int* robustness), (attr, robustness),
+                    ((sthread_mutexattr_t*)attr, robustness));
+
+intercepted_pthcall(create, (pthread_t * thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg),
+                    (thread, attr, start_routine, arg), ((sthread_t*)thread, attr, start_routine, arg));
+intercepted_pthcall(join, (pthread_t thread, void** retval), (thread, retval), ((sthread_t)thread, retval));
+
+intercepted_pthcall(mutex_init, (pthread_mutex_t * mutex, const pthread_mutexattr_t* attr), (mutex, attr),
+                    ((sthread_mutex_t*)mutex, (sthread_mutexattr_t*)attr));
+intercepted_pthcall(mutex_lock, (pthread_mutex_t * mutex), (mutex), ((sthread_mutex_t*)mutex));
+intercepted_pthcall(mutex_trylock, (pthread_mutex_t * mutex), (mutex), ((sthread_mutex_t*)mutex));
+intercepted_pthcall(mutex_unlock, (pthread_mutex_t * mutex), (mutex), ((sthread_mutex_t*)mutex));
+intercepted_pthcall(mutex_destroy, (pthread_mutex_t * mutex), (mutex), ((sthread_mutex_t*)mutex));
+
+intercepted_pthcall(barrier_init, (pthread_barrier_t * barrier, const pthread_barrierattr_t* attr, unsigned count),
+                    (barrier, attr, count), ((sthread_barrier_t*)barrier, (const sthread_barrierattr_t*)attr, count));
+intercepted_pthcall(barrier_wait, (pthread_barrier_t* barrier),( barrier),((sthread_barrier_t*) barrier));
+intercepted_pthcall(barrier_destroy, (pthread_barrier_t* barrier),( barrier),((sthread_barrier_t*) barrier));
+
+intercepted_pthcall(cond_init, (pthread_cond_t * cond, const pthread_condattr_t* attr), (cond, attr),
+                    ((sthread_cond_t*)cond, (sthread_condattr_t*)attr));
+intercepted_pthcall(cond_signal, (pthread_cond_t * cond), (cond), ((sthread_cond_t*)cond));
+intercepted_pthcall(cond_broadcast, (pthread_cond_t * cond), (cond), ((sthread_cond_t*)cond));
+intercepted_pthcall(cond_wait, (pthread_cond_t * cond, pthread_mutex_t* mutex), (cond, mutex),
+                    ((sthread_cond_t*)cond, (sthread_mutex_t*)mutex));
+intercepted_pthcall(cond_timedwait, (pthread_cond_t * cond, pthread_mutex_t* mutex, const struct timespec* abstime),
+                    (cond, mutex, abstime), ((sthread_cond_t*)cond, (sthread_mutex_t*)mutex, abstime));
+intercepted_pthcall(cond_destroy, (pthread_cond_t * cond), (cond), ((sthread_cond_t*)cond));
+
+#define intercepted_call(rettype, name, raw_params, call_params, sim_params)                                           \
+  rettype name raw_params                                                                                              \
+  {                                                                                                                    \
+    if (_STHREAD_CONCAT(raw_, name) == NULL)                                                                           \
+      intercepter_init();                                                                                              \
+    if (sthread_inside_simgrid)                                                                                        \
+      return _STHREAD_CONCAT(raw_, name) call_params;                                                                  \
+                                                                                                                       \
+    sthread_disable();                                                                                                 \
+    rettype res = _STHREAD_CONCAT(sthread_, name) sim_params;                                                          \
+    sthread_enable();                                                                                                  \
+    return res;                                                                                                        \
+  }
+
+intercepted_call(int, sem_init, (sem_t * sem, int pshared, unsigned int value), (sem, pshared, value),
+                 ((sthread_sem_t*)sem, pshared, value));
+intercepted_call(int, sem_destroy, (sem_t * sem), (sem), ((sthread_sem_t*)sem));
+intercepted_call(int, sem_post, (sem_t * sem), (sem), ((sthread_sem_t*)sem));
+intercepted_call(int, sem_wait, (sem_t * sem), (sem), ((sthread_sem_t*)sem));
+intercepted_call(int, sem_trywait, (sem_t * sem), (sem), ((sthread_sem_t*)sem));
+intercepted_call(int, sem_timedwait, (sem_t * sem, const struct timespec* abs_timeout), (sem, abs_timeout),
+                 ((sthread_sem_t*)sem, abs_timeout));
 
 /* Glibc < 2.31 uses type "struct timezone *" for the second parameter of gettimeofday.
    Other implementations use "void *" instead. */
@@ -255,75 +191,9 @@ int sem_timedwait(sem_t* sem, const struct timespec* abs_timeout)
 #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_disable();
-  int res = sthread_gettimeofday(tv);
-  sthread_enable();
-  return res;
-}
-
-unsigned int sleep(unsigned int seconds)
-{
-  if (raw_sleep == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_sleep(seconds);
-
-  sthread_disable();
-  sthread_sleep(seconds);
-  sthread_enable();
-  return 0;
-}
-
-int usleep(useconds_t usec)
-{
-  if (raw_usleep == NULL)
-    intercepter_init();
-
-  if (sthread_inside_simgrid)
-    return raw_usleep(usec);
-
-  sthread_disable();
-  sthread_sleep(((double)usec) / 1000000.);
-  sthread_enable();
-  return 0;
-}
-
-#if 0
-int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) {
-    *cond = sg_cond_init();
-    return 0;
-}
-
-int pthread_cond_signal(pthread_cond_t *cond) {
-       sg_cond_notify_one(*cond);
-    return 0;
-}
-
-int pthread_cond_broadcast(pthread_cond_t *cond) {
-       sg_cond_notify_all(*cond);
-    return 0;
-}
-
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
-       sg_cond_wait(*cond, *mutex);
-    return 0;
-}
-
-int pthread_cond_destroy(pthread_cond_t *cond) {
-       sg_cond_destroy(*cond);
-    return 0;
-}
-#endif
+intercepted_call(int, gettimeofday, (struct timeval * tv, XBT_ATTRIB_UNUSED TIMEZONE_TYPE* tz), (tv, tz), (tv));
+intercepted_call(unsigned int, sleep, (unsigned int seconds), (seconds), (seconds));
+intercepted_call(int, usleep, (useconds_t usec), (usec), (((double)usec) / 1000000.));
 
 /* Trampoline for the real main() */
 static int (*raw_main)(int, char**, char**);
index 6527968..cf96500 100644 (file)
@@ -31,15 +31,53 @@ typedef unsigned long int sthread_t;
 int sthread_create(sthread_t* thread, const /*pthread_attr_t*/ void* attr, void* (*start_routine)(void*), void* arg);
 int sthread_join(sthread_t thread, void** retval);
 
+typedef struct {
+  unsigned recursive : 1;
+  unsigned errorcheck : 1;
+  unsigned robust : 1;
+} sthread_mutexattr_t;
+
+int sthread_mutexattr_init(sthread_mutexattr_t* attr);
+int sthread_mutexattr_settype(sthread_mutexattr_t* attr, int type);
+int sthread_mutexattr_gettype(const sthread_mutexattr_t* attr, int* type);
+int sthread_mutexattr_getrobust(const sthread_mutexattr_t* attr, int* robustness);
+int sthread_mutexattr_setrobust(sthread_mutexattr_t* attr, int robustness);
+
 typedef struct {
   void* mutex;
 } sthread_mutex_t;
-int sthread_mutex_init(sthread_mutex_t* mutex, const /*pthread_mutexattr_t*/ void* attr);
+int sthread_mutex_init(sthread_mutex_t* mutex, const sthread_mutexattr_t* attr);
 int sthread_mutex_lock(sthread_mutex_t* mutex);
 int sthread_mutex_trylock(sthread_mutex_t* mutex);
 int sthread_mutex_unlock(sthread_mutex_t* mutex);
 int sthread_mutex_destroy(sthread_mutex_t* mutex);
 
+typedef struct {
+  unsigned unused : 1;
+} sthread_barrierattr_t;
+
+typedef struct {
+  void* barrier;
+} sthread_barrier_t;
+int sthread_barrier_init(sthread_barrier_t* barrier, const sthread_barrierattr_t* attr, unsigned count);
+int sthread_barrier_wait(sthread_barrier_t* barrier);
+int sthread_barrier_destroy(sthread_barrier_t* barrier);
+
+typedef struct {
+  unsigned unused : 1;
+} sthread_condattr_t;
+
+typedef struct {
+  void* cond;
+  void* mutex;
+} sthread_cond_t;
+int sthread_cond_init(sthread_cond_t* cond, sthread_condattr_t* attr);
+int sthread_cond_signal(sthread_cond_t* cond);
+int sthread_cond_broadcast(sthread_cond_t* cond);
+int sthread_cond_wait(sthread_cond_t* cond, sthread_mutex_t* mutex);
+int sthread_cond_timedwait(sthread_cond_t* cond, sthread_mutex_t* mutex, const struct timespec* abs_timeout);
+int sthread_cond_destroy(sthread_cond_t* cond);
+
 typedef struct {
   void* sem;
 } sthread_sem_t;
@@ -51,10 +89,11 @@ int sthread_sem_trywait(sthread_sem_t* sem);
 int sthread_sem_timedwait(sthread_sem_t* sem, const struct timespec* abs_timeout);
 
 int sthread_gettimeofday(struct timeval* tv);
-void sthread_sleep(double seconds);
+unsigned int sthread_sleep(double seconds);
+int sthread_usleep(double seconds);
 
-int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line);
-void sthread_access_end(void* objaddr, const char* objname, const char* file, int line);
+int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line, const char* function);
+void sthread_access_end(void* objaddr, const char* objname, const char* file, int line, const char* function);
 
 #if defined(__cplusplus)
 }
index 45ba730..4a92967 100644 (file)
@@ -5,7 +5,12 @@
 
 /* SimGrid's pthread interposer. Actual implementation of the symbols (see the comment in sthread.h) */
 
+#include "simgrid/s4u/Barrier.hpp"
+#include "simgrid/s4u/ConditionVariable.hpp"
 #include "smpi/smpi.h"
+#include "xbt/asserts.h"
+#include "xbt/ex.h"
+#include "xbt/log.h"
 #include "xbt/string.hpp"
 #include <simgrid/actor.h>
 #include <simgrid/s4u/Actor.hpp>
@@ -38,14 +43,36 @@ int sthread_main(int argc, char** argv, char** envp, int (*raw_main)(int, char**
 {
   /* Do not intercept the main when run from SMPI: it will initialize the simulation properly */
   for (int i = 0; envp[i] != nullptr; i++)
-    if (std::string_view(envp[i]).rfind("SMPI_GLOBAL_SIZE", 0) == 0)
+    if (std::string_view(envp[i]).rfind("SMPI_GLOBAL_SIZE", 0) == 0) {
+      printf("sthread refuses to intercept the SMPI application %s directly, as its interception is done otherwise.\n",
+             argv[0]);
       return raw_main(argc, argv, envp);
+    }
+
+  /* Do not intercept system binaries such as valgrind step 1 */
+  std::vector<std::string> binaries = {"/usr/bin/valgrind.bin", "/bin/sh", "/bin/bash", "gdb", "addr2line"};
+  for (int i = 0; envp[i] != nullptr; i++) {
+    auto view = std::string_view(envp[i]);
+    /* If you want to ignore more than one binary, export STHREAD_IGNORE_BINARY1=toto STHREAD_IGNORE_BINARY2=tutu */
+    /* Note that this cannot be configured with --cfg because we are before the main() */
+    if (view.rfind("STHREAD_IGNORE_BINARY", 0) == 0) {
+      view.remove_prefix(std::min(view.rfind("=") + 1, view.size()));
+      binaries.push_back(std::string(view));
+    }
+  }
+  auto binary_view = std::string_view(argv[0]);
+  for (auto binary : binaries) {
+    if (binary_view.rfind(binary) != std::string_view::npos) {
+      printf("sthread refuses to intercept the execution of %s. Running the application unmodified.\n", argv[0]);
+      fflush(stdout);
+      return raw_main(argc, argv, envp);
+    }
+  }
 
   /* If not in SMPI, the old main becomes an actor in a newly created simulation */
-  std::ostringstream id;
-  id << std::this_thread::get_id();
-
-  XBT_DEBUG("sthread main() is starting in thread %s", id.str().c_str());
+  printf("sthread is intercepting the execution of %s. If it's not what you want, export STHREAD_IGNORE_BINARY=%s\n",
+         argv[0], argv[0]);
+  fflush(stdout);
 
   sg4::Engine e(&argc, argv);
   auto* zone = sg4::create_full_zone("world");
@@ -56,7 +83,6 @@ int sthread_main(int argc, char** argv, char** envp, int (*raw_main)(int, char**
   sthread_enable();
   sg4::ActorPtr main_actor = sg4::Actor::create("main thread", lilibeth, raw_main, argc, argv, envp);
 
-  XBT_INFO("Starting the simulation.");
   sg4::Engine::get_instance()->run();
   sthread_disable();
   XBT_INFO("All threads exited. Terminating the simulation.");
@@ -108,9 +134,57 @@ int sthread_join(sthread_t thread, void** /*retval*/)
   return 0;
 }
 
-int sthread_mutex_init(sthread_mutex_t* mutex, const void* /*pthread_mutexattr_t* attr*/)
+int sthread_mutexattr_init(sthread_mutexattr_t* attr)
+{
+  memset(attr, 0, sizeof(*attr));
+  return 0;
+}
+int sthread_mutexattr_settype(sthread_mutexattr_t* attr, int type)
+{
+  switch (type) {
+    case PTHREAD_MUTEX_NORMAL:
+      xbt_assert(not attr->recursive, "S4U does not allow to remove the recursivness of a mutex.");
+      attr->recursive = 0;
+      break;
+    case PTHREAD_MUTEX_RECURSIVE:
+      attr->recursive = 1;
+      attr->errorcheck = 0; // reset
+      break;
+    case PTHREAD_MUTEX_ERRORCHECK:
+      attr->errorcheck = 1;
+      THROW_UNIMPLEMENTED;
+      break;
+    default:
+      THROW_IMPOSSIBLE;
+  }
+  return 0;
+}
+int sthread_mutexattr_gettype(const sthread_mutexattr_t* attr, int* type)
+{
+  if (attr->recursive)
+    *type = PTHREAD_MUTEX_RECURSIVE;
+  else if (attr->errorcheck)
+    *type = PTHREAD_MUTEX_ERRORCHECK;
+  else
+    *type = PTHREAD_MUTEX_NORMAL;
+  return 0;
+}
+int sthread_mutexattr_getrobust(const sthread_mutexattr_t* attr, int* robustness)
+{
+  *robustness = attr->robust;
+  return 0;
+}
+int sthread_mutexattr_setrobust(sthread_mutexattr_t* attr, int robustness)
 {
-  auto m = sg4::Mutex::create();
+  attr->robust = robustness;
+  if (robustness)
+    THROW_UNIMPLEMENTED;
+  return 0;
+}
+
+int sthread_mutex_init(sthread_mutex_t* mutex, const sthread_mutexattr_t* attr)
+{
+  auto m = sg4::Mutex::create(attr != nullptr && attr->recursive);
   intrusive_ptr_add_ref(m.get());
 
   mutex->mutex = m.get();
@@ -123,6 +197,7 @@ int sthread_mutex_lock(sthread_mutex_t* mutex)
   if (mutex->mutex == nullptr)
     sthread_mutex_init(mutex, nullptr);
 
+  XBT_DEBUG("%s(%p)", __func__, mutex);
   static_cast<sg4::Mutex*>(mutex->mutex)->lock();
   return 0;
 }
@@ -133,7 +208,10 @@ int sthread_mutex_trylock(sthread_mutex_t* mutex)
   if (mutex->mutex == nullptr)
     sthread_mutex_init(mutex, nullptr);
 
-  return static_cast<sg4::Mutex*>(mutex->mutex)->try_lock();
+  XBT_DEBUG("%s(%p)", __func__, mutex);
+  if (static_cast<sg4::Mutex*>(mutex->mutex)->try_lock())
+    return 0;
+  return EBUSY;
 }
 
 int sthread_mutex_unlock(sthread_mutex_t* mutex)
@@ -142,6 +220,7 @@ int sthread_mutex_unlock(sthread_mutex_t* mutex)
   if (mutex->mutex == nullptr)
     sthread_mutex_init(mutex, nullptr);
 
+  XBT_DEBUG("%s(%p)", __func__, mutex);
   static_cast<sg4::Mutex*>(mutex->mutex)->unlock();
   return 0;
 }
@@ -151,9 +230,114 @@ int sthread_mutex_destroy(sthread_mutex_t* mutex)
   if (mutex->mutex == nullptr)
     sthread_mutex_init(mutex, nullptr);
 
+  XBT_DEBUG("%s(%p)", __func__, mutex);
   intrusive_ptr_release(static_cast<sg4::Mutex*>(mutex->mutex));
   return 0;
 }
+
+int sthread_barrier_init(sthread_barrier_t* barrier, const sthread_barrierattr_t* attr, unsigned count){
+  auto b = sg4::Barrier::create(count);
+  intrusive_ptr_add_ref(b.get());
+
+  barrier->barrier = b.get();
+  return 0;
+}
+int sthread_barrier_wait(sthread_barrier_t* barrier){
+  XBT_DEBUG("%s(%p)", __func__, barrier);
+  static_cast<sg4::Barrier*>(barrier->barrier)->wait();
+  return 0;
+}
+int sthread_barrier_destroy(sthread_barrier_t* barrier){
+  XBT_DEBUG("%s(%p)", __func__, barrier);
+  intrusive_ptr_release(static_cast<sg4::Barrier*>(barrier->barrier));
+  return 0;
+}
+
+int sthread_cond_init(sthread_cond_t* cond, sthread_condattr_t* attr)
+{
+  auto cv = sg4::ConditionVariable::create();
+  intrusive_ptr_add_ref(cv.get());
+
+  cond->cond = cv.get();
+  cond->mutex = nullptr;
+  return 0;
+}
+int sthread_cond_signal(sthread_cond_t* cond)
+{
+  XBT_DEBUG("%s(%p)", __func__, cond);
+
+  if (cond->mutex == nullptr)
+    XBT_WARN("No mutex was associated so far with condition variable %p. Safety checks skipped.", cond);
+  else {
+    auto* owner = static_cast<sg4::Mutex*>(cond->mutex)->get_owner();
+    if (owner == nullptr)
+      XBT_WARN("The mutex associated to condition %p is not currently owned by anyone when calling "
+               "pthread_cond_signal(). The signal could get lost.",
+               cond);
+    else if (owner != simgrid::s4u::Actor::self())
+      XBT_WARN("The mutex associated to condition %p is currently owned by %s, not by the thread currently calling "
+               "calling pthread_cond_signal(). The signal could get lost.",
+               cond, owner->get_cname());
+  }
+
+  static_cast<sg4::ConditionVariable*>(cond->cond)->notify_one();
+  return 0;
+}
+int sthread_cond_broadcast(sthread_cond_t* cond)
+{
+  XBT_DEBUG("%s(%p)", __func__, cond);
+
+  if (cond->mutex == nullptr)
+    XBT_WARN("No mutex was associated so far with condition variable %p. Safety checks skipped.", cond);
+  else {
+    auto* owner = static_cast<sg4::Mutex*>(cond->mutex)->get_owner();
+    if (owner == nullptr)
+      XBT_WARN("The mutex associated to condition %p is not currently owned by anyone when calling "
+               "pthread_cond_broadcast(). The signal could get lost.",
+               cond);
+    else if (owner != simgrid::s4u::Actor::self())
+      XBT_WARN("The mutex associated to condition %p is currently owned by %s, not by the thread currently calling "
+               "calling pthread_cond_broadcast(). The signal could get lost.",
+               cond, owner->get_cname());
+  }
+
+  static_cast<sg4::ConditionVariable*>(cond->cond)->notify_all();
+  return 0;
+}
+int sthread_cond_wait(sthread_cond_t* cond, sthread_mutex_t* mutex)
+{
+  XBT_DEBUG("%s(%p)", __func__, cond);
+
+  if (cond->mutex == nullptr)
+    cond->mutex = mutex->mutex;
+  else if (cond->mutex != mutex->mutex)
+    XBT_WARN("The condition %p is now waited with mutex %p while it was previoulsy waited with mutex %p. sthread may "
+             "not work with such a dangerous code.",
+             cond, cond->mutex, mutex->mutex);
+
+  static_cast<sg4::ConditionVariable*>(cond->cond)->wait(static_cast<sg4::Mutex*>(mutex->mutex));
+  return 0;
+}
+int sthread_cond_timedwait(sthread_cond_t* cond, sthread_mutex_t* mutex, const struct timespec* abs_timeout)
+{
+  XBT_DEBUG("%s(%p)", __func__, cond);
+
+  if (cond->mutex == nullptr)
+    cond->mutex = mutex->mutex;
+  else if (cond->mutex != mutex->mutex)
+    XBT_WARN("The condition %p is now waited with mutex %p while it was previoulsy waited with mutex %p. sthread may "
+             "not work with such a dangerous code.",
+             cond, cond->mutex, mutex->mutex);
+
+  THROW_UNIMPLEMENTED;
+}
+int sthread_cond_destroy(sthread_cond_t* cond)
+{
+  XBT_DEBUG("%s(%p)", __func__, cond);
+  intrusive_ptr_release(static_cast<sg4::ConditionVariable*>(cond->cond));
+  return 0;
+}
+
 int sthread_sem_init(sthread_sem_t* sem, int /*pshared*/, unsigned int value)
 {
   auto s = sg4::Semaphore::create(value);
@@ -209,34 +393,15 @@ int sthread_gettimeofday(struct timeval* tv)
   return 0;
 }
 
-void sthread_sleep(double seconds)
+unsigned int sthread_sleep(double seconds)
 {
+  XBT_DEBUG("sleep(%lf)", seconds);
   simgrid::s4u::this_actor::sleep_for(seconds);
+  return 0;
 }
-
-#if 0
-int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) {
-    *cond = sg_cond_init();
-    return 0;
-}
-
-int pthread_cond_signal(pthread_cond_t *cond) {
-       sg_cond_notify_one(*cond);
-    return 0;
-}
-
-int pthread_cond_broadcast(pthread_cond_t *cond) {
-       sg_cond_notify_all(*cond);
-    return 0;
-}
-
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
-       sg_cond_wait(*cond, *mutex);
-    return 0;
-}
-
-int pthread_cond_destroy(pthread_cond_t *cond) {
-       sg_cond_destroy(*cond);
-    return 0;
+int sthread_usleep(double seconds)
+{
+  XBT_DEBUG("sleep(%lf)", seconds);
+  simgrid::s4u::this_actor::sleep_for(seconds);
+  return 0;
 }
-#endif
diff --git a/src/xbt/automaton/automaton.c b/src/xbt/automaton/automaton.c
deleted file mode 100644 (file)
index f44bf6d..0000000
+++ /dev/null
@@ -1,417 +0,0 @@
-/* automaton - representation of büchi automaton */
-
-/* Copyright (c) 2011-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "xbt/automaton.h"
-#include <stdio.h> /* printf */
-#include <xbt/sysdep.h>
-
-struct xbt_automaton_propositional_symbol{
-  char* pred;
-  /** Callback used to evaluate the value of the symbol */
-  int (*callback)(void*);
-  /** Additional data for the callback.
-      Alternatively it can be used as a pointer to the data. */
-  void* data;
-  /** Optional callback used to free the data field */
-  void (*free_function)(void*);
-};
-
-xbt_automaton_t xbt_automaton_new(void){
-  xbt_automaton_t automaton = xbt_new0(struct xbt_automaton, 1);
-  automaton->states = xbt_dynar_new(sizeof(xbt_automaton_state_t), xbt_automaton_state_free_voidp);
-  automaton->transitions = xbt_dynar_new(sizeof(xbt_automaton_transition_t), xbt_automaton_transition_free_voidp);
-  automaton->propositional_symbols = xbt_dynar_new(sizeof(xbt_automaton_propositional_symbol_t), xbt_automaton_propositional_symbol_free_voidp);
-  return automaton;
-}
-
-xbt_automaton_state_t xbt_automaton_state_new(const_xbt_automaton_t a, int type, const char* id)
-{
-  xbt_automaton_state_t state = xbt_new0(struct xbt_automaton_state, 1);
-  state->type = type;
-  state->id = xbt_strdup(id);
-  state->in                   = xbt_dynar_new(sizeof(xbt_automaton_transition_t), NULL);
-  state->out                  = xbt_dynar_new(sizeof(xbt_automaton_transition_t), NULL);
-  xbt_dynar_push(a->states, &state);
-  return state;
-}
-
-xbt_automaton_transition_t xbt_automaton_transition_new(const_xbt_automaton_t a, xbt_automaton_state_t src,
-                                                        xbt_automaton_state_t dst, xbt_automaton_exp_label_t label)
-{
-  xbt_automaton_transition_t transition = xbt_new0(struct xbt_automaton_transition, 1);
-  if(src != NULL){
-    xbt_dynar_push(src->out, &transition);
-    transition->src = src;
-  }
-  if(dst != NULL){
-    xbt_dynar_push(dst->in, &transition);
-    transition->dst = dst;
-  }
-  transition->label = label;
-  xbt_dynar_push(a->transitions, &transition);
-  return transition;
-}
-
-xbt_automaton_exp_label_t xbt_automaton_exp_label_new_or(xbt_automaton_exp_label_t left,
-                                                         xbt_automaton_exp_label_t right)
-{
-  xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1);
-  label->type                     = AUT_OR;
-  label->u.or_and.left_exp        = left;
-  label->u.or_and.right_exp       = right;
-  return label;
-}
-
-xbt_automaton_exp_label_t xbt_automaton_exp_label_new_and(xbt_automaton_exp_label_t left,
-                                                          xbt_automaton_exp_label_t right)
-{
-  xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1);
-  label->type                     = AUT_AND;
-  label->u.or_and.left_exp        = left;
-  label->u.or_and.right_exp       = right;
-  return label;
-}
-
-xbt_automaton_exp_label_t xbt_automaton_exp_label_new_not(xbt_automaton_exp_label_t exp_not)
-{
-  xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1);
-  label->type                     = AUT_NOT;
-  label->u.exp_not                = exp_not;
-  return label;
-}
-
-xbt_automaton_exp_label_t xbt_automaton_exp_label_new_predicat(const char* p)
-{
-  xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1);
-  label->type                     = AUT_PREDICAT;
-  label->u.predicat               = xbt_strdup(p);
-  return label;
-}
-
-xbt_automaton_exp_label_t xbt_automaton_exp_label_new_one(void)
-{
-  xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1);
-  label->type                     = AUT_ONE;
-  return label;
-}
-
-xbt_dynar_t xbt_automaton_get_states(const_xbt_automaton_t a)
-{
-  return a->states;
-}
-
-xbt_dynar_t xbt_automaton_get_transitions(const_xbt_automaton_t a)
-{
-  return a->transitions;
-}
-
-xbt_automaton_transition_t xbt_automaton_get_transition(XBT_ATTRIB_UNUSED const_xbt_automaton_t a,
-                                                        const_xbt_automaton_state_t src,
-                                                        const_xbt_automaton_state_t dst)
-{
-  xbt_automaton_transition_t transition;
-  unsigned int cursor;
-  xbt_dynar_foreach(src->out, cursor, transition){
-    if((transition->src == src) && (transition->dst == dst))
-      return transition;
-  }
-  return NULL;
-}
-
-xbt_automaton_state_t xbt_automaton_transition_get_source(const_xbt_automaton_transition_t t)
-{
-  return t->src;
-}
-
-xbt_automaton_state_t xbt_automaton_transition_get_destination(const_xbt_automaton_transition_t t)
-{
-  return t->dst;
-}
-
-void xbt_automaton_transition_set_source(xbt_automaton_transition_t t, xbt_automaton_state_t src){
-  t->src = src;
-  xbt_dynar_push(src->out,&t);
-}
-
-void xbt_automaton_transition_set_destination(xbt_automaton_transition_t t, xbt_automaton_state_t dst){
-  t->dst = dst;
-  xbt_dynar_push(dst->in,&t);
-}
-
-xbt_dynar_t xbt_automaton_state_get_out_transitions(const_xbt_automaton_state_t s)
-{
-  return s->out;
-}
-
-xbt_dynar_t xbt_automaton_state_get_in_transitions(const_xbt_automaton_state_t s)
-{
-  return s->in;
-}
-
-xbt_automaton_state_t xbt_automaton_state_exists(const_xbt_automaton_t a, const char* id)
-{
-  xbt_automaton_state_t state = NULL;
-  unsigned int cursor = 0;
-  xbt_dynar_foreach(a->states, cursor, state){
-   if(strcmp(state->id, id)==0)
-     return state;
-  }
-  return NULL;
-}
-
-void xbt_automaton_display(const_xbt_automaton_t a)
-{
-  unsigned int cursor;
-  xbt_automaton_state_t state = NULL;
-
-  printf("\n\nCurrent state: %s\n", a->current_state->id);
-
-  printf("\nStates' List: %lu\n\n", xbt_dynar_length(a->states));
-
-  xbt_dynar_foreach(a->states, cursor, state)
-    printf("ID: %s, type: %d\n", state->id, state->type);
-
-  xbt_automaton_transition_t transition;
-  printf("\nTransitions: %lu\n\n", xbt_dynar_length(a->transitions));
-
-  xbt_dynar_foreach(a->transitions, cursor, transition){
-    printf("label:");
-    xbt_automaton_exp_label_display(transition->label);
-    printf(", %s -> %s\n", transition->src->id, transition->dst->id);
-  }
-}
-
-void xbt_automaton_exp_label_display(const_xbt_automaton_exp_label_t label)
-{
-  printf("(");
-  switch(label->type){
-    case 0:
-      xbt_automaton_exp_label_display(label->u.or_and.left_exp);
-      printf(" || ");
-      xbt_automaton_exp_label_display(label->u.or_and.right_exp);
-      break;
-    case 1:
-      xbt_automaton_exp_label_display(label->u.or_and.left_exp);
-      printf(" && ");
-      xbt_automaton_exp_label_display(label->u.or_and.right_exp);
-      break;
-    case 2:
-      printf("!");
-      xbt_automaton_exp_label_display(label->u.exp_not);
-      break;
-    case 3:
-      printf("%s", label->u.predicat);
-      break;
-    case 4:
-      printf("1");
-      break;
-    default:
-      break;
-  }
-  printf(")");
-}
-
-xbt_automaton_state_t xbt_automaton_get_current_state(const_xbt_automaton_t a)
-{
-  return a->current_state;
-}
-
-static int call_simple_function(int function(void) )
-{
-  return function();
-}
-
-xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new(const_xbt_automaton_t a, const char* id,
-                                                                            int (*fct)(void))
-{
-  xbt_automaton_propositional_symbol_t prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1);
-  prop_symb->pred = xbt_strdup(id);
-  prop_symb->callback                            = ((int (*)(void *))&call_simple_function);
-  prop_symb->data = (void*)&fct;
-  prop_symb->free_function = NULL;
-  xbt_dynar_push(a->propositional_symbols, &prop_symb);
-  return prop_symb;
-}
-
-XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new_pointer(const_xbt_automaton_t a,
-                                                                                               const char* id,
-                                                                                               int* value)
-{
-  xbt_automaton_propositional_symbol_t prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1);
-  prop_symb->pred = xbt_strdup(id);
-  prop_symb->callback = NULL;
-  prop_symb->data = value;
-  prop_symb->free_function = NULL;
-  xbt_dynar_push(a->propositional_symbols, &prop_symb);
-  return prop_symb;
-}
-
-XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new_callback(
-    const_xbt_automaton_t a, const char* id, xbt_automaton_propositional_symbol_callback_type callback, void* data,
-    xbt_automaton_propositional_symbol_free_function_type free_function)
-{
-  xbt_automaton_propositional_symbol_t prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1);
-  prop_symb->pred = xbt_strdup(id);
-  prop_symb->callback = callback;
-  prop_symb->data = data;
-  prop_symb->free_function = free_function;
-  xbt_dynar_push(a->propositional_symbols, &prop_symb);
-  return prop_symb;
-}
-
-XBT_PUBLIC int xbt_automaton_propositional_symbol_evaluate(const_xbt_automaton_propositional_symbol_t symbol)
-{
-  if (symbol->callback)
-    return (symbol->callback)(symbol->data);
-  else
-    return *(int*) symbol->data;
-}
-
-XBT_PUBLIC xbt_automaton_propositional_symbol_callback_type
-xbt_automaton_propositional_symbol_get_callback(const_xbt_automaton_propositional_symbol_t symbol)
-{
-  return symbol->callback;
-}
-
-XBT_PUBLIC void* xbt_automaton_propositional_symbol_get_data(const_xbt_automaton_propositional_symbol_t symbol)
-{
-  return symbol->data;
-}
-
-XBT_PUBLIC const char* xbt_automaton_propositional_symbol_get_name(const_xbt_automaton_propositional_symbol_t symbol)
-{
-  return symbol->pred;
-}
-
-int xbt_automaton_state_compare(const_xbt_automaton_state_t s1, const_xbt_automaton_state_t s2)
-{
-  /* single id for each state, id and type sufficient for comparison*/
-  return (strcmp(s1->id, s2->id) != 0) || (s1->type != s2->type);
-}
-
-int xbt_automaton_transition_compare(const_xbt_automaton_transition_t t1, const_xbt_automaton_transition_t t2)
-{
-  return xbt_automaton_state_compare(t1->src, t2->src) || xbt_automaton_state_compare(t1->dst, t2->dst) ||
-         xbt_automaton_exp_label_compare(t1->label, t2->label);
-}
-
-int xbt_automaton_exp_label_compare(const_xbt_automaton_exp_label_t l1, const_xbt_automaton_exp_label_t l2)
-{
-  if(l1->type != l2->type)
-    return 1;
-
-  int res;
-  switch(l1->type){
-  case 0 : // OR
-  case 1 : // AND
-    res = xbt_automaton_exp_label_compare(l1->u.or_and.left_exp, l2->u.or_and.left_exp) ||
-          xbt_automaton_exp_label_compare(l1->u.or_and.right_exp, l2->u.or_and.right_exp);
-    break;
-  case 2 : // NOT
-    res = xbt_automaton_exp_label_compare(l1->u.exp_not, l2->u.exp_not);
-    break;
-  case 3 : // predicat
-    res = strcmp(l1->u.predicat, l2->u.predicat) != 0;
-    break;
-  case 4 : // 1
-    res = 0;
-    break;
-  default :
-    res = -1;
-    break;
-  }
-  return res;
-}
-
-int xbt_automaton_propositional_symbols_compare_value(const_xbt_dynar_t s1, const_xbt_dynar_t s2)
-{
-  unsigned long nb_elem = xbt_dynar_length(s1);
-
-  for (unsigned long cursor = 0; cursor < nb_elem; cursor++) {
-    const int* iptr1 = xbt_dynar_get_ptr(s1, cursor);
-    const int* iptr2 = xbt_dynar_get_ptr(s2, cursor);
-    if(*iptr1 != *iptr2)
-      return 1;
-  }
-
-  return 0;
-}
-
-static void xbt_automaton_transition_free(xbt_automaton_transition_t t);
-static void xbt_automaton_exp_label_free(xbt_automaton_exp_label_t e);
-static void xbt_automaton_propositional_symbol_free(xbt_automaton_propositional_symbol_t ps);
-
-void xbt_automaton_state_free(xbt_automaton_state_t s){
-  if (s == NULL)
-    return;
-  xbt_free(s->id);
-  xbt_dynar_free(&(s->in));
-  xbt_dynar_free(&(s->out));
-  xbt_free(s);
-}
-
-void xbt_automaton_state_free_voidp(void *s){
-  xbt_automaton_state_free((xbt_automaton_state_t) * (void **) s);
-}
-
-static void xbt_automaton_transition_free(xbt_automaton_transition_t t){
-  if (t == NULL)
-    return;
-  xbt_automaton_exp_label_free(t->label);
-  xbt_free(t);
-}
-
-void xbt_automaton_transition_free_voidp(void *t){
-  xbt_automaton_transition_free((xbt_automaton_transition_t) * (void **) t);
-}
-
-static void xbt_automaton_exp_label_free(xbt_automaton_exp_label_t e){
-  if (e == NULL)
-    return;
-  switch (e->type) {
-    case AUT_OR:
-    case AUT_AND:
-      xbt_automaton_exp_label_free(e->u.or_and.left_exp);
-      xbt_automaton_exp_label_free(e->u.or_and.right_exp);
-      break;
-    case AUT_NOT:
-      xbt_automaton_exp_label_free(e->u.exp_not);
-      break;
-    case AUT_PREDICAT:
-      xbt_free(e->u.predicat);
-      break;
-    default:
-      break;
-  }
-  xbt_free(e);
-}
-
-void xbt_automaton_exp_label_free_voidp(void *e){
-  xbt_automaton_exp_label_free((xbt_automaton_exp_label_t) * (void **) e);
-}
-
-static void xbt_automaton_propositional_symbol_free(xbt_automaton_propositional_symbol_t ps){
-  if (ps == NULL)
-    return;
-  if (ps->free_function)
-    ps->free_function(ps->data);
-  xbt_free(ps->pred);
-  xbt_free(ps);
-}
-
-void xbt_automaton_propositional_symbol_free_voidp(void *ps){
-  xbt_automaton_propositional_symbol_free((xbt_automaton_propositional_symbol_t) * (void**)ps);
-}
-
-void xbt_automaton_free(xbt_automaton_t a){
-  if (a == NULL)
-    return;
-  xbt_dynar_free(&(a->propositional_symbols));
-  xbt_dynar_free(&(a->transitions));
-  xbt_dynar_free(&(a->states));
-  xbt_free(a);
-}
diff --git a/src/xbt/automaton/automaton_lexer.yy.c b/src/xbt/automaton/automaton_lexer.yy.c
deleted file mode 100644 (file)
index 2138ba4..0000000
+++ /dev/null
@@ -1,2184 +0,0 @@
-#line 2 "automaton_lexer.yy.c"
-
-#line 4 "automaton_lexer.yy.c"
-
-#define  YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define yy_create_buffer xbt_automaton_parser__create_buffer
-#define yy_delete_buffer xbt_automaton_parser__delete_buffer
-#define yy_scan_buffer xbt_automaton_parser__scan_buffer
-#define yy_scan_string xbt_automaton_parser__scan_string
-#define yy_scan_bytes xbt_automaton_parser__scan_bytes
-#define yy_init_buffer xbt_automaton_parser__init_buffer
-#define yy_flush_buffer xbt_automaton_parser__flush_buffer
-#define yy_load_buffer_state xbt_automaton_parser__load_buffer_state
-#define yy_switch_to_buffer xbt_automaton_parser__switch_to_buffer
-#define yypush_buffer_state xbt_automaton_parser_push_buffer_state
-#define yypop_buffer_state xbt_automaton_parser_pop_buffer_state
-#define yyensure_buffer_stack xbt_automaton_parser_ensure_buffer_stack
-#define yy_flex_debug xbt_automaton_parser__flex_debug
-#define yyin xbt_automaton_parser_in
-#define yyleng xbt_automaton_parser_leng
-#define yylex xbt_automaton_parser_lex
-#define yylineno xbt_automaton_parser_lineno
-#define yyout xbt_automaton_parser_out
-#define yyrestart xbt_automaton_parser_restart
-#define yytext xbt_automaton_parser_text
-#define yywrap xbt_automaton_parser_wrap
-#define yyalloc xbt_automaton_parser_alloc
-#define yyrealloc xbt_automaton_parser_realloc
-#define yyfree xbt_automaton_parser_free
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 6
-#define YY_FLEX_SUBMINOR_VERSION 4
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-#ifdef yy_create_buffer
-#define xbt_automaton_parser__create_buffer_ALREADY_DEFINED
-#else
-#define yy_create_buffer xbt_automaton_parser__create_buffer
-#endif
-
-#ifdef yy_delete_buffer
-#define xbt_automaton_parser__delete_buffer_ALREADY_DEFINED
-#else
-#define yy_delete_buffer xbt_automaton_parser__delete_buffer
-#endif
-
-#ifdef yy_scan_buffer
-#define xbt_automaton_parser__scan_buffer_ALREADY_DEFINED
-#else
-#define yy_scan_buffer xbt_automaton_parser__scan_buffer
-#endif
-
-#ifdef yy_scan_string
-#define xbt_automaton_parser__scan_string_ALREADY_DEFINED
-#else
-#define yy_scan_string xbt_automaton_parser__scan_string
-#endif
-
-#ifdef yy_scan_bytes
-#define xbt_automaton_parser__scan_bytes_ALREADY_DEFINED
-#else
-#define yy_scan_bytes xbt_automaton_parser__scan_bytes
-#endif
-
-#ifdef yy_init_buffer
-#define xbt_automaton_parser__init_buffer_ALREADY_DEFINED
-#else
-#define yy_init_buffer xbt_automaton_parser__init_buffer
-#endif
-
-#ifdef yy_flush_buffer
-#define xbt_automaton_parser__flush_buffer_ALREADY_DEFINED
-#else
-#define yy_flush_buffer xbt_automaton_parser__flush_buffer
-#endif
-
-#ifdef yy_load_buffer_state
-#define xbt_automaton_parser__load_buffer_state_ALREADY_DEFINED
-#else
-#define yy_load_buffer_state xbt_automaton_parser__load_buffer_state
-#endif
-
-#ifdef yy_switch_to_buffer
-#define xbt_automaton_parser__switch_to_buffer_ALREADY_DEFINED
-#else
-#define yy_switch_to_buffer xbt_automaton_parser__switch_to_buffer
-#endif
-
-#ifdef yypush_buffer_state
-#define xbt_automaton_parser_push_buffer_state_ALREADY_DEFINED
-#else
-#define yypush_buffer_state xbt_automaton_parser_push_buffer_state
-#endif
-
-#ifdef yypop_buffer_state
-#define xbt_automaton_parser_pop_buffer_state_ALREADY_DEFINED
-#else
-#define yypop_buffer_state xbt_automaton_parser_pop_buffer_state
-#endif
-
-#ifdef yyensure_buffer_stack
-#define xbt_automaton_parser_ensure_buffer_stack_ALREADY_DEFINED
-#else
-#define yyensure_buffer_stack xbt_automaton_parser_ensure_buffer_stack
-#endif
-
-#ifdef yylex
-#define xbt_automaton_parser_lex_ALREADY_DEFINED
-#else
-#define yylex xbt_automaton_parser_lex
-#endif
-
-#ifdef yyrestart
-#define xbt_automaton_parser_restart_ALREADY_DEFINED
-#else
-#define yyrestart xbt_automaton_parser_restart
-#endif
-
-#ifdef yylex_init
-#define xbt_automaton_parser_lex_init_ALREADY_DEFINED
-#else
-#define yylex_init xbt_automaton_parser_lex_init
-#endif
-
-#ifdef yylex_init_extra
-#define xbt_automaton_parser_lex_init_extra_ALREADY_DEFINED
-#else
-#define yylex_init_extra xbt_automaton_parser_lex_init_extra
-#endif
-
-#ifdef yylex_destroy
-#define xbt_automaton_parser_lex_destroy_ALREADY_DEFINED
-#else
-#define yylex_destroy xbt_automaton_parser_lex_destroy
-#endif
-
-#ifdef yyget_debug
-#define xbt_automaton_parser_get_debug_ALREADY_DEFINED
-#else
-#define yyget_debug xbt_automaton_parser_get_debug
-#endif
-
-#ifdef yyset_debug
-#define xbt_automaton_parser_set_debug_ALREADY_DEFINED
-#else
-#define yyset_debug xbt_automaton_parser_set_debug
-#endif
-
-#ifdef yyget_extra
-#define xbt_automaton_parser_get_extra_ALREADY_DEFINED
-#else
-#define yyget_extra xbt_automaton_parser_get_extra
-#endif
-
-#ifdef yyset_extra
-#define xbt_automaton_parser_set_extra_ALREADY_DEFINED
-#else
-#define yyset_extra xbt_automaton_parser_set_extra
-#endif
-
-#ifdef yyget_in
-#define xbt_automaton_parser_get_in_ALREADY_DEFINED
-#else
-#define yyget_in xbt_automaton_parser_get_in
-#endif
-
-#ifdef yyset_in
-#define xbt_automaton_parser_set_in_ALREADY_DEFINED
-#else
-#define yyset_in xbt_automaton_parser_set_in
-#endif
-
-#ifdef yyget_out
-#define xbt_automaton_parser_get_out_ALREADY_DEFINED
-#else
-#define yyget_out xbt_automaton_parser_get_out
-#endif
-
-#ifdef yyset_out
-#define xbt_automaton_parser_set_out_ALREADY_DEFINED
-#else
-#define yyset_out xbt_automaton_parser_set_out
-#endif
-
-#ifdef yyget_leng
-#define xbt_automaton_parser_get_leng_ALREADY_DEFINED
-#else
-#define yyget_leng xbt_automaton_parser_get_leng
-#endif
-
-#ifdef yyget_text
-#define xbt_automaton_parser_get_text_ALREADY_DEFINED
-#else
-#define yyget_text xbt_automaton_parser_get_text
-#endif
-
-#ifdef yyget_lineno
-#define xbt_automaton_parser_get_lineno_ALREADY_DEFINED
-#else
-#define yyget_lineno xbt_automaton_parser_get_lineno
-#endif
-
-#ifdef yyset_lineno
-#define xbt_automaton_parser_set_lineno_ALREADY_DEFINED
-#else
-#define yyset_lineno xbt_automaton_parser_set_lineno
-#endif
-
-#ifdef yywrap
-#define xbt_automaton_parser_wrap_ALREADY_DEFINED
-#else
-#define yywrap xbt_automaton_parser_wrap
-#endif
-
-#ifdef yyalloc
-#define xbt_automaton_parser_alloc_ALREADY_DEFINED
-#else
-#define yyalloc xbt_automaton_parser_alloc
-#endif
-
-#ifdef yyrealloc
-#define xbt_automaton_parser_realloc_ALREADY_DEFINED
-#else
-#define yyrealloc xbt_automaton_parser_realloc
-#endif
-
-#ifdef yyfree
-#define xbt_automaton_parser_free_ALREADY_DEFINED
-#else
-#define yyfree xbt_automaton_parser_free
-#endif
-
-#ifdef yytext
-#define xbt_automaton_parser_text_ALREADY_DEFINED
-#else
-#define yytext xbt_automaton_parser_text
-#endif
-
-#ifdef yyleng
-#define xbt_automaton_parser_leng_ALREADY_DEFINED
-#else
-#define yyleng xbt_automaton_parser_leng
-#endif
-
-#ifdef yyin
-#define xbt_automaton_parser_in_ALREADY_DEFINED
-#else
-#define yyin xbt_automaton_parser_in
-#endif
-
-#ifdef yyout
-#define xbt_automaton_parser_out_ALREADY_DEFINED
-#else
-#define yyout xbt_automaton_parser_out
-#endif
-
-#ifdef yy_flex_debug
-#define xbt_automaton_parser__flex_debug_ALREADY_DEFINED
-#else
-#define yy_flex_debug xbt_automaton_parser__flex_debug
-#endif
-
-#ifdef yylineno
-#define xbt_automaton_parser_lineno_ALREADY_DEFINED
-#else
-#define yylineno xbt_automaton_parser_lineno
-#endif
-
-/* First, we deal with  platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types. 
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t; 
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN               (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN              (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN              (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX               (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX              (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX              (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX              (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX             (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX             (4294967295U)
-#endif
-
-#ifndef SIZE_MAX
-#define SIZE_MAX               (~(size_t)0)
-#endif
-
-#endif /* ! C99 */
-
-#endif /* ! FLEXINT_H */
-
-/* begin standard C++ headers. */
-
-/* TODO: this is always defined, so inline it */
-#define yyconst const
-
-#if defined(__GNUC__) && __GNUC__ >= 3
-#define yynoreturn __attribute__((__noreturn__))
-#else
-#define yynoreturn
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an
- *   integer in range [0..255] for use as an array index.
- */
-#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
-
-/* Enter a start condition.  This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN (yy_start) = 1 + 2 *
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state.  The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START (((yy_start) - 1) / 2)
-#define YYSTATE YY_START
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart( yyin  )
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k.
- * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
- * Ditto for the __ia64__ case accordingly.
- */
-#define YY_BUF_SIZE 32768
-#else
-#define YY_BUF_SIZE 16384
-#endif /* __ia64__ */
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-extern int yyleng;
-
-extern FILE *yyin, *yyout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-    
-    #define YY_LESS_LINENO(n)
-    #define YY_LINENO_REWIND_TO(ptr)
-    
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-        int yyless_macro_arg = (n); \
-        YY_LESS_LINENO(yyless_macro_arg);\
-               *yy_cp = (yy_hold_char); \
-               YY_RESTORE_YY_MORE_OFFSET \
-               (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
-               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
-               } \
-       while ( 0 )
-#define unput(c) yyunput( c, (yytext_ptr)  )
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
-       {
-       FILE *yy_input_file;
-
-       char *yy_ch_buf;                /* input buffer */
-       char *yy_buf_pos;               /* current position in input buffer */
-
-       /* Size of input buffer in bytes, not including room for EOB
-        * characters.
-        */
-       int yy_buf_size;
-
-       /* Number of characters read into yy_ch_buf, not including EOB
-        * characters.
-        */
-       int yy_n_chars;
-
-       /* Whether we "own" the buffer - i.e., we know we created it,
-        * and can realloc() it to grow it, and should free() it to
-        * delete it.
-        */
-       int yy_is_our_buffer;
-
-       /* Whether this is an "interactive" input source; if so, and
-        * if we're using stdio for input, then we want to use getc()
-        * instead of fread(), to make sure we stop fetching input after
-        * each newline.
-        */
-       int yy_is_interactive;
-
-       /* Whether we're considered to be at the beginning of a line.
-        * If so, '^' rules will be active on the next match, otherwise
-        * not.
-        */
-       int yy_at_bol;
-
-    int yy_bs_lineno; /**< The line count. */
-    int yy_bs_column; /**< The column count. */
-
-       /* Whether to try to fill the input buffer when we reach the
-        * end of it.
-        */
-       int yy_fill_buffer;
-
-       int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
-       /* When an EOF's been seen but there's still some text to process
-        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
-        * shouldn't try reading from the input source any more.  We might
-        * still have a bunch of tokens to match, though, because of
-        * possible backing-up.
-        *
-        * When we actually see the EOF, we change the status to "new"
-        * (via yyrestart()), so that the user can continue scanning by
-        * just pointing yyin at a new input file.
-        */
-#define YY_BUFFER_EOF_PENDING 2
-
-       };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* Stack of input buffers. */
-static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
-static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
-                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
-                          : NULL)
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-static int yy_n_chars;         /* number of characters read into yy_ch_buf */
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = NULL;
-static int yy_init = 0;                /* whether we need to initialize */
-static int yy_start = 0;       /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin.  A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void yyrestart ( FILE *input_file  );
-void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer  );
-YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size  );
-void yy_delete_buffer ( YY_BUFFER_STATE b  );
-void yy_flush_buffer ( YY_BUFFER_STATE b  );
-void yypush_buffer_state ( YY_BUFFER_STATE new_buffer  );
-void yypop_buffer_state ( void );
-
-static void yyensure_buffer_stack ( void );
-static void yy_load_buffer_state ( void );
-static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file  );
-#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER )
-
-YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size  );
-YY_BUFFER_STATE yy_scan_string ( const char *yy_str  );
-YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len  );
-
-void *yyalloc ( yy_size_t  );
-void *yyrealloc ( void *, yy_size_t  );
-void yyfree ( void *  );
-
-#define yy_new_buffer yy_create_buffer
-#define yy_set_interactive(is_interactive) \
-       { \
-       if ( ! YY_CURRENT_BUFFER ){ \
-        yyensure_buffer_stack (); \
-               YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer( yyin, YY_BUF_SIZE ); \
-       } \
-       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
-       }
-#define yy_set_bol(at_bol) \
-       { \
-       if ( ! YY_CURRENT_BUFFER ){\
-        yyensure_buffer_stack (); \
-               YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer( yyin, YY_BUF_SIZE ); \
-       } \
-       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
-       }
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-/* Begin user sect3 */
-
-#define xbt_automaton_parser_wrap() (/*CONSTCOND*/1)
-#define YY_SKIP_YYWRAP
-typedef flex_uint8_t YY_CHAR;
-
-FILE *yyin = NULL, *yyout = NULL;
-
-typedef int yy_state_type;
-
-extern int yylineno;
-int yylineno = 1;
-
-extern char *yytext;
-#ifdef yytext_ptr
-#undef yytext_ptr
-#endif
-#define yytext_ptr yytext
-
-static yy_state_type yy_get_previous_state ( void );
-static yy_state_type yy_try_NUL_trans ( yy_state_type current_state  );
-static int yy_get_next_buffer ( void );
-static void yynoreturn yy_fatal_error ( const char* msg  );
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
-       (yytext_ptr) = yy_bp; \
-       yyleng = (int) (yy_cp - yy_bp); \
-       (yy_hold_char) = *yy_cp; \
-       *yy_cp = '\0'; \
-       (yy_c_buf_p) = yy_cp;
-#define YY_NUM_RULES 25
-#define YY_END_OF_BUFFER 26
-/* This struct is not used in this scanner,
-   but its presence is necessary. */
-struct yy_trans_info
-       {
-       flex_int32_t yy_verify;
-       flex_int32_t yy_nxt;
-       };
-static const flex_int16_t yy_accept[54] =
-    {   0,
-        0,    0,   26,   24,   18,   23,    8,   24,   24,    9,
-       10,   24,   24,   20,   14,   12,   13,   22,   22,   22,
-       22,   22,   15,   24,   16,   18,    0,    0,   21,    0,
-        6,    4,    0,    0,   20,   11,   22,    3,   22,    2,
-       22,    7,    0,    0,    0,   19,   22,   22,   17,    5,
-       22,    1,    0
-    } ;
-
-static const YY_CHAR yy_ec[256] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    4,    5,    6,    1,    1,    1,    7,    1,    8,
-        9,   10,    1,    1,   11,   12,   13,   14,   15,   14,
-       14,   14,   14,   14,   14,   14,   14,   16,   17,    1,
-        1,   18,    1,    1,   19,   19,   19,   19,   19,   19,
-       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
-       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
-        1,   20,    1,    1,   21,    1,   19,   19,   19,   19,
-
-       22,   23,   24,   19,   25,   19,   19,   19,   19,   26,
-       27,   19,   19,   28,   19,   29,   19,   30,   19,   19,
-       19,   19,   31,   32,   33,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1
-    } ;
-
-static const YY_CHAR yy_meta[34] =
-    {   0,
-        1,    1,    2,    2,    1,    2,    1,    1,    1,    1,
-        1,    1,    3,    4,    4,    1,    1,    1,    4,    2,
-        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
-        1,    1,    1
-    } ;
-
-static const flex_int16_t yy_base[57] =
-    {   0,
-        0,    0,   89,   90,   32,   90,   90,   34,   81,   90,
-       90,   69,   76,   27,   31,   69,   90,    0,   59,   56,
-       58,   55,   90,   42,   90,   45,   47,    0,    0,    0,
-       90,   90,   52,   43,   49,   90,    0,    0,   44,    0,
-       42,   90,   56,   65,   52,   56,   25,   26,   90,    0,
-       16,    0,   90,   74,   31,   78
-    } ;
-
-static const flex_int16_t yy_def[57] =
-    {   0,
-       53,    1,   53,   53,   53,   53,   53,   54,   53,   53,
-       53,   53,   53,   53,   53,   53,   53,   55,   55,   55,
-       55,   55,   53,   53,   53,   53,   54,   27,   27,   27,
-       53,   53,   56,   53,   53,   53,   55,   55,   55,   55,
-       55,   53,   56,   56,   53,   53,   55,   55,   53,   55,
-       55,   55,    0,   53,   53,   53
-    } ;
-
-static const flex_int16_t yy_nxt[124] =
-    {   0,
-        4,    5,    6,    5,    7,    8,    9,   10,   11,    4,
-       12,    4,   13,   14,   15,   16,   17,    4,   18,    4,
-        4,   18,   19,   20,   21,   22,   18,   18,   18,   18,
-       23,   24,   25,   26,   37,   26,   27,   28,   34,   29,
-       35,   35,   34,   52,   35,   35,   26,   51,   26,   27,
-       28,   50,   29,   27,   44,   44,   46,   46,   44,   44,
-       34,   45,   35,   35,   49,   45,   27,   44,   44,   46,
-       46,   48,   47,   42,   45,   30,   41,   30,   43,   43,
-       40,   43,   39,   38,   36,   33,   32,   31,   53,    3,
-       53,   53,   53,   53,   53,   53,   53,   53,   53,   53,
-
-       53,   53,   53,   53,   53,   53,   53,   53,   53,   53,
-       53,   53,   53,   53,   53,   53,   53,   53,   53,   53,
-       53,   53,   53
-    } ;
-
-static const flex_int16_t yy_chk[124] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    5,   55,    5,    8,    8,   14,    8,
-       14,   14,   15,   51,   15,   15,   26,   48,   26,   27,
-       27,   47,   27,    8,   33,   33,   34,   34,   43,   43,
-       35,   33,   35,   35,   45,   43,   27,   44,   44,   46,
-       46,   41,   39,   24,   44,   54,   22,   54,   56,   56,
-       21,   56,   20,   19,   16,   13,   12,    9,    3,   53,
-       53,   53,   53,   53,   53,   53,   53,   53,   53,   53,
-
-       53,   53,   53,   53,   53,   53,   53,   53,   53,   53,
-       53,   53,   53,   53,   53,   53,   53,   53,   53,   53,
-       53,   53,   53
-    } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-extern int yy_flex_debug;
-int yy_flex_debug = 0;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
-#line 1 "parserPromela.lex"
-/* Copyright (c) 2012-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-#line 10 "parserPromela.lex"
-
-#include "simgrid/config.h"
-#if !HAVE_UNISTD_H
-#define YY_NO_UNISTD_H /* hello Windows */
-#endif
-
-#include <stdio.h>
-#include "parserPromela.tab.hacc"
-
-  extern YYSTYPE yylval;
-
-#line 764 "automaton_lexer.yy.c"
-#line 765 "automaton_lexer.yy.c"
-
-#define INITIAL 0
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-static int yy_init_globals ( void );
-
-/* Accessor methods to globals.
-   These are made visible to non-reentrant scanners for convenience. */
-
-int yylex_destroy ( void );
-
-int yyget_debug ( void );
-
-void yyset_debug ( int debug_flag  );
-
-YY_EXTRA_TYPE yyget_extra ( void );
-
-void yyset_extra ( YY_EXTRA_TYPE user_defined  );
-
-FILE *yyget_in ( void );
-
-void yyset_in  ( FILE * _in_str  );
-
-FILE *yyget_out ( void );
-
-void yyset_out  ( FILE * _out_str  );
-
-                       int yyget_leng ( void );
-
-char *yyget_text ( void );
-
-int yyget_lineno ( void );
-
-void yyset_lineno ( int _line_number  );
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap ( void );
-#else
-extern int yywrap ( void );
-#endif
-#endif
-
-#ifndef YY_NO_UNPUT
-    
-    static void yyunput ( int c, char *buf_ptr  );
-    
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy ( char *, const char *, int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen ( const char * );
-#endif
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-static int yyinput ( void );
-#else
-static int input ( void );
-#endif
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k */
-#define YY_READ_BUF_SIZE 16384
-#else
-#define YY_READ_BUF_SIZE 8192
-#endif /* __ia64__ */
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
-#endif
-
-/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
-               { \
-               int c = '*'; \
-               int n; \
-               for ( n = 0; n < max_size && \
-                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
-                       buf[n] = (char) c; \
-               if ( c == '\n' ) \
-                       buf[n++] = (char) c; \
-               if ( c == EOF && ferror( yyin ) ) \
-                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
-               result = n; \
-               } \
-       else \
-               { \
-               errno=0; \
-               while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
-                       { \
-                       if( errno != EINTR) \
-                               { \
-                               YY_FATAL_ERROR( "input in flex scanner failed" ); \
-                               break; \
-                               } \
-                       errno=0; \
-                       clearerr(yyin); \
-                       } \
-               }\
-\
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* end tables serialization structures and prototypes */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK /*LINTED*/break;
-#endif
-
-#define YY_RULE_SETUP \
-       YY_USER_ACTION
-
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
-       yy_state_type yy_current_state;
-       char *yy_cp, *yy_bp;
-       int yy_act;
-    
-       if ( !(yy_init) )
-               {
-               (yy_init) = 1;
-
-#ifdef YY_USER_INIT
-               YY_USER_INIT;
-#endif
-
-               if ( ! (yy_start) )
-                       (yy_start) = 1; /* first start state */
-
-               if ( ! yyin )
-                       yyin = stdin;
-
-               if ( ! yyout )
-                       yyout = stdout;
-
-               if ( ! YY_CURRENT_BUFFER ) {
-                       yyensure_buffer_stack ();
-                       YY_CURRENT_BUFFER_LVALUE =
-                               yy_create_buffer( yyin, YY_BUF_SIZE );
-               }
-
-               yy_load_buffer_state(  );
-               }
-
-       {
-#line 38 "parserPromela.lex"
-
-
-#line 985 "automaton_lexer.yy.c"
-
-       while ( /*CONSTCOND*/1 )                /* loops until end-of-file is reached */
-               {
-               yy_cp = (yy_c_buf_p);
-
-               /* Support of yytext. */
-               *yy_cp = (yy_hold_char);
-
-               /* yy_bp points to the position in yy_ch_buf of the start of
-                * the current run.
-                */
-               yy_bp = yy_cp;
-
-               yy_current_state = (yy_start);
-yy_match:
-               do
-                       {
-                       YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
-                       if ( yy_accept[yy_current_state] )
-                               {
-                               (yy_last_accepting_state) = yy_current_state;
-                               (yy_last_accepting_cpos) = yy_cp;
-                               }
-                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-                               {
-                               yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 54 )
-                                       yy_c = yy_meta[yy_c];
-                               }
-                       yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
-                       ++yy_cp;
-                       }
-               while ( yy_base[yy_current_state] != 90 );
-
-yy_find_action:
-               yy_act = yy_accept[yy_current_state];
-               if ( yy_act == 0 )
-                       { /* have to back up */
-                       yy_cp = (yy_last_accepting_cpos);
-                       yy_current_state = (yy_last_accepting_state);
-                       yy_act = yy_accept[yy_current_state];
-                       }
-
-               YY_DO_BEFORE_ACTION;
-
-do_action:     /* This label is used only to access EOF actions. */
-
-               switch ( yy_act )
-       { /* beginning of action switch */
-                       case 0: /* must back up */
-                       /* undo the effects of YY_DO_BEFORE_ACTION */
-                       *yy_cp = (yy_hold_char);
-                       yy_cp = (yy_last_accepting_cpos);
-                       yy_current_state = (yy_last_accepting_state);
-                       goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 40 "parserPromela.lex"
-{ return (NEVER); }
-       YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 41 "parserPromela.lex"
-{ return (IF); }
-       YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 42 "parserPromela.lex"
-{ return (FI); }
-       YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 43 "parserPromela.lex"
-{ return (IMPLIES); }
-       YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 44 "parserPromela.lex"
-{ return (GOTO); }
-       YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 45 "parserPromela.lex"
-{ return (AND); }
-       YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 46 "parserPromela.lex"
-{ return (OR); }
-       YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 47 "parserPromela.lex"
-{ return (NOT); }
-       YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 48 "parserPromela.lex"
-{ return (LEFT_PAR); }
-       YY_BREAK
-case 10:
-YY_RULE_SETUP
-#line 49 "parserPromela.lex"
-{ return (RIGHT_PAR); }
-       YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 50 "parserPromela.lex"
-{ return (CASE); }
-       YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 51 "parserPromela.lex"
-{ return (COLON); }
-       YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 52 "parserPromela.lex"
-{ return (SEMI_COLON); }
-       YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 53 "parserPromela.lex"
-{ return (CASE_TRUE); }
-       YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 54 "parserPromela.lex"
-{ return (LEFT_BRACE); }
-       YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 55 "parserPromela.lex"
-{ return (RIGHT_BRACE); }
-       YY_BREAK
-case 17:
-/* rule 17 can match eol */
-YY_RULE_SETUP
-#line 58 "parserPromela.lex"
-{ }
-       YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 60 "parserPromela.lex"
-{ }
-       YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 63 "parserPromela.lex"
-{ sscanf(yytext,"%lf",&yylval.real);
-                            return (LITT_REEL); }
-       YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 66 "parserPromela.lex"
-{ sscanf(yytext,"%d",&yylval.integer);
-                            return (LITT_ENT); }
-       YY_BREAK
-case 21:
-/* rule 21 can match eol */
-YY_RULE_SETUP
-#line 69 "parserPromela.lex"
-{ yylval.string=(char *)malloc(strlen(yytext)+1);
-                            sscanf(yytext,"%s",yylval.string);
-                            return (LITT_CHAINE); }
-       YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 73 "parserPromela.lex"
-{ yylval.string=(char *)malloc(strlen(yytext)+1);
-                            sscanf(yytext,"%s",yylval.string);
-                                             return (ID); }
-       YY_BREAK
-case 23:
-/* rule 23 can match eol */
-YY_RULE_SETUP
-#line 77 "parserPromela.lex"
-{ }
-       YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 79 "parserPromela.lex"
-{ }
-       YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 81 "parserPromela.lex"
-ECHO;
-       YY_BREAK
-#line 1176 "automaton_lexer.yy.c"
-case YY_STATE_EOF(INITIAL):
-       yyterminate();
-
-       case YY_END_OF_BUFFER:
-               {
-               /* Amount of text matched not including the EOB char. */
-               int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
-
-               /* Undo the effects of YY_DO_BEFORE_ACTION. */
-               *yy_cp = (yy_hold_char);
-               YY_RESTORE_YY_MORE_OFFSET
-
-               if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
-                       {
-                       /* We're scanning a new file or input source.  It's
-                        * possible that this happened because the user
-                        * just pointed yyin at a new source and called
-                        * yylex().  If so, then we have to assure
-                        * consistency between YY_CURRENT_BUFFER and our
-                        * globals.  Here is the right place to do so, because
-                        * this is the first action (other than possibly a
-                        * back-up) that will match for the new input source.
-                        */
-                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
-                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
-                       }
-
-               /* Note that here we test for yy_c_buf_p "<=" to the position
-                * of the first EOB in the buffer, since yy_c_buf_p will
-                * already have been incremented past the NUL character
-                * (since all states make transitions on EOB to the
-                * end-of-buffer state).  Contrast this with the test
-                * in input().
-                */
-               if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
-                       { /* This was really a NUL. */
-                       yy_state_type yy_next_state;
-
-                       (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
-
-                       yy_current_state = yy_get_previous_state(  );
-
-                       /* Okay, we're now positioned to make the NUL
-                        * transition.  We couldn't have
-                        * yy_get_previous_state() go ahead and do it
-                        * for us because it doesn't know how to deal
-                        * with the possibility of jamming (and we don't
-                        * want to build jamming into it because then it
-                        * will run more slowly).
-                        */
-
-                       yy_next_state = yy_try_NUL_trans( yy_current_state );
-
-                       yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-
-                       if ( yy_next_state )
-                               {
-                               /* Consume the NUL. */
-                               yy_cp = ++(yy_c_buf_p);
-                               yy_current_state = yy_next_state;
-                               goto yy_match;
-                               }
-
-                       else
-                               {
-                               yy_cp = (yy_c_buf_p);
-                               goto yy_find_action;
-                               }
-                       }
-
-               else switch ( yy_get_next_buffer(  ) )
-                       {
-                       case EOB_ACT_END_OF_FILE:
-                               {
-                               (yy_did_buffer_switch_on_eof) = 0;
-
-                               if ( yywrap(  ) )
-                                       {
-                                       /* Note: because we've taken care in
-                                        * yy_get_next_buffer() to have set up
-                                        * yytext, we can now set up
-                                        * yy_c_buf_p so that if some total
-                                        * hoser (like flex itself) wants to
-                                        * call the scanner after we return the
-                                        * YY_NULL, it'll still work - another
-                                        * YY_NULL will get returned.
-                                        */
-                                       (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
-
-                                       yy_act = YY_STATE_EOF(YY_START);
-                                       goto do_action;
-                                       }
-
-                               else
-                                       {
-                                       if ( ! (yy_did_buffer_switch_on_eof) )
-                                               YY_NEW_FILE;
-                                       }
-                               break;
-                               }
-
-                       case EOB_ACT_CONTINUE_SCAN:
-                               (yy_c_buf_p) =
-                                       (yytext_ptr) + yy_amount_of_matched_text;
-
-                               yy_current_state = yy_get_previous_state(  );
-
-                               yy_cp = (yy_c_buf_p);
-                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-                               goto yy_match;
-
-                       case EOB_ACT_LAST_MATCH:
-                               (yy_c_buf_p) =
-                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
-
-                               yy_current_state = yy_get_previous_state(  );
-
-                               yy_cp = (yy_c_buf_p);
-                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-                               goto yy_find_action;
-                       }
-               break;
-               }
-
-       default:
-               YY_FATAL_ERROR(
-                       "fatal flex scanner internal error--no action found" );
-       } /* end of action switch */
-               } /* end of scanning one token */
-       } /* end of user's declarations */
-} /* end of yylex */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- *     EOB_ACT_LAST_MATCH -
- *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- *     EOB_ACT_END_OF_FILE - end of file
- */
-static int yy_get_next_buffer (void)
-{
-       char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
-       char *source = (yytext_ptr);
-       int number_to_move, i;
-       int ret_val;
-
-       if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
-               YY_FATAL_ERROR(
-               "fatal flex scanner internal error--end of buffer missed" );
-
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
-               { /* Don't try to fill the buffer, so this is an EOF. */
-               if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
-                       {
-                       /* We matched a single character, the EOB, so
-                        * treat this as a final EOF.
-                        */
-                       return EOB_ACT_END_OF_FILE;
-                       }
-
-               else
-                       {
-                       /* We matched some text prior to the EOB, first
-                        * process it.
-                        */
-                       return EOB_ACT_LAST_MATCH;
-                       }
-               }
-
-       /* Try to read more data. */
-
-       /* First move last chars to start of buffer. */
-       number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
-
-       for ( i = 0; i < number_to_move; ++i )
-               *(dest++) = *(source++);
-
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
-               /* don't do the read, it's not guaranteed to return an EOF,
-                * just force an EOF
-                */
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
-
-       else
-               {
-                       int num_to_read =
-                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
-               while ( num_to_read <= 0 )
-                       { /* Not enough room in the buffer - grow it. */
-
-                       /* just a shorter name for the current buffer */
-                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
-
-                       int yy_c_buf_p_offset =
-                               (int) ((yy_c_buf_p) - b->yy_ch_buf);
-
-                       if ( b->yy_is_our_buffer )
-                               {
-                               int new_size = b->yy_buf_size * 2;
-
-                               if ( new_size <= 0 )
-                                       b->yy_buf_size += b->yy_buf_size / 8;
-                               else
-                                       b->yy_buf_size *= 2;
-
-                               b->yy_ch_buf = (char *)
-                                       /* Include room in for 2 EOB chars. */
-                                       yyrealloc( (void *) b->yy_ch_buf,
-                                                        (yy_size_t) (b->yy_buf_size + 2)  );
-                               }
-                       else
-                               /* Can't grow it, we don't own it. */
-                               b->yy_ch_buf = NULL;
-
-                       if ( ! b->yy_ch_buf )
-                               YY_FATAL_ERROR(
-                               "fatal error - scanner input buffer overflow" );
-
-                       (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
-
-                       num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
-                                               number_to_move - 1;
-
-                       }
-
-               if ( num_to_read > YY_READ_BUF_SIZE )
-                       num_to_read = YY_READ_BUF_SIZE;
-
-               /* Read in more data. */
-               YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
-                       (yy_n_chars), num_to_read );
-
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-               }
-
-       if ( (yy_n_chars) == 0 )
-               {
-               if ( number_to_move == YY_MORE_ADJ )
-                       {
-                       ret_val = EOB_ACT_END_OF_FILE;
-                       yyrestart( yyin  );
-                       }
-
-               else
-                       {
-                       ret_val = EOB_ACT_LAST_MATCH;
-                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
-                               YY_BUFFER_EOF_PENDING;
-                       }
-               }
-
-       else
-               ret_val = EOB_ACT_CONTINUE_SCAN;
-
-       if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
-               /* Extend the array by 50%, plus the number we really need. */
-               int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
-               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
-                       (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size  );
-               if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
-                       YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
-               /* "- 2" to take care of EOB's */
-               YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
-       }
-
-       (yy_n_chars) += number_to_move;
-       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
-       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
-
-       (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
-       return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-    static yy_state_type yy_get_previous_state (void)
-{
-       yy_state_type yy_current_state;
-       char *yy_cp;
-    
-       yy_current_state = (yy_start);
-
-       for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
-               {
-               YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
-               if ( yy_accept[yy_current_state] )
-                       {
-                       (yy_last_accepting_state) = yy_current_state;
-                       (yy_last_accepting_cpos) = yy_cp;
-                       }
-               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-                       {
-                       yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 54 )
-                               yy_c = yy_meta[yy_c];
-                       }
-               yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
-               }
-
-       return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- *     next_state = yy_try_NUL_trans( current_state );
- */
-    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
-{
-       int yy_is_jam;
-       char *yy_cp = (yy_c_buf_p);
-
-       YY_CHAR yy_c = 1;
-       if ( yy_accept[yy_current_state] )
-               {
-               (yy_last_accepting_state) = yy_current_state;
-               (yy_last_accepting_cpos) = yy_cp;
-               }
-       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-               {
-               yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 54 )
-                       yy_c = yy_meta[yy_c];
-               }
-       yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
-       yy_is_jam = (yy_current_state == 53);
-
-               return yy_is_jam ? 0 : yy_current_state;
-}
-
-#ifndef YY_NO_UNPUT
-
-    static void yyunput (int c, char * yy_bp )
-{
-       char *yy_cp;
-    
-    yy_cp = (yy_c_buf_p);
-
-       /* undo effects of setting up yytext */
-       *yy_cp = (yy_hold_char);
-
-       if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
-               { /* need to shift things up to make room */
-               /* +2 for EOB chars. */
-               int number_to_move = (yy_n_chars) + 2;
-               char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
-                                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
-               char *source =
-                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
-
-               while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
-                       *--dest = *--source;
-
-               yy_cp += (int) (dest - source);
-               yy_bp += (int) (dest - source);
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
-                       (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
-
-               if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
-                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
-               }
-
-       *--yy_cp = (char) c;
-
-       (yytext_ptr) = yy_bp;
-       (yy_hold_char) = *yy_cp;
-       (yy_c_buf_p) = yy_cp;
-}
-
-#endif
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-    static int yyinput (void)
-#else
-    static int input  (void)
-#endif
-
-{
-       int c;
-    
-       *(yy_c_buf_p) = (yy_hold_char);
-
-       if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
-               {
-               /* yy_c_buf_p now points to the character we want to return.
-                * If this occurs *before* the EOB characters, then it's a
-                * valid NUL; if not, then we've hit the end of the buffer.
-                */
-               if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
-                       /* This was really a NUL. */
-                       *(yy_c_buf_p) = '\0';
-
-               else
-                       { /* need more input */
-                       int offset = (int) ((yy_c_buf_p) - (yytext_ptr));
-                       ++(yy_c_buf_p);
-
-                       switch ( yy_get_next_buffer(  ) )
-                               {
-                               case EOB_ACT_LAST_MATCH:
-                                       /* This happens because yy_g_n_b()
-                                        * sees that we've accumulated a
-                                        * token and flags that we need to
-                                        * try matching the token before
-                                        * proceeding.  But for input(),
-                                        * there's no matching to consider.
-                                        * So convert the EOB_ACT_LAST_MATCH
-                                        * to EOB_ACT_END_OF_FILE.
-                                        */
-
-                                       /* Reset buffer status. */
-                                       yyrestart( yyin );
-
-                                       /*FALLTHROUGH*/
-
-                               case EOB_ACT_END_OF_FILE:
-                                       {
-                                       if ( yywrap(  ) )
-                                               return 0;
-
-                                       if ( ! (yy_did_buffer_switch_on_eof) )
-                                               YY_NEW_FILE;
-#ifdef __cplusplus
-                                       return yyinput();
-#else
-                                       return input();
-#endif
-                                       }
-
-                               case EOB_ACT_CONTINUE_SCAN:
-                                       (yy_c_buf_p) = (yytext_ptr) + offset;
-                                       break;
-                               }
-                       }
-               }
-
-       c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
-       *(yy_c_buf_p) = '\0';   /* preserve yytext */
-       (yy_hold_char) = *++(yy_c_buf_p);
-
-       return c;
-}
-#endif /* ifndef YY_NO_INPUT */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- * 
- * @note This function does not reset the start condition to @c INITIAL .
- */
-    void yyrestart  (FILE * input_file )
-{
-    
-       if ( ! YY_CURRENT_BUFFER ){
-        yyensure_buffer_stack ();
-               YY_CURRENT_BUFFER_LVALUE =
-            yy_create_buffer( yyin, YY_BUF_SIZE );
-       }
-
-       yy_init_buffer( YY_CURRENT_BUFFER, input_file );
-       yy_load_buffer_state(  );
-}
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- * 
- */
-    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
-{
-    
-       /* TODO. We should be able to replace this entire function body
-        * with
-        *              yypop_buffer_state();
-        *              yypush_buffer_state(new_buffer);
-     */
-       yyensure_buffer_stack ();
-       if ( YY_CURRENT_BUFFER == new_buffer )
-               return;
-
-       if ( YY_CURRENT_BUFFER )
-               {
-               /* Flush out information for old buffer. */
-               *(yy_c_buf_p) = (yy_hold_char);
-               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-               }
-
-       YY_CURRENT_BUFFER_LVALUE = new_buffer;
-       yy_load_buffer_state(  );
-
-       /* We don't actually know whether we did this switch during
-        * EOF (yywrap()) processing, but the only time this flag
-        * is looked at is after yywrap() is called, so it's safe
-        * to go ahead and always set it.
-        */
-       (yy_did_buffer_switch_on_eof) = 1;
-}
-
-static void yy_load_buffer_state  (void)
-{
-       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-       (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
-       yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
-       (yy_hold_char) = *(yy_c_buf_p);
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- * 
- * @return the allocated buffer state.
- */
-    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
-{
-       YY_BUFFER_STATE b;
-    
-       b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state )  );
-       if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-       b->yy_buf_size = size;
-
-       /* yy_ch_buf has to be 2 characters longer than the size given because
-        * we need to put in 2 end-of-buffer characters.
-        */
-       b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2)  );
-       if ( ! b->yy_ch_buf )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-       b->yy_is_our_buffer = 1;
-
-       yy_init_buffer( b, file );
-
-       return b;
-}
-
-/** Destroy the buffer.
- * @param b a buffer created with yy_create_buffer()
- * 
- */
-    void yy_delete_buffer (YY_BUFFER_STATE  b )
-{
-    
-       if ( ! b )
-               return;
-
-       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
-               YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
-       if ( b->yy_is_our_buffer )
-               yyfree( (void *) b->yy_ch_buf  );
-
-       yyfree( (void *) b  );
-}
-
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a yyrestart() or at EOF.
- */
-    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
-
-{
-       int oerrno = errno;
-    
-       yy_flush_buffer( b );
-
-       b->yy_input_file = file;
-       b->yy_fill_buffer = 1;
-
-    /* If b is the current buffer, then yy_init_buffer was _probably_
-     * called from yyrestart() or through yy_get_next_buffer.
-     * In that case, we don't want to reset the lineno or column.
-     */
-    if (b != YY_CURRENT_BUFFER){
-        b->yy_bs_lineno = 1;
-        b->yy_bs_column = 0;
-    }
-
-        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-    
-       errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- * 
- */
-    void yy_flush_buffer (YY_BUFFER_STATE  b )
-{
-       if ( ! b )
-               return;
-
-       b->yy_n_chars = 0;
-
-       /* We always need two end-of-buffer characters.  The first causes
-        * a transition to the end-of-buffer state.  The second causes
-        * a jam in that state.
-        */
-       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
-       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
-       b->yy_buf_pos = &b->yy_ch_buf[0];
-
-       b->yy_at_bol = 1;
-       b->yy_buffer_status = YY_BUFFER_NEW;
-
-       if ( b == YY_CURRENT_BUFFER )
-               yy_load_buffer_state(  );
-}
-
-/** Pushes the new state onto the stack. The new state becomes
- *  the current state. This function will allocate the stack
- *  if necessary.
- *  @param new_buffer The new state.
- *  
- */
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
-{
-       if (new_buffer == NULL)
-               return;
-
-       yyensure_buffer_stack();
-
-       /* This block is copied from yy_switch_to_buffer. */
-       if ( YY_CURRENT_BUFFER )
-               {
-               /* Flush out information for old buffer. */
-               *(yy_c_buf_p) = (yy_hold_char);
-               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-               }
-
-       /* Only push if top exists. Otherwise, replace top. */
-       if (YY_CURRENT_BUFFER)
-               (yy_buffer_stack_top)++;
-       YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
-       /* copied from yy_switch_to_buffer. */
-       yy_load_buffer_state(  );
-       (yy_did_buffer_switch_on_eof) = 1;
-}
-
-/** Removes and deletes the top of the stack, if present.
- *  The next element becomes the new top.
- *  
- */
-void yypop_buffer_state (void)
-{
-       if (!YY_CURRENT_BUFFER)
-               return;
-
-       yy_delete_buffer(YY_CURRENT_BUFFER );
-       YY_CURRENT_BUFFER_LVALUE = NULL;
-       if ((yy_buffer_stack_top) > 0)
-               --(yy_buffer_stack_top);
-
-       if (YY_CURRENT_BUFFER) {
-               yy_load_buffer_state(  );
-               (yy_did_buffer_switch_on_eof) = 1;
-       }
-}
-
-/* Allocates the stack if it does not exist.
- *  Guarantees space for at least one push.
- */
-static void yyensure_buffer_stack (void)
-{
-       yy_size_t num_to_alloc;
-    
-       if (!(yy_buffer_stack)) {
-
-               /* First allocation is just for 2 elements, since we don't know if this
-                * scanner will even need a stack. We use 2 instead of 1 to avoid an
-                * immediate realloc on the next call.
-         */
-      num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
-               (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
-                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
-                                                               );
-               if ( ! (yy_buffer_stack) )
-                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
-               memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
-               (yy_buffer_stack_max) = num_to_alloc;
-               (yy_buffer_stack_top) = 0;
-               return;
-       }
-
-       if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
-
-               /* Increase the buffer to prepare for a possible push. */
-               yy_size_t grow_size = 8 /* arbitrary grow size */;
-
-               num_to_alloc = (yy_buffer_stack_max) + grow_size;
-               (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
-                                                               ((yy_buffer_stack),
-                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
-                                                               );
-               if ( ! (yy_buffer_stack) )
-                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
-               /* zero only the new slots.*/
-               memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
-               (yy_buffer_stack_max) = num_to_alloc;
-       }
-}
-
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- * 
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
-{
-       YY_BUFFER_STATE b;
-    
-       if ( size < 2 ||
-            base[size-2] != YY_END_OF_BUFFER_CHAR ||
-            base[size-1] != YY_END_OF_BUFFER_CHAR )
-               /* They forgot to leave room for the EOB's. */
-               return NULL;
-
-       b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state )  );
-       if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
-       b->yy_buf_size = (int) (size - 2);      /* "- 2" to take care of EOB's */
-       b->yy_buf_pos = b->yy_ch_buf = base;
-       b->yy_is_our_buffer = 0;
-       b->yy_input_file = NULL;
-       b->yy_n_chars = b->yy_buf_size;
-       b->yy_is_interactive = 0;
-       b->yy_at_bol = 1;
-       b->yy_fill_buffer = 0;
-       b->yy_buffer_status = YY_BUFFER_NEW;
-
-       yy_switch_to_buffer( b  );
-
-       return b;
-}
-
-/** Setup the input buffer state to scan a string. The next call to yylex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- * 
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- *       yy_scan_bytes() instead.
- */
-YY_BUFFER_STATE yy_scan_string (const char * yystr )
-{
-    
-       return yy_scan_bytes( yystr, (int) strlen(yystr) );
-}
-
-/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
- * scan from a @e copy of @a bytes.
- * @param yybytes the byte buffer to scan
- * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
- * 
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_bytes  (const char * yybytes, int  _yybytes_len )
-{
-       YY_BUFFER_STATE b;
-       char *buf;
-       yy_size_t n;
-       int i;
-    
-       /* Get memory for full buffer, including space for trailing EOB's. */
-       n = (yy_size_t) (_yybytes_len + 2);
-       buf = (char *) yyalloc( n  );
-       if ( ! buf )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
-       for ( i = 0; i < _yybytes_len; ++i )
-               buf[i] = yybytes[i];
-
-       buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
-       b = yy_scan_buffer( buf, n );
-       if ( ! b )
-               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
-       /* It's okay to grow etc. this buffer, and we should throw it
-        * away when we're done.
-        */
-       b->yy_is_our_buffer = 1;
-
-       return b;
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-static void yynoreturn yy_fatal_error (const char* msg )
-{
-                       fprintf( stderr, "%s\n", msg );
-       exit( YY_EXIT_FAILURE );
-}
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-        int yyless_macro_arg = (n); \
-        YY_LESS_LINENO(yyless_macro_arg);\
-               yytext[yyleng] = (yy_hold_char); \
-               (yy_c_buf_p) = yytext + yyless_macro_arg; \
-               (yy_hold_char) = *(yy_c_buf_p); \
-               *(yy_c_buf_p) = '\0'; \
-               yyleng = yyless_macro_arg; \
-               } \
-       while ( 0 )
-
-/* Accessor  methods (get/set functions) to struct members. */
-
-/** Get the current line number.
- * 
- */
-int yyget_lineno  (void)
-{
-    
-    return yylineno;
-}
-
-/** Get the input stream.
- * 
- */
-FILE *yyget_in  (void)
-{
-        return yyin;
-}
-
-/** Get the output stream.
- * 
- */
-FILE *yyget_out  (void)
-{
-        return yyout;
-}
-
-/** Get the length of the current token.
- * 
- */
-int yyget_leng  (void)
-{
-        return yyleng;
-}
-
-/** Get the current token.
- * 
- */
-
-char *yyget_text  (void)
-{
-        return yytext;
-}
-
-/** Set the current line number.
- * @param _line_number line number
- * 
- */
-void yyset_lineno (int  _line_number )
-{
-    
-    yylineno = _line_number;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param _in_str A readable stream.
- * 
- * @see yy_switch_to_buffer
- */
-void yyset_in (FILE *  _in_str )
-{
-        yyin = _in_str ;
-}
-
-void yyset_out (FILE *  _out_str )
-{
-        yyout = _out_str ;
-}
-
-int yyget_debug  (void)
-{
-        return yy_flex_debug;
-}
-
-void yyset_debug (int  _bdebug )
-{
-        yy_flex_debug = _bdebug ;
-}
-
-static int yy_init_globals (void)
-{
-        /* Initialization is the same as for the non-reentrant scanner.
-     * This function is called from yylex_destroy(), so don't allocate here.
-     */
-
-    (yy_buffer_stack) = NULL;
-    (yy_buffer_stack_top) = 0;
-    (yy_buffer_stack_max) = 0;
-    (yy_c_buf_p) = NULL;
-    (yy_init) = 0;
-    (yy_start) = 0;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
-    yyin = stdin;
-    yyout = stdout;
-#else
-    yyin = NULL;
-    yyout = NULL;
-#endif
-
-    /* For future reference: Set errno on error, since we are called by
-     * yylex_init()
-     */
-    return 0;
-}
-
-/* yylex_destroy is for both reentrant and non-reentrant scanners. */
-int yylex_destroy  (void)
-{
-    
-    /* Pop the buffer stack, destroying each element. */
-       while(YY_CURRENT_BUFFER){
-               yy_delete_buffer( YY_CURRENT_BUFFER  );
-               YY_CURRENT_BUFFER_LVALUE = NULL;
-               yypop_buffer_state();
-       }
-
-       /* Destroy the stack itself. */
-       yyfree((yy_buffer_stack) );
-       (yy_buffer_stack) = NULL;
-
-    /* Reset the globals. This is important in a non-reentrant scanner so the next time
-     * yylex() is called, initialization will occur. */
-    yy_init_globals( );
-
-    return 0;
-}
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, const char * s2, int n )
-{
-               
-       int i;
-       for ( i = 0; i < n; ++i )
-               s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (const char * s )
-{
-       int n;
-       for ( n = 0; s[n]; ++n )
-               ;
-
-       return n;
-}
-#endif
-
-void *yyalloc (yy_size_t  size )
-{
-                       return malloc(size);
-}
-
-void *yyrealloc  (void * ptr, yy_size_t  size )
-{
-               
-       /* The cast to (char *) in the following accommodates both
-        * implementations that use char* generic pointers, and those
-        * that use void* generic pointers.  It works with the latter
-        * because both ANSI C and C++ allow castless assignment from
-        * any pointer type to void*, and deal with argument conversions
-        * as though doing an assignment.
-        */
-       return realloc(ptr, size);
-}
-
-void yyfree (void * ptr )
-{
-                       free( (char *) ptr );   /* see yyrealloc() for (char *) cast */
-}
-
-#define YYTABLES_NAME "yytables"
-
-#line 81 "parserPromela.lex"
-
-
-
-
diff --git a/src/xbt/automaton/automatonparse_promela.c b/src/xbt/automaton/automatonparse_promela.c
deleted file mode 100644 (file)
index 4fad698..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* methods for implementation of automaton from promela description */
-
-/* Copyright (c) 2011-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "src/internal_config.h"
-#include "xbt/automaton.h"
-#include <errno.h>
-#include <string.h>   /* strerror */
-#if HAVE_UNISTD_H
-# include <unistd.h>   /* isatty */
-#endif
-#include <xbt/sysdep.h>
-
-#include "parserPromela.tab.cacc"
-
-static xbt_automaton_t parsed_automaton;
-char* state_id_src;
-
-static void new_state(const char* id, int src)
-{
-  char* saveptr = NULL; // for strtok_r()
-  char* id_copy = xbt_strdup(id);
-  const char* first_part = strtok_r(id_copy, "_", &saveptr);
-  int type = 0 ; // -1=initial state; 0=intermediate state; 1=final state
-
-  if(strcmp(first_part,"accept")==0){
-    type = 1;
-  }else{
-    const char* second_part = strtok_r(NULL, "_", &saveptr);
-    if(strcmp(second_part,"init")==0){
-      type = -1;
-    }
-  }
-  xbt_free(id_copy);
-
-  xbt_automaton_state_t state = xbt_automaton_state_exists(parsed_automaton, id);
-  if(state == NULL){
-    state = xbt_automaton_state_new(parsed_automaton, type, id);
-  }
-
-  if(type==-1)
-    parsed_automaton->current_state = state;
-
-  if(src) {
-    xbt_free(state_id_src);
-    state_id_src = xbt_strdup(id);
-  }
-}
-
-static void new_transition(const char* id, xbt_automaton_exp_label_t label)
-{
-  new_state(id, 0);
-  xbt_automaton_state_t state_dst = xbt_automaton_state_exists(parsed_automaton, id);
-  xbt_automaton_state_t state_src = xbt_automaton_state_exists(parsed_automaton, state_id_src);
-
-  xbt_automaton_transition_new(parsed_automaton, state_src, state_dst, label);
-
-}
-
-void xbt_automaton_load(xbt_automaton_t a, const char *file)
-{
-  parsed_automaton = a;
-  xbt_automaton_parser_in = fopen(file, "r");
-  xbt_assert(xbt_automaton_parser_in != NULL, "Failed to open automaton file `%s': %s", file, strerror(errno));
-  xbt_automaton_parser_parse();
-  fclose(xbt_automaton_parser_in);
-}
diff --git a/src/xbt/automaton/parserPromela.lex b/src/xbt/automaton/parserPromela.lex
deleted file mode 100644 (file)
index 461c323..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* Copyright (c) 2012-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-%option noyywrap
-
-%{
-
-#include "simgrid/config.h"
-#if !HAVE_UNISTD_H
-#define YY_NO_UNISTD_H /* hello Windows */
-#endif
-
-#include <stdio.h>
-#include "parserPromela.tab.hacc"
-
-  extern YYSTYPE yylval;
-
-%}
-
-blancs       [ \t]+
-espace       [ ]+
-nouv_ligne   [ \n]
-
-chiffre      [0-9]
-entier       {chiffre}+
-reel         {entier}("."{entier})
-caractere    [a-zA-Z0-9_]
-
-numl         \n
-
-chaine       \"({caractere}*|\n|\\|\"|{espace}*)*\"
-
-commentaire  "/*"([^\*\/]*{nouv_ligne}*[^\*\/]*)*"*/"
-
-%%
-
-"never"      { return (NEVER); }
-"if"         { return (IF); }
-"fi"         { return (FI); }
-"->"         { return (IMPLIES); }
-"goto"       { return (GOTO); }
-"&&"         { return (AND); }
-"||"         { return (OR); }
-"!"          { return (NOT); }
-"("          { return (LEFT_PAR); }
-")"          { return (RIGHT_PAR); }
-"::"         { return (CASE); }
-":"          { return (COLON); }
-";"          { return (SEMI_COLON); }
-"1"          { return (CASE_TRUE); }
-"{"          { return (LEFT_BRACE); }
-"}"          { return (RIGHT_BRACE); }
-
-
-{commentaire}             { }
-
-{blancs}                  { }
-
-
-{reel}                    { sscanf(yytext,"%lf",&yylval.real);
-                            return (LITT_REEL); }
-
-{entier}                  { sscanf(yytext,"%d",&yylval.integer);
-                            return (LITT_ENT); }
-
-{chaine}                  { yylval.string=(char *)malloc(strlen(yytext)+1);
-                            sscanf(yytext,"%s",yylval.string);
-                            return (LITT_CHAINE); }
-
-[a-zA-Z]{caractere}*      { yylval.string=(char *)malloc(strlen(yytext)+1);
-                            sscanf(yytext,"%s",yylval.string);
-                                             return (ID); }
-
-{numl}                    { }
-
-.                         { }
-
-%%
-
-
diff --git a/src/xbt/automaton/parserPromela.tab.cacc b/src/xbt/automaton/parserPromela.tab.cacc
deleted file mode 100644 (file)
index 776faa8..0000000
+++ /dev/null
@@ -1,1364 +0,0 @@
-/* A Bison parser, made by GNU Bison 3.8.2.  */
-
-/* Bison implementation for Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
-   Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
-   especially those whose name start with YY_ or yy_.  They are
-   private implementation details that can be changed or removed.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output, and Bison version.  */
-#define YYBISON 30802
-
-/* Bison version string.  */
-#define YYBISON_VERSION "3.8.2"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Push parsers.  */
-#define YYPUSH 0
-
-/* Pull parsers.  */
-#define YYPULL 1
-
-
-/* Substitute the variable and function names.  */
-#define yyparse         xbt_automaton_parser_parse
-#define yylex           xbt_automaton_parser_lex
-#define yyerror         xbt_automaton_parser_error
-#define yydebug         xbt_automaton_parser_debug
-#define yynerrs         xbt_automaton_parser_nerrs
-#define yylval          xbt_automaton_parser_lval
-#define yychar          xbt_automaton_parser_char
-
-/* First part of user prologue.  */
-#line 7 "parserPromela.yacc"
-
-#include "simgrid/config.h"
-#if !HAVE_UNISTD_H
-#define YY_NO_UNISTD_H /* hello Windows */
-#endif
-
-#include "automaton_lexer.yy.c"
-#include <xbt/automaton.h>
-
-void yyerror(const char *s);
-
-static void new_state(const char* id, int src);
-static void new_transition(const char* id, xbt_automaton_exp_label_t label);
-
-
-#line 94 "parserPromela.tab.cacc"
-
-# ifndef YY_CAST
-#  ifdef __cplusplus
-#   define YY_CAST(Type, Val) static_cast<Type> (Val)
-#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
-#  else
-#   define YY_CAST(Type, Val) ((Type) (Val))
-#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
-#  endif
-# endif
-# ifndef YY_NULLPTR
-#  if defined __cplusplus
-#   if 201103L <= __cplusplus
-#    define YY_NULLPTR nullptr
-#   else
-#    define YY_NULLPTR 0
-#   endif
-#  else
-#   define YY_NULLPTR ((void*)0)
-#  endif
-# endif
-
-#include "parserPromela.tab.hacc"
-/* Symbol kind.  */
-enum yysymbol_kind_t
-{
-  YYSYMBOL_YYEMPTY = -2,
-  YYSYMBOL_YYEOF = 0,                      /* "end of file"  */
-  YYSYMBOL_YYerror = 1,                    /* error  */
-  YYSYMBOL_YYUNDEF = 2,                    /* "invalid token"  */
-  YYSYMBOL_NEVER = 3,                      /* NEVER  */
-  YYSYMBOL_IF = 4,                         /* IF  */
-  YYSYMBOL_FI = 5,                         /* FI  */
-  YYSYMBOL_IMPLIES = 6,                    /* IMPLIES  */
-  YYSYMBOL_GOTO = 7,                       /* GOTO  */
-  YYSYMBOL_AND = 8,                        /* AND  */
-  YYSYMBOL_OR = 9,                         /* OR  */
-  YYSYMBOL_NOT = 10,                       /* NOT  */
-  YYSYMBOL_LEFT_PAR = 11,                  /* LEFT_PAR  */
-  YYSYMBOL_RIGHT_PAR = 12,                 /* RIGHT_PAR  */
-  YYSYMBOL_CASE = 13,                      /* CASE  */
-  YYSYMBOL_COLON = 14,                     /* COLON  */
-  YYSYMBOL_SEMI_COLON = 15,                /* SEMI_COLON  */
-  YYSYMBOL_CASE_TRUE = 16,                 /* CASE_TRUE  */
-  YYSYMBOL_LEFT_BRACE = 17,                /* LEFT_BRACE  */
-  YYSYMBOL_RIGHT_BRACE = 18,               /* RIGHT_BRACE  */
-  YYSYMBOL_LITT_ENT = 19,                  /* LITT_ENT  */
-  YYSYMBOL_LITT_CHAINE = 20,               /* LITT_CHAINE  */
-  YYSYMBOL_LITT_REEL = 21,                 /* LITT_REEL  */
-  YYSYMBOL_ID = 22,                        /* ID  */
-  YYSYMBOL_YYACCEPT = 23,                  /* $accept  */
-  YYSYMBOL_automaton = 24,                 /* automaton  */
-  YYSYMBOL_stateseq = 25,                  /* stateseq  */
-  YYSYMBOL_26_1 = 26,                      /* $@1  */
-  YYSYMBOL_option = 27,                    /* option  */
-  YYSYMBOL_exp = 28                        /* exp  */
-};
-typedef enum yysymbol_kind_t yysymbol_kind_t;
-
-
-
-
-#ifdef short
-# undef short
-#endif
-
-/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
-   <limits.h> and (if available) <stdint.h> are included
-   so that the code can choose integer types of a good width.  */
-
-#ifndef __PTRDIFF_MAX__
-# include <limits.h> /* INFRINGES ON USER NAME SPACE */
-# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
-#  include <stdint.h> /* INFRINGES ON USER NAME SPACE */
-#  define YY_STDINT_H
-# endif
-#endif
-
-/* Narrow types that promote to a signed type and that can represent a
-   signed or unsigned integer of at least N bits.  In tables they can
-   save space and decrease cache pressure.  Promoting to a signed type
-   helps avoid bugs in integer arithmetic.  */
-
-#ifdef __INT_LEAST8_MAX__
-typedef __INT_LEAST8_TYPE__ yytype_int8;
-#elif defined YY_STDINT_H
-typedef int_least8_t yytype_int8;
-#else
-typedef signed char yytype_int8;
-#endif
-
-#ifdef __INT_LEAST16_MAX__
-typedef __INT_LEAST16_TYPE__ yytype_int16;
-#elif defined YY_STDINT_H
-typedef int_least16_t yytype_int16;
-#else
-typedef short yytype_int16;
-#endif
-
-/* Work around bug in HP-UX 11.23, which defines these macros
-   incorrectly for preprocessor constants.  This workaround can likely
-   be removed in 2023, as HPE has promised support for HP-UX 11.23
-   (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of
-   <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>.  */
-#ifdef __hpux
-# undef UINT_LEAST8_MAX
-# undef UINT_LEAST16_MAX
-# define UINT_LEAST8_MAX 255
-# define UINT_LEAST16_MAX 65535
-#endif
-
-#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
-typedef __UINT_LEAST8_TYPE__ yytype_uint8;
-#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
-       && UINT_LEAST8_MAX <= INT_MAX)
-typedef uint_least8_t yytype_uint8;
-#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
-typedef unsigned char yytype_uint8;
-#else
-typedef short yytype_uint8;
-#endif
-
-#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
-typedef __UINT_LEAST16_TYPE__ yytype_uint16;
-#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
-       && UINT_LEAST16_MAX <= INT_MAX)
-typedef uint_least16_t yytype_uint16;
-#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
-typedef unsigned short yytype_uint16;
-#else
-typedef int yytype_uint16;
-#endif
-
-#ifndef YYPTRDIFF_T
-# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
-#  define YYPTRDIFF_T __PTRDIFF_TYPE__
-#  define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
-# elif defined PTRDIFF_MAX
-#  ifndef ptrdiff_t
-#   include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  endif
-#  define YYPTRDIFF_T ptrdiff_t
-#  define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
-# else
-#  define YYPTRDIFF_T long
-#  define YYPTRDIFF_MAXIMUM LONG_MAX
-# endif
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM                                  \
-  YY_CAST (YYPTRDIFF_T,                                 \
-           (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1)  \
-            ? YYPTRDIFF_MAXIMUM                         \
-            : YY_CAST (YYSIZE_T, -1)))
-
-#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
-
-
-/* Stored state numbers (used for stacks). */
-typedef yytype_int8 yy_state_t;
-
-/* State numbers in computations.  */
-typedef int yy_state_fast_t;
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(Msgid) Msgid
-# endif
-#endif
-
-
-#ifndef YY_ATTRIBUTE_PURE
-# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
-#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
-# else
-#  define YY_ATTRIBUTE_PURE
-# endif
-#endif
-
-#ifndef YY_ATTRIBUTE_UNUSED
-# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
-#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-# else
-#  define YY_ATTRIBUTE_UNUSED
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YY_USE(E) ((void) (E))
-#else
-# define YY_USE(E) /* empty */
-#endif
-
-/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
-# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
-#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
-    _Pragma ("GCC diagnostic push")                                     \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
-# else
-#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
-    _Pragma ("GCC diagnostic push")                                     \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
-    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# endif
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
-    _Pragma ("GCC diagnostic pop")
-#else
-# define YY_INITIAL_VALUE(Value) Value
-#endif
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
-
-#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
-# define YY_IGNORE_USELESS_CAST_BEGIN                          \
-    _Pragma ("GCC diagnostic push")                            \
-    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
-# define YY_IGNORE_USELESS_CAST_END            \
-    _Pragma ("GCC diagnostic pop")
-#endif
-#ifndef YY_IGNORE_USELESS_CAST_BEGIN
-# define YY_IGNORE_USELESS_CAST_BEGIN
-# define YY_IGNORE_USELESS_CAST_END
-#endif
-
-
-#define YY_ASSERT(E) ((void) (0 && (E)))
-
-#if !defined yyoverflow
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
-#     ifndef EXIT_SUCCESS
-#      define EXIT_SUCCESS 0
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's 'empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
-       && ! ((defined YYMALLOC || defined malloc) \
-             && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef EXIT_SUCCESS
-#    define EXIT_SUCCESS 0
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined EXIT_SUCCESS
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined EXIT_SUCCESS
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* !defined yyoverflow */
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yy_state_t yyss_alloc;
-  YYSTYPE yyvs_alloc;
-};
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-# define YYCOPY_NEEDED 1
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
-    do                                                                  \
-      {                                                                 \
-        YYPTRDIFF_T yynewbytes;                                         \
-        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
-        Stack = &yyptr->Stack_alloc;                                    \
-        yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
-        yyptr += yynewbytes / YYSIZEOF (*yyptr);                        \
-      }                                                                 \
-    while (0)
-
-#endif
-
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from SRC to DST.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(Dst, Src, Count) \
-      __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
-#  else
-#   define YYCOPY(Dst, Src, Count)              \
-      do                                        \
-        {                                       \
-          YYPTRDIFF_T yyi;                      \
-          for (yyi = 0; yyi < (Count); yyi++)   \
-            (Dst)[yyi] = (Src)[yyi];            \
-        }                                       \
-      while (0)
-#  endif
-# endif
-#endif /* !YYCOPY_NEEDED */
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  4
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   28
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  23
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  6
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  13
-/* YYNSTATES -- Number of states.  */
-#define YYNSTATES  32
-
-/* YYMAXUTOK -- Last valid token kind.  */
-#define YYMAXUTOK   277
-
-
-/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
-   as returned by yylex, with out-of-bounds checking.  */
-#define YYTRANSLATE(YYX)                                \
-  (0 <= (YYX) && (YYX) <= YYMAXUTOK                     \
-   ? YY_CAST (yysymbol_kind_t, yytranslate[YYX])        \
-   : YYSYMBOL_YYUNDEF)
-
-/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
-   as returned by yylex.  */
-static const yytype_int8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22
-};
-
-#if YYDEBUG
-/* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
-static const yytype_int8 yyrline[] =
-{
-       0,    60,    60,    63,    64,    64,    67,    68,    71,    72,
-      73,    74,    75,    76
-};
-#endif
-
-/** Accessing symbol of state STATE.  */
-#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
-
-#if YYDEBUG || 0
-/* The user-facing name of the symbol whose (internal) number is
-   YYSYMBOL.  No bounds checking.  */
-static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
-
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "\"end of file\"", "error", "\"invalid token\"", "NEVER", "IF", "FI",
-  "IMPLIES", "GOTO", "AND", "OR", "NOT", "LEFT_PAR", "RIGHT_PAR", "CASE",
-  "COLON", "SEMI_COLON", "CASE_TRUE", "LEFT_BRACE", "RIGHT_BRACE",
-  "LITT_ENT", "LITT_CHAINE", "LITT_REEL", "ID", "$accept", "automaton",
-  "stateseq", "$@1", "option", "exp", YY_NULLPTR
-};
-
-static const char *
-yysymbol_name (yysymbol_kind_t yysymbol)
-{
-  return yytname[yysymbol];
-}
-#endif
-
-#define YYPACT_NINF (-16)
-
-#define yypact_value_is_default(Yyn) \
-  ((Yyn) == YYPACT_NINF)
-
-#define YYTABLE_NINF (-1)
-
-#define yytable_value_is_error(Yyn) \
-  0
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-static const yytype_int8 yypact[] =
-{
-       0,   -15,    10,   -13,   -16,     2,     1,   -16,   -16,    16,
-       8,   -10,    17,   -10,   -10,   -16,   -16,     9,    11,   -16,
-      -1,    18,   -10,   -10,   -13,   -16,     5,   -16,   -16,   -16,
-       8,   -16
-};
-
-/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
-   Performed when YYTABLE does not specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_int8 yydefact[] =
-{
-       0,     0,     0,     3,     1,     0,     0,     4,     2,     0,
-       6,     0,     0,     0,     0,    12,    13,     0,     0,    11,
-       0,     0,     0,     0,     3,     8,     0,    10,     9,     5,
-       6,     7
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int8 yypgoto[] =
-{
-     -16,   -16,     4,   -16,    -7,    -9
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int8 yydefgoto[] =
-{
-       0,     2,     6,     9,    12,    17
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule whose
-   number is the opposite.  If YYTABLE_NINF, syntax error.  */
-static const yytype_int8 yytable[] =
-{
-      13,    14,     3,     1,    19,    20,    15,    22,    23,     5,
-       4,    25,    16,    27,    28,    21,     7,    22,    23,     8,
-      10,    11,    18,    31,     0,    26,    24,    30,    29
-};
-
-static const yytype_int8 yycheck[] =
-{
-      10,    11,    17,     3,    13,    14,    16,     8,     9,    22,
-       0,    12,    22,    22,    23,     6,    14,     8,     9,    18,
-       4,    13,     5,    30,    -1,     7,    15,    22,    24
-};
-
-/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
-   state STATE-NUM.  */
-static const yytype_int8 yystos[] =
-{
-       0,     3,    24,    17,     0,    22,    25,    14,    18,    26,
-       4,    13,    27,    10,    11,    16,    22,    28,     5,    28,
-      28,     6,     8,     9,    15,    12,     7,    28,    28,    25,
-      22,    27
-};
-
-/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM.  */
-static const yytype_int8 yyr1[] =
-{
-       0,    23,    24,    25,    26,    25,    27,    27,    28,    28,
-      28,    28,    28,    28
-};
-
-/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM.  */
-static const yytype_int8 yyr2[] =
-{
-       0,     2,     4,     0,     0,     8,     0,     6,     3,     3,
-       3,     2,     1,     1
-};
-
-
-enum { YYENOMEM = -2 };
-
-#define yyerrok         (yyerrstatus = 0)
-#define yyclearin       (yychar = YYEMPTY)
-
-#define YYACCEPT        goto yyacceptlab
-#define YYABORT         goto yyabortlab
-#define YYERROR         goto yyerrorlab
-#define YYNOMEM         goto yyexhaustedlab
-
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)                                    \
-  do                                                              \
-    if (yychar == YYEMPTY)                                        \
-      {                                                           \
-        yychar = (Token);                                         \
-        yylval = (Value);                                         \
-        YYPOPSTACK (yylen);                                       \
-        yystate = *yyssp;                                         \
-        goto yybackup;                                            \
-      }                                                           \
-    else                                                          \
-      {                                                           \
-        yyerror (YY_("syntax error: cannot back up")); \
-        YYERROR;                                                  \
-      }                                                           \
-  while (0)
-
-/* Backward compatibility with an undocumented macro.
-   Use YYerror or YYUNDEF. */
-#define YYERRCODE YYUNDEF
-
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)                        \
-do {                                            \
-  if (yydebug)                                  \
-    YYFPRINTF Args;                             \
-} while (0)
-
-
-
-
-# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
-do {                                                                      \
-  if (yydebug)                                                            \
-    {                                                                     \
-      YYFPRINTF (stderr, "%s ", Title);                                   \
-      yy_symbol_print (stderr,                                            \
-                  Kind, Value); \
-      YYFPRINTF (stderr, "\n");                                           \
-    }                                                                     \
-} while (0)
-
-
-/*-----------------------------------.
-| Print this symbol's value on YYO.  |
-`-----------------------------------*/
-
-static void
-yy_symbol_value_print (FILE *yyo,
-                       yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep)
-{
-  FILE *yyoutput = yyo;
-  YY_USE (yyoutput);
-  if (!yyvaluep)
-    return;
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YY_USE (yykind);
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-}
-
-
-/*---------------------------.
-| Print this symbol on YYO.  |
-`---------------------------*/
-
-static void
-yy_symbol_print (FILE *yyo,
-                 yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep)
-{
-  YYFPRINTF (yyo, "%s %s (",
-             yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
-
-  yy_symbol_value_print (yyo, yykind, yyvaluep);
-  YYFPRINTF (yyo, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-static void
-yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; yybottom <= yytop; yybottom++)
-    {
-      int yybot = *yybottom;
-      YYFPRINTF (stderr, " %d", yybot);
-    }
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)                            \
-do {                                                            \
-  if (yydebug)                                                  \
-    yy_stack_print ((Bottom), (Top));                           \
-} while (0)
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-static void
-yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
-                 int yyrule)
-{
-  int yylno = yyrline[yyrule];
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
-             yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr,
-                       YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
-                       &yyvsp[(yyi + 1) - (yynrhs)]);
-      YYFPRINTF (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)          \
-do {                                    \
-  if (yydebug)                          \
-    yy_reduce_print (yyssp, yyvsp, Rule); \
-} while (0)
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args) ((void) 0)
-# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-static void
-yydestruct (const char *yymsg,
-            yysymbol_kind_t yykind, YYSTYPE *yyvaluep)
-{
-  YY_USE (yyvaluep);
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
-
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YY_USE (yykind);
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-}
-
-
-/* Lookahead token kind.  */
-int yychar;
-
-/* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval;
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-int
-yyparse (void)
-{
-    yy_state_fast_t yystate = 0;
-    /* Number of tokens to shift before error messages enabled.  */
-    int yyerrstatus = 0;
-
-    /* Refer to the stacks through separate pointers, to allow yyoverflow
-       to reallocate them elsewhere.  */
-
-    /* Their size.  */
-    YYPTRDIFF_T yystacksize = YYINITDEPTH;
-
-    /* The state stack: array, bottom, top.  */
-    yy_state_t yyssa[YYINITDEPTH];
-    yy_state_t *yyss = yyssa;
-    yy_state_t *yyssp = yyss;
-
-    /* The semantic value stack: array, bottom, top.  */
-    YYSTYPE yyvsa[YYINITDEPTH];
-    YYSTYPE *yyvs = yyvsa;
-    YYSTYPE *yyvsp = yyvs;
-
-  int yyn;
-  /* The return value of yyparse.  */
-  int yyresult;
-  /* Lookahead symbol kind.  */
-  yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yychar = YYEMPTY; /* Cause a token to be read.  */
-
-  goto yysetstate;
-
-
-/*------------------------------------------------------------.
-| yynewstate -- push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
-yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
-
-/*--------------------------------------------------------------------.
-| yysetstate -- set current state (the top of the stack) to yystate.  |
-`--------------------------------------------------------------------*/
-yysetstate:
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
-  YY_IGNORE_USELESS_CAST_BEGIN
-  *yyssp = YY_CAST (yy_state_t, yystate);
-  YY_IGNORE_USELESS_CAST_END
-  YY_STACK_PRINT (yyss, yyssp);
-
-  if (yyss + yystacksize - 1 <= yyssp)
-#if !defined yyoverflow && !defined YYSTACK_RELOCATE
-    YYNOMEM;
-#else
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYPTRDIFF_T yysize = yyssp - yyss + 1;
-
-# if defined yyoverflow
-      {
-        /* Give user a chance to reallocate the stack.  Use copies of
-           these so that the &'s don't force the real ones into
-           memory.  */
-        yy_state_t *yyss1 = yyss;
-        YYSTYPE *yyvs1 = yyvs;
-
-        /* Each stack pointer address is followed by the size of the
-           data in use in that stack, in bytes.  This used to be a
-           conditional around just the two extra args, but that might
-           be undefined if yyoverflow is a macro.  */
-        yyoverflow (YY_("memory exhausted"),
-                    &yyss1, yysize * YYSIZEOF (*yyssp),
-                    &yyvs1, yysize * YYSIZEOF (*yyvsp),
-                    &yystacksize);
-        yyss = yyss1;
-        yyvs = yyvs1;
-      }
-# else /* defined YYSTACK_RELOCATE */
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-        YYNOMEM;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-        yystacksize = YYMAXDEPTH;
-
-      {
-        yy_state_t *yyss1 = yyss;
-        union yyalloc *yyptr =
-          YY_CAST (union yyalloc *,
-                   YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
-        if (! yyptr)
-          YYNOMEM;
-        YYSTACK_RELOCATE (yyss_alloc, yyss);
-        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-#  undef YYSTACK_RELOCATE
-        if (yyss1 != yyssa)
-          YYSTACK_FREE (yyss1);
-      }
-# endif
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-      YY_IGNORE_USELESS_CAST_BEGIN
-      YYDPRINTF ((stderr, "Stack size increased to %ld\n",
-                  YY_CAST (long, yystacksize)));
-      YY_IGNORE_USELESS_CAST_END
-
-      if (yyss + yystacksize - 1 <= yyssp)
-        YYABORT;
-    }
-#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
-
-
-  if (yystate == YYFINAL)
-    YYACCEPT;
-
-  goto yybackup;
-
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-  /* Do appropriate processing given the current state.  Read a
-     lookahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to lookahead token.  */
-  yyn = yypact[yystate];
-  if (yypact_value_is_default (yyn))
-    goto yydefault;
-
-  /* Not known => get a lookahead token if don't already have one.  */
-
-  /* YYCHAR is either empty, or end-of-input, or a valid lookahead.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token\n"));
-      yychar = yylex ();
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = YYEOF;
-      yytoken = YYSYMBOL_YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else if (yychar == YYerror)
-    {
-      /* The scanner already issued an error message, process directly
-         to error recovery.  But do not keep the error token as
-         lookahead, it is too special and may lead us to an endless
-         loop in error recovery. */
-      yychar = YYUNDEF;
-      yytoken = YYSYMBOL_YYerror;
-      goto yyerrlab1;
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yytable_value_is_error (yyn))
-        goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the lookahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-  yystate = yyn;
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  *++yyvsp = yylval;
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-
-  /* Discard the shifted token.  */
-  yychar = YYEMPTY;
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     '$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-  case 4: /* $@1: %empty  */
-#line 64 "parserPromela.yacc"
-                    { new_state((yyvsp[-1].string), 1);}
-#line 1116 "parserPromela.tab.cacc"
-    break;
-
-  case 7: /* option: CASE exp IMPLIES GOTO ID option  */
-#line 68 "parserPromela.yacc"
-                                         { new_transition((yyvsp[-1].string), (yyvsp[-4].label));}
-#line 1122 "parserPromela.tab.cacc"
-    break;
-
-  case 8: /* exp: LEFT_PAR exp RIGHT_PAR  */
-#line 71 "parserPromela.yacc"
-                             { (yyval.label) = (yyvsp[-1].label); }
-#line 1128 "parserPromela.tab.cacc"
-    break;
-
-  case 9: /* exp: exp OR exp  */
-#line 72 "parserPromela.yacc"
-                 { (yyval.label) = xbt_automaton_exp_label_new_or((yyvsp[-2].label), (yyvsp[0].label)); }
-#line 1134 "parserPromela.tab.cacc"
-    break;
-
-  case 10: /* exp: exp AND exp  */
-#line 73 "parserPromela.yacc"
-                  { (yyval.label) = xbt_automaton_exp_label_new_and((yyvsp[-2].label), (yyvsp[0].label)); }
-#line 1140 "parserPromela.tab.cacc"
-    break;
-
-  case 11: /* exp: NOT exp  */
-#line 74 "parserPromela.yacc"
-              { (yyval.label) = xbt_automaton_exp_label_new_not((yyvsp[0].label)); }
-#line 1146 "parserPromela.tab.cacc"
-    break;
-
-  case 12: /* exp: CASE_TRUE  */
-#line 75 "parserPromela.yacc"
-                { (yyval.label) = xbt_automaton_exp_label_new_one(); }
-#line 1152 "parserPromela.tab.cacc"
-    break;
-
-  case 13: /* exp: ID  */
-#line 76 "parserPromela.yacc"
-         { (yyval.label) = xbt_automaton_exp_label_new_predicat((yyvsp[0].string)); }
-#line 1158 "parserPromela.tab.cacc"
-    break;
-
-
-#line 1162 "parserPromela.tab.cacc"
-
-      default: break;
-    }
-  /* User semantic actions sometimes alter yychar, and that requires
-     that yytoken be updated with the new translation.  We take the
-     approach of translating immediately before every use of yytoken.
-     One alternative is translating here after every semantic action,
-     but that translation would be missed if the semantic action invokes
-     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
-     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
-     incorrect destructor might then be invoked immediately.  In the
-     case of YYERROR or YYBACKUP, subsequent parser actions might lead
-     to an incorrect destructor call or verbose syntax error message
-     before the lookahead is translated.  */
-  YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-
-  *++yyvsp = yyval;
-
-  /* Now 'shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-  {
-    const int yylhs = yyr1[yyn] - YYNTOKENS;
-    const int yyi = yypgoto[yylhs] + *yyssp;
-    yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
-               ? yytable[yyi]
-               : yydefgoto[yylhs]);
-  }
-
-  goto yynewstate;
-
-
-/*--------------------------------------.
-| yyerrlab -- here on detecting error.  |
-`--------------------------------------*/
-yyerrlab:
-  /* Make sure we have latest lookahead translation.  See comments at
-     user semantic actions for why this is necessary.  */
-  yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-      yyerror (YY_("syntax error"));
-    }
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse lookahead token after an
-         error, discard it.  */
-
-      if (yychar <= YYEOF)
-        {
-          /* Return failure if at end of input.  */
-          if (yychar == YYEOF)
-            YYABORT;
-        }
-      else
-        {
-          yydestruct ("Error: discarding",
-                      yytoken, &yylval);
-          yychar = YYEMPTY;
-        }
-    }
-
-  /* Else will try to reuse lookahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-  /* Pacify compilers when the user code never invokes YYERROR and the
-     label yyerrorlab therefore never appears in user code.  */
-  if (0)
-    YYERROR;
-  ++yynerrs;
-
-  /* Do not reclaim the symbols of the rule whose action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
-
-  /* Pop stack until we find a state that shifts the error token.  */
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (!yypact_value_is_default (yyn))
-        {
-          yyn += YYSYMBOL_YYerror;
-          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
-            {
-              yyn = yytable[yyn];
-              if (0 < yyn)
-                break;
-            }
-        }
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-        YYABORT;
-
-
-      yydestruct ("Error: popping",
-                  YY_ACCESSING_SYMBOL (yystate), yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  *++yyvsp = yylval;
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturnlab;
-
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturnlab;
-
-
-/*-----------------------------------------------------------.
-| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here.  |
-`-----------------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  goto yyreturnlab;
-
-
-/*----------------------------------------------------------.
-| yyreturnlab -- parsing is finished, clean up and return.  |
-`----------------------------------------------------------*/
-yyreturnlab:
-  if (yychar != YYEMPTY)
-    {
-      /* Make sure we have latest lookahead translation.  See comments at
-         user semantic actions for why this is necessary.  */
-      yytoken = YYTRANSLATE (yychar);
-      yydestruct ("Cleanup: discarding lookahead",
-                  yytoken, &yylval);
-    }
-  /* Do not reclaim the symbols of the rule whose action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-                  YY_ACCESSING_SYMBOL (+*yyssp), yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-
-  return yyresult;
-}
-
-#line 79 "parserPromela.yacc"
-
-
-
-
-void yyerror(const char *s){
-  fprintf (stderr, "%s\n", s);
-}
-
-
-
diff --git a/src/xbt/automaton/parserPromela.tab.hacc b/src/xbt/automaton/parserPromela.tab.hacc
deleted file mode 100644 (file)
index 9579e0b..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* A Bison parser, made by GNU Bison 3.8.2.  */
-
-/* Bison interface for Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
-   Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
-   especially those whose name start with YY_ or yy_.  They are
-   private implementation details that can be changed or removed.  */
-
-#ifndef YY_XBT_AUTOMATON_PARSER_PARSERPROMELA_TAB_HACC_INCLUDED
-# define YY_XBT_AUTOMATON_PARSER_PARSERPROMELA_TAB_HACC_INCLUDED
-/* Debug traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-#if YYDEBUG
-extern int xbt_automaton_parser_debug;
-#endif
-
-/* Token kinds.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-  enum yytokentype
-  {
-    YYEMPTY = -2,
-    YYEOF = 0,                     /* "end of file"  */
-    YYerror = 256,                 /* error  */
-    YYUNDEF = 257,                 /* "invalid token"  */
-    NEVER = 258,                   /* NEVER  */
-    IF = 259,                      /* IF  */
-    FI = 260,                      /* FI  */
-    IMPLIES = 261,                 /* IMPLIES  */
-    GOTO = 262,                    /* GOTO  */
-    AND = 263,                     /* AND  */
-    OR = 264,                      /* OR  */
-    NOT = 265,                     /* NOT  */
-    LEFT_PAR = 266,                /* LEFT_PAR  */
-    RIGHT_PAR = 267,               /* RIGHT_PAR  */
-    CASE = 268,                    /* CASE  */
-    COLON = 269,                   /* COLON  */
-    SEMI_COLON = 270,              /* SEMI_COLON  */
-    CASE_TRUE = 271,               /* CASE_TRUE  */
-    LEFT_BRACE = 272,              /* LEFT_BRACE  */
-    RIGHT_BRACE = 273,             /* RIGHT_BRACE  */
-    LITT_ENT = 274,                /* LITT_ENT  */
-    LITT_CHAINE = 275,             /* LITT_CHAINE  */
-    LITT_REEL = 276,               /* LITT_REEL  */
-    ID = 277                       /* ID  */
-  };
-  typedef enum yytokentype yytoken_kind_t;
-#endif
-
-/* Value type.  */
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-union YYSTYPE
-{
-#line 23 "parserPromela.yacc"
-
-  double real;
-  int integer;
-  char* string;
-  xbt_automaton_exp_label_t label;
-
-#line 93 "parserPromela.tab.hacc"
-
-};
-typedef union YYSTYPE YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-
-extern YYSTYPE xbt_automaton_parser_lval;
-
-
-int xbt_automaton_parser_parse (void);
-
-
-#endif /* !YY_XBT_AUTOMATON_PARSER_PARSERPROMELA_TAB_HACC_INCLUDED  */
diff --git a/src/xbt/automaton/parserPromela.yacc b/src/xbt/automaton/parserPromela.yacc
deleted file mode 100644 (file)
index 05bb382..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* Copyright (c) 2012-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-%{
-#include "simgrid/config.h"
-#if !HAVE_UNISTD_H
-#define YY_NO_UNISTD_H /* hello Windows */
-#endif
-
-#include "automaton_lexer.yy.c"
-#include <xbt/automaton.h>
-
-void yyerror(const char *s);
-
-static void new_state(const char* id, int src);
-static void new_transition(const char* id, xbt_automaton_exp_label_t label);
-
-%}
-
-%union{
-  double real;
-  int integer;
-  char* string;
-  xbt_automaton_exp_label_t label;
-}
-
-%token NEVER
-%token IF
-%token FI
-%token IMPLIES
-%token GOTO
-%token AND
-%token OR
-%token NOT
-%token LEFT_PAR
-%token RIGHT_PAR
-%token CASE
-%token COLON
-%token SEMI_COLON
-%token CASE_TRUE
-%token LEFT_BRACE
-%token RIGHT_BRACE
-%token <integer> LITT_ENT
-%token <string> LITT_CHAINE
-%token <real> LITT_REEL
-%token <string> ID
-
-%type <label> exp;
-
-%start automaton
-
-%left AND OR
-%nonassoc NOT
-
-%%
-
-automaton : NEVER LEFT_BRACE stateseq RIGHT_BRACE
-          ;
-
-stateseq :
-         | ID COLON { new_state($1, 1);} IF option FI SEMI_COLON stateseq
-         ;
-
-option :
-       | CASE exp IMPLIES GOTO ID option { new_transition($5, $2);}
-       ;
-
-exp : LEFT_PAR exp RIGHT_PAR { $$ = $2; }
-    | exp OR exp { $$ = xbt_automaton_exp_label_new_or($1, $3); }
-    | exp AND exp { $$ = xbt_automaton_exp_label_new_and($1, $3); }
-    | NOT exp { $$ = xbt_automaton_exp_label_new_not($2); }
-    | CASE_TRUE { $$ = xbt_automaton_exp_label_new_one(); }
-    | ID { $$ = xbt_automaton_exp_label_new_predicat($1); }
-    ;
-
-%%
-
-
-
-void yyerror(const char *s){
-  fprintf (stderr, "%s\n", s);
-}
-
-
-
index 4914d2b..b719eaf 100644 (file)
@@ -49,7 +49,8 @@ public:
       const std::string frame_name = frame.name();
       if (print) {
         if (frame_name.rfind("simgrid::xbt::MainFunction", 0) == 0 ||
-            frame_name.rfind("simgrid::kernel::context::Context::operator()()", 0) == 0)
+            frame_name.rfind("simgrid::kernel::context::Context::operator()()", 0) == 0 ||
+            frame_name.rfind("auto sthread_create::{lambda") == 0)
           break;
         ss << "  ->  #" << frame_count++ << " ";
         if (xbt_log_no_loc) // Don't display file source and line if so
index 0c28bac..84049fa 100644 (file)
@@ -18,7 +18,7 @@ TEST_CASE("xbt::config: Configuration support", "config")
   XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg);
   xbt_log_threshold_set(&_XBT_LOGV(xbt_cfg), xbt_log_priority_critical);
 
-  auto temp      = simgrid_config;
+  auto* temp     = simgrid_config;
   simgrid_config = nullptr;
   simgrid::config::declare_flag<int>("speed", "description", 0);
   simgrid::config::alias("speed", {"velocity"});
index e8048f8..e4d1755 100644 (file)
@@ -35,7 +35,7 @@ void log_exception(e_xbt_log_priority_t prio, const char* context, std::exceptio
   try {
     std::string name = boost::core::demangle(typeid(exception).name());
 
-    auto* with_context = dynamic_cast<const simgrid::Exception*>(&exception);
+    const auto* with_context = dynamic_cast<const simgrid::Exception*>(&exception);
     if (with_context != nullptr) {
       XBT_LOG(prio, "%s %s by %s/%ld: %s", context, name.c_str(), with_context->throw_point().procname_.c_str(),
               with_context->throw_point().pid_, exception.what());
@@ -54,7 +54,7 @@ void log_exception(e_xbt_log_priority_t prio, const char* context, std::exceptio
 
   try {
     // Do we have a nested exception?
-    auto* with_nested = dynamic_cast<const std::nested_exception*>(&exception);
+    const auto* with_nested = dynamic_cast<const std::nested_exception*>(&exception);
     if (with_nested != nullptr && with_nested->nested_ptr() != nullptr)
       with_nested->rethrow_nested();
   } catch (const std::exception& nested_exception) {
index d5a0a55..944e2a1 100644 (file)
@@ -67,7 +67,7 @@ static inline void lock_release(xbt_mallocator_t m)
  * This function must be called once the framework configuration is done. mallocators will not get used until it's
  * called (check the implementation notes above for more info).
  *
- * sg_config uses this function to inform the mallocators when simgrid is configured, and whether lock protection is
+ * sg_config uses this function to inform the mallocators when SimGrid is configured, and whether lock protection is
  * needed.
  */
 void xbt_mallocator_initialization_is_done(int need_protection)
diff --git a/src/xbt/mmalloc/mfree.c b/src/xbt/mmalloc/mfree.c
deleted file mode 100644 (file)
index 8572826..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Free a block of memory allocated by `mmalloc'. */
-
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Copyright 1990, 1991, 1992 Free Software Foundation
-
-   Written May 1989 by Mike Haertel.
-   Heavily modified Mar 1992 by Fred Fish.  (fnf@cygnus.com) */
-
-#include "mmprivate.h"
-#include "src/mc/mc.h"
-
-/* Return memory to the heap.
-   Like `mfree' but don't call a mfree_hook if there is one.  */
-
-/* Return memory to the heap.  */
-void mfree(struct mdesc *mdp, void *ptr)
-{
-  size_t frag_nb;
-  size_t i;
-  size_t it;
-
-  if (ptr == NULL)
-    return;
-
-  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();
-  }
-
-  int type = mdp->heapinfo[block].type;
-
-  switch (type) {
-  case MMALLOC_TYPE_HEAPINFO:
-    fprintf(stderr, "Asked to free a fragment in a heapinfo block. I'm confused.\n");
-    abort();
-    break;
-
-  case MMALLOC_TYPE_FREE: /* Already free */
-    fprintf(stderr, "Asked to free a fragment in a block that is already free. I'm puzzled.\n");
-    abort();
-    break;
-
-  case MMALLOC_TYPE_UNFRAGMENTED:
-    /* Get as many statistics as early as we can.  */
-    mdp -> heapstats.chunks_used--;
-    mdp -> heapstats.bytes_used -=
-      mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
-    mdp -> heapstats.bytes_free +=
-      mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
-
-    if (MC_is_active() && mdp->heapinfo[block].busy_block.ignore > 0)
-      MC_unignore_heap(ptr, mdp->heapinfo[block].busy_block.busy_size);
-
-    /* Find the free cluster previous to this one in the free list.
-       Start searching at the last block referenced; this may benefit
-       programs with locality of allocation.  */
-    i = mdp->heapindex;
-    if (i > block) {
-      while (i > block) {
-        i = mdp->heapinfo[i].free_block.prev;
-      }
-    } else {
-      do {
-        i = mdp->heapinfo[i].free_block.next;
-      }
-      while ((i != 0) && (i < block));
-      i = mdp->heapinfo[i].free_block.prev;
-    }
-
-    /* Determine how to link this block into the free list.  */
-    if (block == i + mdp->heapinfo[i].free_block.size) {
-
-      /* Coalesce this block with its predecessor.  */
-      mdp->heapinfo[i].free_block.size += mdp->heapinfo[block].busy_block.size;
-      /* Mark all my ex-blocks as free */
-      for (it=0; it<mdp->heapinfo[block].busy_block.size; it++) {
-        if (mdp->heapinfo[block+it].type < 0) {
-          fprintf(stderr,
-                  "Internal Error: Asked to free a block already marked as free (block=%zu it=%zu type=%d). "
-                  "Please report this bug.\n",
-                  block, it, mdp->heapinfo[block].type);
-          abort();
-        }
-        mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
-      }
-
-      block = i;
-    } else {
-      /* Really link this block back into the free list.  */
-      mdp->heapinfo[block].free_block.size = mdp->heapinfo[block].busy_block.size;
-      mdp->heapinfo[block].free_block.next = mdp->heapinfo[i].free_block.next;
-      mdp->heapinfo[block].free_block.prev = i;
-      mdp->heapinfo[i].free_block.next = block;
-      mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
-      mdp -> heapstats.chunks_free++;
-      /* Mark all my ex-blocks as free */
-      for (it=0; it<mdp->heapinfo[block].free_block.size; it++) {
-        if (mdp->heapinfo[block+it].type <0) {
-          fprintf(stderr,
-                  "Internal error: Asked to free a block already marked as free (block=%zu it=%zu/%zu type=%d). "
-                  "Please report this bug.\n",
-                  block, it, mdp->heapinfo[block].free_block.size, mdp->heapinfo[block].type);
-          abort();
-        }
-        mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
-      }
-    }
-
-    /* Now that the block is linked in, see if we can coalesce it
-       with its successor (by deleting its successor from the list
-       and adding in its size).  */
-    if (block + mdp->heapinfo[block].free_block.size ==
-        mdp->heapinfo[block].free_block.next) {
-      mdp->heapinfo[block].free_block.size
-        += mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.size;
-      mdp->heapinfo[block].free_block.next
-        = mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.next;
-      mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
-      mdp -> heapstats.chunks_free--;
-    }
-
-    /* Now see if we can return stuff to the system.  */
-#if 0
-          blocks = mdp -> heapinfo[block].free.size;
-          if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
-          && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
-          {
-          register size_t bytes = blocks * BLOCKSIZE;
-          mdp -> heaplimit -= blocks;
-          mdp -> morecore (mdp, -bytes);
-          mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
-          = mdp -> heapinfo[block].free.next;
-          mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
-          = mdp -> heapinfo[block].free.prev;
-          block = mdp -> heapinfo[block].free.prev;
-          mdp -> heapstats.chunks_free--;
-          mdp -> heapstats.bytes_free -= bytes;
-          }
-#endif
-
-    /* Set the next search to begin at this block.
-       This is probably important to the trick where realloc returns the block to
-       the system before reasking for the same block with a bigger size.  */
-    mdp->heapindex = block;
-    break;
-
-  default:
-    if (type < 0) {
-      fprintf(stderr, "Unknown mmalloc block type.\n");
-      abort();
-    }
-
-    /* Do some of the statistics.  */
-    mdp -> heapstats.chunks_used--;
-    mdp -> heapstats.bytes_used -= 1 << type;
-    mdp -> heapstats.chunks_free++;
-    mdp -> heapstats.bytes_free += 1 << type;
-
-    frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
-
-    if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
-      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)
-      MC_unignore_heap(ptr, mdp->heapinfo[block].busy_frag.frag_size[frag_nb]);
-
-    /* Set size used in the fragment to -1 */
-    mdp->heapinfo[block].busy_frag.frag_size[frag_nb] = -1;
-    mdp->heapinfo[block].busy_frag.ignore[frag_nb] = 0;
-
-    if (mdp->heapinfo[block].busy_frag.nfree ==
-        (BLOCKSIZE >> type) - 1) {
-      /* If all fragments of this block are free, remove this block from its swag and free the whole block.  */
-      xbt_swag_remove(&mdp->heapinfo[block],&mdp->fraghead[type]);
-
-      /* pretend that this block is used and free it so that it gets properly coalesced with adjacent free blocks */
-      mdp->heapinfo[block].type = MMALLOC_TYPE_UNFRAGMENTED;
-      mdp->heapinfo[block].busy_block.size = 1;
-      mdp->heapinfo[block].busy_block.busy_size = 0;
-
-      /* Keep the statistics accurate.  */
-      mdp -> heapstats.chunks_used++;
-      mdp -> heapstats.bytes_used += BLOCKSIZE;
-      mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
-      mdp -> heapstats.bytes_free -= BLOCKSIZE;
-
-      mfree(mdp, ADDRESS(block));
-    } else if (mdp->heapinfo[block].busy_frag.nfree != 0) {
-      /* If some fragments of this block are free, you know what? I'm already happy. */
-      ++mdp->heapinfo[block].busy_frag.nfree;
-    } else {
-      /* No fragments of this block were free before the one we just released,
-       * so add this block to the swag and announce that
-       it is the first free fragment of this block. */
-      mdp->heapinfo[block].busy_frag.nfree = 1;
-      mdp->heapinfo[block].freehook.prev = NULL;
-      mdp->heapinfo[block].freehook.next = NULL;
-
-      xbt_swag_insert(&mdp->heapinfo[block],&mdp->fraghead[type]);
-    }
-    break;
-  }
-}
diff --git a/src/xbt/mmalloc/mm.c b/src/xbt/mmalloc/mm.c
deleted file mode 100644 (file)
index 9945155..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Build the entire mmalloc library as a single object module. This
-   avoids having clients pick up part of their allocation routines
-   from mmalloc and part from libc, which results in undefined
-   behavior.  It should also still be possible to build the library
-   as a standard library with multiple objects. */
-
-/* Copyright (c) 2010-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Copyright 1996, 2000 Free Software Foundation  */
-
-#define _GNU_SOURCE
-#include "src/internal_config.h"
-#if HAVE_UNISTD_H
-#include <unistd.h>             /* Prototypes for lseek, sbrk (maybe) */
-#endif
-
-#include "swag.c"
-#include "mfree.c"
-#include "mmalloc.c"
-#include "mrealloc.c"
-#include "mmorecore.c"
-#include "mm_legacy.c"
-#include "mm_module.c"
diff --git a/src/xbt/mmalloc/mm_interface.c b/src/xbt/mmalloc/mm_interface.c
deleted file mode 100644 (file)
index 967bf2f..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* External interface to a mmap'd malloc managed region. */
-
-/* Copyright (c) 2012-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* 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;
-}
diff --git a/src/xbt/mmalloc/mm_legacy.c b/src/xbt/mmalloc/mm_legacy.c
deleted file mode 100644 (file)
index 5cd89d5..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Redefine the classical malloc/free/realloc functions so that they fit well in the mmalloc framework */
-#define _GNU_SOURCE
-
-#include "mmprivate.h"
-
-#include <dlfcn.h>
-#include <math.h>
-#include <stdlib.h>
-
-/* ***** Whether to use `mmalloc` of the underlying malloc ***** */
-
-static int __malloc_use_mmalloc;
-
-int malloc_use_mmalloc(void)
-{
-  return __malloc_use_mmalloc;
-}
-
-/* ***** Current heap ***** */
-
-/* The mmalloc() package can use a single implicit malloc descriptor
-   for mmalloc/mrealloc/mfree operations which do not supply an explicit
-   descriptor.  This allows mmalloc() to provide
-   backwards compatibility with the non-mmap'd version. */
-xbt_mheap_t __mmalloc_default_mdp = NULL;
-
-/* The heap we are currently using. */
-static xbt_mheap_t __mmalloc_current_heap = NULL;
-
-xbt_mheap_t mmalloc_get_current_heap(void)
-{
-  return __mmalloc_current_heap;
-}
-
-/* Override the malloc-like functions if MC is activated at compile time */
-/* ***** Temporary allocator
- *
- * This is used before we have found the real malloc implementation with dlsym.
- */
-
-static size_t fake_alloc_index;
-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
- * if this fails.
- */
-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 >= 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;
-  return res;
-}
-
-static void* mm_fake_calloc(size_t nmemb, size_t size)
-{
-  // This is fresh .bss data, we don't need to clear it:
-  size_t n = nmemb * size;
-  return mm_fake_malloc(n);
-}
-
-static void* mm_fake_realloc(XBT_ATTRIB_UNUSED void* p, size_t s)
-{
-  return mm_fake_malloc(s);
-}
-
-static void mm_fake_free(XBT_ATTRIB_UNUSED void* p)
-{
-  // Nothing to do
-}
-
-/* Function signatures for the main malloc functions: */
-typedef void* (*mm_malloc_t)(size_t size);
-typedef void  (*mm_free_t)(void*);
-typedef void* (*mm_calloc_t)(size_t nmemb, size_t size);
-typedef void* (*mm_realloc_t)(void *ptr, size_t size);
-
-/* Function pointers to the real/next implementations: */
-static mm_malloc_t mm_real_malloc;
-static mm_free_t mm_real_free;
-static mm_calloc_t mm_real_calloc;
-static mm_realloc_t mm_real_realloc;
-
-static int mm_initializing;
-static int mm_initialized;
-
-/** Constructor functions used to initialize the malloc implementation
- */
-XBT_ATTRIB_CONSTRUCTOR(101) static void mm_legacy_constructor()
-{
-  if (mm_initialized)
-    return;
-  mm_initializing = 1;
-  __malloc_use_mmalloc = getenv(MC_ENV_SOCKET_FD) != NULL;
-  if (__malloc_use_mmalloc) {
-    __mmalloc_current_heap = mmalloc_preinit();
-  } else {
-#if HAVE_DLFUNC
-    mm_real_realloc  = (void *(*)(void *, size_t))dlfunc(RTLD_NEXT, "realloc");
-    mm_real_malloc   = (void *(*)(size_t))dlfunc(RTLD_NEXT, "malloc");
-    mm_real_free     = (void (*)(void *))dlfunc(RTLD_NEXT, "free");
-    mm_real_calloc   = (void *(*)(size_t, size_t))dlfunc(RTLD_NEXT, "calloc");
-#else
-    mm_real_realloc  = dlsym(RTLD_NEXT, "realloc");
-    mm_real_malloc   = dlsym(RTLD_NEXT, "malloc");
-    mm_real_free     = dlsym(RTLD_NEXT, "free");
-    mm_real_calloc   = dlsym(RTLD_NEXT, "calloc");
-#endif
-  }
-
-  mm_initializing = 0;
-  mm_initialized = 1;
-}
-
-/* ***** malloc/free implementation
- *
- * They call either the underlying/native/RTLD_NEXT implementation (non MC mode)
- * or the mm implementation (MC mode).
- *
- * If we are initializing the malloc subsystem, we call the fake/dummy `malloc`
- * implementation. This is necessary because `dlsym` calls `malloc` and friends.
- */
-
-#define GET_HEAP() __mmalloc_current_heap
-
-void *malloc(size_t n)
-{
-  if (!mm_initialized) {
-    if (mm_initializing)
-      return mm_fake_malloc(n);
-    mm_legacy_constructor();
-  }
-
-  if (!__malloc_use_mmalloc) {
-    return mm_real_malloc(n);
-  }
-
-  xbt_mheap_t mdp = GET_HEAP();
-  if (!mdp)
-    return NULL;
-
-  return mmalloc(mdp, n);
-}
-
-void *calloc(size_t nmemb, size_t size)
-{
-  if (!mm_initialized) {
-    if (mm_initializing)
-      return mm_fake_calloc(nmemb, size);
-    mm_legacy_constructor();
-  }
-
-  if (!__malloc_use_mmalloc) {
-    return mm_real_calloc(nmemb, size);
-  }
-
-  xbt_mheap_t mdp = GET_HEAP();
-  if (!mdp)
-    return NULL;
-
-  void *ret = mmalloc(mdp, nmemb*size);
-  // This was already done in the callee:
-  if(!(mdp->options & XBT_MHEAP_OPTION_MEMSET)) {
-    memset(ret, 0, nmemb * size);
-  }
-  return ret;
-}
-
-void *realloc(void *p, size_t s)
-{
-  if (!mm_initialized) {
-    if (mm_initializing)
-      return mm_fake_realloc(p, s);
-    mm_legacy_constructor();
-  }
-
-  if (!__malloc_use_mmalloc) {
-    return mm_real_realloc(p, s);
-  }
-
-  xbt_mheap_t mdp = GET_HEAP();
-  if (!mdp)
-    return NULL;
-
-  return mrealloc(mdp, p, s);
-}
-
-void free(void *p)
-{
-  if (!mm_initialized) {
-    if (mm_initializing)
-      return mm_fake_free(p);
-    mm_legacy_constructor();
-  }
-
-  if (!__malloc_use_mmalloc) {
-    mm_real_free(p);
-    return;
-  }
-
-  if (!p)
-    return;
-
-  xbt_mheap_t mdp = GET_HEAP();
-  mfree(mdp, p);
-}
diff --git a/src/xbt/mmalloc/mm_module.c b/src/xbt/mmalloc/mm_module.c
deleted file mode 100644 (file)
index f4bd97a..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* Initialization for access to a mmap'd malloc managed region. */
-
-/* Copyright (c) 2012-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* 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 <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"
-
-/* Initialize access to a mmalloc managed region.
-
-   The mapping is established starting at the specified address BASEADDR
-   in the process address space.
-
-   The provided BASEADDR should be chosen carefully in order to avoid
-   bumping into existing mapped regions or future mapped regions.
-
-   On success, returns a "malloc descriptor" which is used in subsequent
-   calls to other mmalloc package functions.  It is explicitly "void *"
-   so that users of the package don't have to worry about the actual
-   implementation details.
-
-   On failure, returns NULL. */
-
-xbt_mheap_t xbt_mheap_new(void* baseaddr, int options)
-{
-  /* NULL is not a valid baseaddr as we cannot map anything there. C'mon, user. Think! */
-  if (baseaddr == NULL)
-    return NULL;
-
-  /* We start off with the malloc descriptor allocated on the stack, until we build it up enough to
-   * call _mmalloc_mmap_morecore() to allocate the first page of the region and copy it there.  Ensure that it is
-   * zero'd and then initialize the fields that we know values for. */
-
-  struct mdesc mtemp;
-  xbt_mheap_t mdp = &mtemp;
-  memset((char *) mdp, 0, sizeof(mtemp));
-  strncpy(mdp->magic, MMALLOC_MAGIC, MMALLOC_MAGIC_SIZE);
-  mdp->headersize = sizeof(mtemp);
-  mdp->version = MMALLOC_VERSION;
-  mdp->base = mdp->breakval = mdp->top = baseaddr;
-  mdp->next_mdesc = NULL;
-  mdp->options = options;
-
-  /* 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. */
-
-  /* Now try to map in the first page, copy the malloc descriptor structure there, and arrange to return a pointer to
-   * this new copy.  If the mapping fails, then close the file descriptor if it was opened by us, and arrange to return
-   * a NULL. */
-
-  void* mbase = mmorecore(mdp, sizeof(mtemp));
-  if (mbase == NULL) {
-    fprintf(stderr, "morecore failed to get some more memory!\n");
-    abort();
-  }
-  memcpy(mbase, mdp, sizeof(mtemp));
-
-  /* Add the new heap to the linked list of heaps attached by mmalloc */
-  if(__mmalloc_default_mdp){
-    mdp = __mmalloc_default_mdp;
-    while(mdp->next_mdesc)
-      mdp = mdp->next_mdesc;
-
-    mdp->next_mdesc = (struct mdesc *)mbase;
-  }
-
-  return mbase;
-}
-
-/** 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.
-
-    Returns NULL on success.
-
-    Returns the malloc descriptor on failure, which can subsequently be used for further action, such as obtaining more
-    information about the nature of the failure.
-
-    Note that the malloc descriptor that we are using is currently located in region we are about to unmap, so we first
-    make a local copy of it on the stack and use the copy. */
-
-void *xbt_mheap_destroy(xbt_mheap_t mdp)
-{
-  if (mdp != NULL) {
-    /* Remove the heap from the linked list of heaps attached by mmalloc */
-    struct mdesc* mdptemp = __mmalloc_default_mdp;
-    while(mdptemp->next_mdesc != mdp )
-      mdptemp = mdptemp->next_mdesc;
-
-    mdptemp->next_mdesc = mdp->next_mdesc;
-
-    struct mdesc mtemp = *mdp;
-
-    /* Now unmap all the pages associated with this region by asking for a
-       negative increment equal to the current size of the region. */
-
-    if (mmorecore(&mtemp, (char *)mtemp.base - (char *)mtemp.breakval) == NULL) {
-      /* Deallocating failed.  Update the original malloc descriptor with any changes */
-      *mdp = mtemp;
-    } else {
-      mdp = NULL;
-    }
-  }
-
-  return mdp;
-}
-
-/* Safety gap from the heap's break address.
- * Try to increase this first if you experience strange errors under valgrind. */
-#define HEAP_OFFSET   (128UL<<20)
-
-/* 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) {
-    unsigned long mmalloc_pagesize = (unsigned long)sysconf(_SC_PAGESIZE);
-    unsigned long mask             = ~(mmalloc_pagesize - 1);
-    void* addr            = (void*)(((unsigned long)sbrk(0) + HEAP_OFFSET) & mask);
-    __mmalloc_default_mdp = xbt_mheap_new(addr, XBT_MHEAP_OPTION_MEMSET);
-  }
-  mmalloc_assert(__mmalloc_default_mdp != NULL, "__mmalloc_default_mdp cannot be NULL");
-
-  return __mmalloc_default_mdp;
-}
diff --git a/src/xbt/mmalloc/mmalloc.c b/src/xbt/mmalloc/mmalloc.c
deleted file mode 100644 (file)
index ea99da9..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/* Memory allocator `malloc'. */
-
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Copyright 1990, 1991, 1992 Free Software Foundation
-
-   Written May 1989 by Mike Haertel.
-   Heavily modified Mar 1992 by Fred Fish for mmap'd version. */
-
-#include <string.h>             /* Prototypes for memcpy, memmove, memset, etc */
-#include <stdio.h>
-#include "mmprivate.h"
-
-/* Prototypes for local functions */
-
-static void initialize(xbt_mheap_t mdp);
-static void *register_morecore(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* mmalloc_aligned(struct mdesc* mdp, size_t size)
-{
-  void *result;
-  unsigned long int adj;
-
-  result = mmorecore(mdp, size);
-
-  /* if this reservation does not fill up the last block of our resa,
-   * complete the reservation by also asking for the full latest block.
-   *
-   * Also, the returned block is aligned to the end of block (but I've
-   * no fucking idea of why, actually -- http://abstrusegoose.com/432 --
-   * but not doing so seems to lead to issues).
-   */
-  adj = RESIDUAL(result, BLOCKSIZE);
-  if (adj != 0) {
-    adj = BLOCKSIZE - adj;
-    mmorecore(mdp, adj);
-    result = (char *) result + adj;
-  }
-  return result;
-}
-
-/** Initialize heapinfo about the heapinfo pages :) */
-static void initialize_heapinfo_heapinfo(const s_xbt_mheap_t* mdp)
-{
-  // Update heapinfo about the heapinfo pages (!):
-  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:
-  for (size_t j=0; j!=nblocks; ++j) {
-    mdp->heapinfo[block+j].type = MMALLOC_TYPE_FREE;
-    mdp->heapinfo[block+j].free_block.size = 0;
-    mdp->heapinfo[block+j].free_block.next = 0;
-    mdp->heapinfo[block+j].free_block.prev = 0;
-  }
-  mdp->heapinfo[block].free_block.size = nblocks;
-}
-
-/* Finish the initialization of the mheap. If we want to inline it
- * 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*)mmalloc_aligned(mdp, mdp->heapsize * sizeof(malloc_info));
-  mdp->heapbase = (void *) mdp->heapinfo;
-  mdp->flags |= MMALLOC_INITIALIZED;
-
-  // Update root heapinfo:
-  memset((void *) mdp->heapinfo, 0, mdp->heapsize * sizeof(malloc_info));
-  mdp->heapinfo[0].type = MMALLOC_TYPE_FREE;
-  mdp->heapinfo[0].free_block.size = 0;
-  mdp->heapinfo[0].free_block.next = mdp->heapinfo[0].free_block.prev = 0;
-  mdp->heapindex = 0;
-
-  initialize_heapinfo_heapinfo(mdp);
-
-  for (int i = 0; i < BLOCKLOG; i++) {
-    malloc_info mi; /* to compute the offset of the swag hook */
-    xbt_swag_init(&(mdp->fraghead[i]), xbt_swag_offset(mi, freehook));
-  }
-}
-
-static inline void update_hook(void **a, size_t offset)
-{
-  if (*a)
-    *a = (char*)*a + offset;
-}
-
-/* Get neatly aligned memory from the low level layers, and register it
- * into the heap info table as necessary. */
-static void *register_morecore(struct mdesc *mdp, size_t size)
-{
-  void* result = mmalloc_aligned(mdp, size); // Never returns NULL
-
-  /* Check if we need to grow the info table (in a multiplicative manner)  */
-  if (BLOCK((char*)result + size) > mdp->heapsize) {
-    size_t newsize = mdp->heapsize;
-    while (BLOCK((char*)result + size) > newsize)
-      newsize *= 2;
-
-    /* Copy old info into new location */
-    malloc_info* oldinfo = mdp->heapinfo;
-    malloc_info* newinfo = (malloc_info*)mmalloc_aligned(mdp, newsize * sizeof(malloc_info));
-    memcpy(newinfo, oldinfo, mdp->heapsize * sizeof(malloc_info));
-
-    /* Initialize the new blockinfo : */
-    memset((char*) newinfo + mdp->heapsize * sizeof(malloc_info), 0,
-      (newsize - mdp->heapsize)* sizeof(malloc_info));
-
-    /* Update the swag of busy blocks containing free fragments by applying the offset to all swag_hooks. Yeah. My hand is right in the fan and I still type */
-    size_t offset=((char*)newinfo)-((char*)oldinfo);
-
-    for (size_t i = 1 /*first element of heapinfo describes the mdesc area*/; i < mdp->heaplimit; i++) {
-      update_hook(&newinfo[i].freehook.next, offset);
-      update_hook(&newinfo[i].freehook.prev, offset);
-    }
-    // also update the starting points of the swag
-    for (int i = 0; i < BLOCKLOG; i++) {
-      update_hook(&mdp->fraghead[i].head, offset);
-      update_hook(&mdp->fraghead[i].tail, offset);
-    }
-    mdp->heapinfo = newinfo;
-
-    /* mark the space previously occupied by the block info as free by first marking it
-     * as occupied in the regular way, and then freing it */
-    for (size_t it = 0; it < BLOCKIFY(mdp->heapsize * sizeof(malloc_info)); it++) {
-      newinfo[BLOCK(oldinfo)+it].type = MMALLOC_TYPE_UNFRAGMENTED;
-      newinfo[BLOCK(oldinfo)+it].busy_block.ignore = 0;
-    }
-
-    newinfo[BLOCK(oldinfo)].busy_block.size = BLOCKIFY(mdp->heapsize * sizeof(malloc_info));
-    newinfo[BLOCK(oldinfo)].busy_block.busy_size = size;
-    mfree(mdp, (void *) oldinfo);
-    mdp->heapsize = newsize;
-
-    initialize_heapinfo_heapinfo(mdp);
-  }
-
-  mdp->heaplimit = BLOCK((char *) result + size);
-  return result;
-}
-
-/* Allocate memory from the heap.  */
-void *mmalloc(xbt_mheap_t mdp, size_t size) {
-  void *res= mmalloc_no_memset(mdp,size);
-  if (mdp->options & XBT_MHEAP_OPTION_MEMSET) {
-    memset(res,0,size);
-  }
-  return res;
-}
-
-static void mmalloc_mark_used(xbt_mheap_t mdp, size_t block, size_t nblocks, size_t requested_size)
-{
-  for (size_t it = 0; it < nblocks; it++) {
-    mdp->heapinfo[block + it].type                 = MMALLOC_TYPE_UNFRAGMENTED;
-    mdp->heapinfo[block + it].busy_block.busy_size = 0;
-    mdp->heapinfo[block + it].busy_block.ignore    = 0;
-    mdp->heapinfo[block + it].busy_block.size      = 0;
-  }
-  mdp->heapinfo[block].busy_block.size      = nblocks;
-  mdp->heapinfo[block].busy_block.busy_size = requested_size;
-  mdp->heapstats.chunks_used++;
-  mdp->heapstats.bytes_used += nblocks * BLOCKSIZE;
-}
-
-/* Splitting mmalloc this way is mandated by a trick in mrealloc, that gives
-   back the memory of big blocks to the system before reallocating them: we don't
-   want to loose the beginning of the area when this happens */
-void *mmalloc_no_memset(xbt_mheap_t mdp, size_t size)
-{
-  void *result;
-  size_t block;
-
-  size_t requested_size = size; // The amount of memory requested by user, for real
-
-  /* Work even if the user was stupid enough to ask a ridiculously small block (even 0-length),
-   *    ie return a valid block that can be realloced and freed.
-   * glibc malloc does not use this trick but return a constant pointer, but we need to enlist the free fragments later on.
-   */
-  if (size < SMALLEST_POSSIBLE_MALLOC)
-    size = SMALLEST_POSSIBLE_MALLOC;
-
-  if (!(mdp->flags & MMALLOC_INITIALIZED))
-    initialize(mdp);
-
-  /* Determine the allocation policy based on the request size.  */
-  if (size <= BLOCKSIZE / 2) {
-    /* Small allocation to receive a fragment of a block.
-       Determine the logarithm to base two of the fragment size. */
-    size_t log = 1;
-    --size;
-    while ((size /= 2) != 0) {
-      ++log;
-    }
-
-    /* Look in the fragment lists for a free fragment of the desired size. */
-    if (xbt_swag_size(&mdp->fraghead[log])>0) {
-      /* There are free fragments of this size; Get one of them and prepare to return it.
-         Update the block's nfree and if no other free fragment, get out of the swag. */
-
-      /* search a fragment that I could return as a result */
-      malloc_info *candidate_info = xbt_swag_getFirst(&mdp->fraghead[log]);
-      size_t candidate_block = (candidate_info - &(mdp->heapinfo[0]));
-      size_t candidate_frag;
-      for (candidate_frag=0;candidate_frag<(size_t) (BLOCKSIZE >> log);candidate_frag++)
-        if (candidate_info->busy_frag.frag_size[candidate_frag] == -1)
-          break;
-      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));
-
-      /* Remove this fragment from the list of free guys */
-      candidate_info->busy_frag.nfree--;
-      if (candidate_info->busy_frag.nfree == 0) {
-        xbt_swag_remove(candidate_info,&mdp->fraghead[log]);
-      }
-
-      /* Update our metadata about this fragment */
-      candidate_info->busy_frag.frag_size[candidate_frag] = requested_size;
-      candidate_info->busy_frag.ignore[candidate_frag] = 0;
-
-      /* Update the statistics.  */
-      mdp -> heapstats.chunks_used++;
-      mdp -> heapstats.bytes_used += 1 << log;
-      mdp -> heapstats.chunks_free--;
-      mdp -> heapstats.bytes_free -= 1 << log;
-
-    } else {
-      /* No free fragments of the desired size, so get a new block
-         and break it into fragments, returning the first.  */
-
-      result = mmalloc(mdp, BLOCKSIZE); // does not return NULL
-      block = BLOCK(result);
-
-      mdp->heapinfo[block].type = (int)log;
-      /* Link all fragments but the first as free, and add the block to the swag of blocks containing free frags  */
-      size_t i;
-      for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i) {
-        mdp->heapinfo[block].busy_frag.frag_size[i] = -1;
-        mdp->heapinfo[block].busy_frag.ignore[i] = 0;
-      }
-      mdp->heapinfo[block].busy_frag.nfree = i - 1;
-      mdp->heapinfo[block].freehook.prev = NULL;
-      mdp->heapinfo[block].freehook.next = NULL;
-
-      xbt_swag_insert(&mdp->heapinfo[block], &(mdp->fraghead[log]));
-
-      /* mark the fragment returned as busy */
-      mdp->heapinfo[block].busy_frag.frag_size[0] = requested_size;
-      mdp->heapinfo[block].busy_frag.ignore[0] = 0;
-
-      /* update stats */
-      mdp -> heapstats.chunks_free += (BLOCKSIZE >> log) - 1;
-      mdp -> heapstats.bytes_free += BLOCKSIZE - (1 << log);
-      mdp -> heapstats.bytes_used -= BLOCKSIZE - (1 << log);
-    }
-  } else {
-    /* Large allocation to receive one or more blocks.
-       Search the free list in a circle starting at the last place visited.
-       If we loop completely around without finding a large enough
-       space we will have to get more memory from the system.  */
-    size_t blocks = BLOCKIFY(size);
-    size_t start  = MALLOC_SEARCH_START;
-    block         = MALLOC_SEARCH_START;
-    while (mdp->heapinfo[block].free_block.size < blocks) {
-      if (mdp->heapinfo[block].type >=0) { // Don't trust xbt_die and friends in malloc-level library, you fool!
-        fprintf(stderr,
-                "Internal error: found a free block not marked as such (block=%zu type=%d). Please report this bug.\n",
-                block, mdp->heapinfo[block].type);
-        abort();
-      }
-
-      block = mdp->heapinfo[block].free_block.next;
-      if (block == start) {
-        /* Need to get more from the system.  Check to see if
-           the new core will be contiguous with the final free
-           block; if so we don't need to get as much.  */
-        block = mdp->heapinfo[0].free_block.prev;
-        size_t lastblocks = mdp->heapinfo[block].free_block.size;
-        if (mdp->heaplimit != 0 &&
-            block + lastblocks == mdp->heaplimit &&
-            mmorecore(mdp, 0) == ADDRESS(block + lastblocks) &&
-            (register_morecore(mdp, (blocks - lastblocks) * BLOCKSIZE)) != NULL) {
-          /* Which block we are extending (the `final free
-             block' referred to above) might have changed, if
-             it got combined with a freed info table.  */
-          block = mdp->heapinfo[0].free_block.prev;
-
-          mdp->heapinfo[block].free_block.size += (blocks - lastblocks);
-          continue;
-        }
-        result = register_morecore(mdp, blocks * BLOCKSIZE);
-
-        block = BLOCK(result);
-        mmalloc_mark_used(mdp, block, blocks, requested_size);
-
-        return result;
-      }
-      /* Need large block(s), but found some in the existing heap */
-    }
-
-    /* At this point we have found a suitable free list entry.
-       Figure out how to remove what we need from the list. */
-    result = ADDRESS(block);
-    if (mdp->heapinfo[block].free_block.size > blocks) {
-      /* The block we found has a bit left over,
-         so relink the tail end back into the free list. */
-      mdp->heapinfo[block + blocks].free_block.size
-        = mdp->heapinfo[block].free_block.size - blocks;
-      mdp->heapinfo[block + blocks].free_block.next
-        = mdp->heapinfo[block].free_block.next;
-      mdp->heapinfo[block + blocks].free_block.prev
-        = mdp->heapinfo[block].free_block.prev;
-      mdp->heapinfo[mdp->heapinfo[block].free_block.prev].free_block.next
-        = mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev
-        = mdp->heapindex = block + blocks;
-    } else {
-      /* The block exactly matches our requirements,
-         so just remove it from the list. */
-      mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev
-        = mdp->heapinfo[block].free_block.prev;
-      mdp->heapinfo[mdp->heapinfo[block].free_block.prev].free_block.next
-        = mdp->heapindex = mdp->heapinfo[block].free_block.next;
-    }
-
-    mmalloc_mark_used(mdp, block, blocks, requested_size);
-    mdp -> heapstats.bytes_free -= blocks * BLOCKSIZE;
-
-  }
-
-  return result;
-}
diff --git a/src/xbt/mmalloc/mmalloc.h b/src/xbt/mmalloc/mmalloc.h
deleted file mode 100644 (file)
index d3cdc24..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
-   This file was then part of the GNU C Library. */
-
-#ifndef SIMGRID_MMALLOC_H
-#define SIMGRID_MMALLOC_H
-
-#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 */
-
-SG_BEGIN_DECL
-
-/* Datatype representing a separate heap. The whole point of the mmalloc module is to allow several such heaps in the
- * process. It thus works by redefining all the classical memory management functions (malloc and friends) with an
- * extra first argument: the heap in which the memory is to be taken.
- *
- * The heap structure itself is an opaque object that shouldn't be messed with.
- */
-typedef struct mdesc s_xbt_mheap_t;
-typedef s_xbt_mheap_t* xbt_mheap_t;
-
-#if HAVE_MMALLOC
-/* Allocate SIZE bytes of memory (and memset it to 0).  */
-XBT_PUBLIC void* mmalloc(xbt_mheap_t md, size_t size);
-
-/* Allocate SIZE bytes of memory (and don't mess with it) */
-void* mmalloc_no_memset(xbt_mheap_t mdp, size_t size);
-
-/* Re-allocate the previously allocated block in void*, making the new block SIZE bytes long.  */
-XBT_PUBLIC void* mrealloc(xbt_mheap_t md, void* ptr, size_t size);
-
-/* Free a block allocated by `mmalloc', `mrealloc' or `mcalloc'.  */
-XBT_PUBLIC void mfree(xbt_mheap_t md, void* ptr);
-
-#define XBT_MHEAP_OPTION_MEMSET 1
-
-XBT_PUBLIC xbt_mheap_t xbt_mheap_new(void* baseaddr, int options);
-
-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
-
-#endif /* SIMGRID_MMALLOC_H */
diff --git a/src/xbt/mmalloc/mmalloc.info b/src/xbt/mmalloc/mmalloc.info
deleted file mode 100644 (file)
index 50fb1ba..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-This is ./mmalloc.info, produced by makeinfo version 4.6 from
-mmalloc.texi.
-
-START-INFO-DIR-ENTRY
-* Mmalloc: (mmalloc).          The GNU mapped-malloc package.
-END-INFO-DIR-ENTRY
-
-   This file documents the GNU mmalloc (mapped-malloc) package, written
-by fnf@cygnus.com, based on GNU malloc written by mike@ai.mit.edu.
-
-   Copyright (C) 1992 Free Software Foundation, Inc.
-
-   Permission is granted to make and distribute verbatim copies of this
-manual provided the copyright notice and this permission notice are
-preserved on all copies.
-
-   Permission is granted to copy and distribute modified versions of
-this manual under the conditions for verbatim copying, provided also
-that the entire resulting derived work is distributed under the terms
-of a permission notice identical to this one.
-
-   Permission is granted to copy and distribute translations of this
-manual into another language, under the above conditions for modified
-versions.
-
-\1f
-File: mmalloc.info,  Node: Top,  Next: Overview,  Prev: (dir),  Up: (dir)
-
-mmalloc
-*******
-
-This file documents the GNU memory-mapped malloc package mmalloc.
-
-* Menu:
-
-* Overview::                    Overall Description
-* Implementation::              Implementation
-
- --- The Detailed Node Listing ---
-
-Implementation
-
-* Compatibility::               Backwards Compatibility
-* Functions::                   Function Descriptions
-
-\1f
-File: mmalloc.info,  Node: Overview,  Next: Implementation,  Prev: Top,  Up: Top
-
-Overall Description
-*******************
-
-This is a heavily modified version of GNU `malloc'.  It uses `mmap' as
-the basic mechanism for obtaining memory from the system, rather than
-`sbrk'.  This gives it several advantages over the more traditional
-malloc:
-
-   * Several different heaps can be used, each of them growing or
-     shinking under control of `mmap', with the `mmalloc' functions
-     using a specific heap on a call by call basis.
-
-   * By using `mmap', it is easy to create heaps which are intended to
-     be persistent and exist as a filesystem object after the creating
-     process has gone away.
-
-   * Because multiple heaps can be managed, data used for a specific
-     purpose can be allocated into its own heap, making it easier to
-     allow applications to "dump" and "restore" initialized
-     malloc-managed memory regions.  For example, the "unexec" hack
-     popularized by GNU Emacs could potentially go away.
-
-\1f
-File: mmalloc.info,  Node: Implementation,  Prev: Overview,  Up: Top
-
-Implementation
-**************
-
-The `mmalloc' functions contain no internal static state.  All
-`mmalloc' internal data is allocated in the mapped in region, along
-with the user data that it manages.  This allows it to manage multiple
-such regions and to "pick up where it left off" when such regions are
-later dynamically mapped back in.
-
-   In some sense, malloc has been "purified" to contain no internal
-state information and generalized to use multiple memory regions rather
-than a single region managed by `sbrk'.  However the new routines now
-need an extra parameter which informs `mmalloc' which memory region it
-is dealing with (along with other information).  This parameter is
-called the "malloc descriptor".
-
-   The functions initially provided by `mmalloc' are:
-
-     void *mmalloc_attach (int fd, void *baseaddr);
-     void *mmalloc_detach (void *md);
-     int mmalloc_errno (void *md);
-     int mmalloc_setkey (void *md, int keynum, void *key);
-     void *mmalloc_getkey (void *md, int keynum);
-
-     void *mmalloc (void *md, size_t size);
-     void *mrealloc (void *md, void *ptr, size_t size);
-     void *mvalloc (void *md, size_t size);
-     void mfree (void *md, void *ptr);
-
-* Menu:
-
-* Compatibility::               Backwards Compatibility
-* Functions::                   Function Descriptions
-
-\1f
-File: mmalloc.info,  Node: Compatibility,  Next: Functions,  Prev: Implementation,  Up: Implementation
-
-Backwards Compatibility
-=======================
-
-To allow a single malloc package to be used in a given application,
-provision is made for the traditional `malloc', `realloc', and `free'
-functions to be implemented as special cases of the `mmalloc'
-functions.  In particular, if any of the functions that expect malloc
-descriptors are called with a `NULL' pointer rather than a valid malloc
-descriptor, then they default to using an `sbrk' managed region.  The
-`mmalloc' package provides compatible `malloc', `realloc', and `free'
-functions using this mechanism internally.  Applications can avoid this
-extra interface layer by simply including the following defines:
-
-     #define malloc(size)              mmalloc ((void *)0, (size))
-     #define realloc(ptr,size) mrealloc ((void *)0, (ptr), (size));
-     #define free(ptr)         mfree ((void *)0, (ptr))
-
-or replace the existing `malloc', `realloc', and `free' calls with the
-above patterns if using `#define' causes problems.
-
-\1f
-File: mmalloc.info,  Node: Functions,  Prev: Compatibility,  Up: Implementation
-
-Function Descriptions
-=====================
-
-These are the details on the functions that make up the `mmalloc'
-package.
-
-`void *mmalloc_attach (int FD, void *BASEADDR);'
-     Initialize access to a `mmalloc' managed region.
-
-     If FD is a valid file descriptor for an open file, then data for
-     the `mmalloc' managed region is mapped to that file.   Otherwise
-     `/dev/zero' is used and the data will not exist in any filesystem
-     object.
-
-     If the open file corresponding to FD is from a previous use of
-     `mmalloc' and passes some basic sanity checks to ensure that it is
-     compatible with the current `mmalloc' package, then its data is
-     mapped in and is immediately accessible at the same addresses in
-     the current process as the process that created the file.
-
-     If BASEADDR is not `NULL', the mapping is established starting at
-     the specified address in the process address space.  If BASEADDR
-     is `NULL', the `mmalloc' package chooses a suitable address at
-     which to start the mapped region, which will be the value of the
-     previous mapping if opening an existing file which was previously
-     built by `mmalloc', or for new files will be a value chosen by
-     `mmap'.
-
-     Specifying BASEADDR provides more control over where the regions
-     start and how big they can be before bumping into existing mapped
-     regions or future mapped regions.
-
-     On success, returns a malloc descriptor which is used in subsequent
-     calls to other `mmalloc' package functions.  It is explicitly
-     `void *' (`char *' for systems that don't fully support `void') so
-     that users of the package don't have to worry about the actual
-     implementation details.
-
-     On failure returns `NULL'.
-
-`void *mmalloc_detach (void *MD);'
-     Terminate access to a `mmalloc' managed region identified by the
-     descriptor MD, by closing the base file and unmapping all memory
-     pages associated with the region.
-
-     Returns `NULL' on success.
-
-     Returns the malloc descriptor on failure, which can subsequently
-     be used for further action (such as obtaining more information
-     about the nature of the failure).
-
-`void *mmalloc (void *MD, size_t SIZE);'
-     Given an `mmalloc' descriptor MD, allocate additional memory of
-     SIZE bytes in the associated mapped region.
-
-`*mrealloc (void *MD, void *PTR, size_t SIZE);'
-     Given an `mmalloc' descriptor MD and a pointer to memory
-     previously allocated by `mmalloc' in PTR, reallocate the memory to
-     be SIZE bytes long, possibly moving the existing contents of
-     memory if necessary.
-
-`void *mvalloc (void *MD, size_t SIZE);'
-     Like `mmalloc' but the resulting memory is aligned on a page
-     boundary.
-
-`void mfree (void *MD, void *PTR);'
-     Given an `mmalloc' descriptor MD and a pointer to memory previously
-     allocated by `mmalloc' in PTR, free the previously allocated
-     memory.
-
-`int mmalloc_errno (void *MD);'
-     Given a `mmalloc' descriptor, if the last `mmalloc' operation
-     failed for some reason due to a system call failure, then returns
-     the associated `errno'.  Returns 0 otherwise.  (This function is
-     not yet implemented).
-
-
-\1f
-Tag Table:
-Node: Top\7f937
-Node: Overview\7f1370
-Node: Implementation\7f2395
-Node: Compatibility\7f3785
-Node: Functions\7f4856
-\1f
-End Tag Table
diff --git a/src/xbt/mmalloc/mmalloc.texi b/src/xbt/mmalloc/mmalloc.texi
deleted file mode 100644 (file)
index 0669995..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-\input texinfo  @c                                  -*- Texinfo -*-
-@setfilename mmalloc.info
-
-@ifinfo
-@format
-START-INFO-DIR-ENTRY
-* Mmalloc: (mmalloc).          The GNU mapped-malloc package.
-END-INFO-DIR-ENTRY
-@end format
-
-This file documents the GNU mmalloc (mapped-malloc) package, written by
-fnf@@cygnus.com, based on GNU malloc written by mike@@ai.mit.edu.
-
-Copyright (C) 1992 Free Software Foundation, Inc.
-
-Permission is granted to make and distribute verbatim copies of
-this manual provided the copyright notice and this permission notice
-are preserved on all copies.
-
-@ignore
-Permission is granted to process this file through Tex and print the
-results, provided the printed document carries copying permission
-notice identical to this one except for the removal of this paragraph
-(this paragraph not being relevant to the printed manual).
-
-@end ignore
-Permission is granted to copy and distribute modified versions of this
-manual under the conditions for verbatim copying, provided also that the
-entire resulting derived work is distributed under the terms of a
-permission notice identical to this one.
-
-Permission is granted to copy and distribute translations of this manual
-into another language, under the above conditions for modified versions.
-@end ifinfo
-@iftex
-@c @finalout
-@setchapternewpage odd
-@settitle MMALLOC, the GNU memory-mapped malloc package
-@titlepage
-@title mmalloc
-@subtitle The GNU memory-mapped malloc package
-@author Fred Fish
-@author Cygnus Support
-@author Mike Haertel
-@author Free Software Foundation
-@page
-
-@tex
-\def\$#1${{#1}}  % Kluge: collect RCS revision info without $...$
-\xdef\manvers{\$Revision: 1.4 $}  % For use in headers, footers too
-{\parskip=0pt
-\hfill Cygnus Support\par
-\hfill fnf\@cygnus.com\par
-\hfill {\it MMALLOC, the GNU memory-mapped malloc package}, \manvers\par
-\hfill \TeX{}info \texinfoversion\par
-}
-@end tex
-
-@vskip 0pt plus 1filll
-Copyright @copyright{} 1992 Free Software Foundation, Inc.
-
-Permission is granted to make and distribute verbatim copies of
-this manual provided the copyright notice and this permission notice
-are preserved on all copies.
-
-Permission is granted to copy and distribute modified versions of this
-manual under the conditions for verbatim copying, provided also that
-the entire resulting derived work is distributed under the terms of a
-permission notice identical to this one.
-
-Permission is granted to copy and distribute translations of this manual
-into another language, under the above conditions for modified versions.
-@end titlepage
-@end iftex
-
-@ifinfo
-@node Top, Overview, (dir), (dir)
-@top mmalloc
-This file documents the GNU memory-mapped malloc package mmalloc.
-
-@menu
-* Overview::                    Overall Description
-* Implementation::              Implementation
-
- --- The Detailed Node Listing ---
-
-Implementation
-
-* Compatibility::               Backwards Compatibility
-* Functions::                   Function Descriptions
-@end menu
-
-@end ifinfo
-
-@node Overview, Implementation, Top, Top
-@chapter Overall Description
-
-This is a heavily modified version of GNU @code{malloc}.  It uses
-@code{mmap} as the basic mechanism for obtaining memory from the
-system, rather than @code{sbrk}.  This gives it several advantages over the
-more traditional malloc:
-
-@itemize @bullet
-@item
-Several different heaps can be used, each of them growing
-or shinking under control of @code{mmap}, with the @code{mmalloc} functions
-using a specific heap on a call by call basis.
-
-@item
-By using @code{mmap}, it is easy to create heaps which are intended to
-be persistent and exist as a filesystem object after the creating
-process has gone away.
-
-@item
-Because multiple heaps can be managed, data used for a
-specific purpose can be allocated into its own heap, making
-it easier to allow applications to ``dump'' and ``restore'' initialized
-malloc-managed memory regions.  For example, the ``unexec'' hack popularized
-by GNU Emacs could potentially go away.
-@end itemize
-
-@node Implementation,  , Overview, Top
-@chapter Implementation
-
-The @code{mmalloc} functions contain no internal static state.  All
-@code{mmalloc} internal data is allocated in the mapped in region, along
-with the user data that it manages.  This allows it to manage multiple
-such regions and to ``pick up where it left off'' when such regions are
-later dynamically mapped back in.
-
-In some sense, malloc has been ``purified'' to contain no internal state
-information and generalized to use multiple memory regions rather than a
-single region managed by @code{sbrk}.  However the new routines now need an
-extra parameter which informs @code{mmalloc} which memory region it is dealing
-with (along with other information).  This parameter is called the
-@dfn{malloc descriptor}.
-
-The functions initially provided by @code{mmalloc} are:
-
-@example
-void *mmalloc_attach (int fd, void *baseaddr);
-void *mmalloc_detach (void *md);
-int mmalloc_errno (void *md);
-int mmalloc_setkey (void *md, int keynum, void *key);
-void *mmalloc_getkey (void *md, int keynum);
-
-void *mmalloc (void *md, size_t size);
-void *mrealloc (void *md, void *ptr, size_t size);
-void *mvalloc (void *md, size_t size);
-void mfree (void *md, void *ptr);
-@end example
-
-@menu
-* Compatibility::               Backwards Compatibility
-* Functions::                   Function Descriptions
-@end menu
-
-@node Compatibility, Functions, Implementation, Implementation
-@section Backwards Compatibility
-
-To allow a single malloc package to be used in a given application,
-provision is made for the traditional @code{malloc}, @code{realloc}, and
-@code{free} functions to be implemented as special cases of the
-@code{mmalloc} functions.  In particular, if any of the functions that
-expect malloc descriptors are called with a @code{NULL} pointer rather than a
-valid malloc descriptor, then they default to using an @code{sbrk} managed
-region.
-The @code{mmalloc} package provides compatible @code{malloc}, @code{realloc},
-and @code{free} functions using this mechanism internally.
-Applications can avoid this extra interface layer by simply including the
-following defines:
-
-@example
-#define malloc(size)           mmalloc ((void *)0, (size))
-#define realloc(ptr,size)      mrealloc ((void *)0, (ptr), (size));
-#define free(ptr)              mfree ((void *)0, (ptr))
-@end example
-
-@noindent
-or replace the existing @code{malloc}, @code{realloc}, and @code{free}
-calls with the above patterns if using @code{#define} causes problems.
-
-@node Functions,  , Compatibility, Implementation
-@section Function Descriptions
-
-These are the details on the functions that make up the @code{mmalloc}
-package.
-
-@table @code
-@item void *mmalloc_attach (int @var{fd}, void *@var{baseaddr});
-Initialize access to a @code{mmalloc} managed region.
-
-If @var{fd} is a valid file descriptor for an open file, then data for the
-@code{mmalloc} managed region is mapped to that file.   Otherwise
-@file{/dev/zero} is used and the data will not exist in any filesystem object.
-
-If the open file corresponding to @var{fd} is from a previous use of
-@code{mmalloc} and passes some basic sanity checks to ensure that it is
-compatible with the current @code{mmalloc} package, then its data is
-mapped in and is immediately accessible at the same addresses in
-the current process as the process that created the file.
-
-If @var{baseaddr} is not @code{NULL}, the mapping is established
-starting at the specified address in the process address space.  If
-@var{baseaddr} is @code{NULL}, the @code{mmalloc} package chooses a
-suitable address at which to start the mapped region, which will be the
-value of the previous mapping if opening an existing file which was
-previously built by @code{mmalloc}, or for new files will be a value
-chosen by @code{mmap}.
-
-Specifying @var{baseaddr} provides more control over where the regions
-start and how big they can be before bumping into existing mapped
-regions or future mapped regions.
-
-On success, returns a malloc descriptor which is used in subsequent
-calls to other @code{mmalloc} package functions.  It is explicitly
-@samp{void *} (@samp{char *} for systems that don't fully support
-@code{void}) so that users of the package don't have to worry about the
-actual implementation details.
-
-On failure returns @code{NULL}.
-
-@item void *mmalloc_detach (void *@var{md});
-Terminate access to a @code{mmalloc} managed region identified by the
-descriptor @var{md}, by closing the base file and unmapping all memory
-pages associated with the region.
-
-Returns @code{NULL} on success.
-
-Returns the malloc descriptor on failure, which can subsequently
-be used for further action (such as obtaining more information about
-the nature of the failure).
-
-@item void *mmalloc (void *@var{md}, size_t @var{size});
-Given an @code{mmalloc} descriptor @var{md}, allocate additional memory of
-@var{size} bytes in the associated mapped region.
-
-@item *mrealloc (void *@var{md}, void *@var{ptr}, size_t @var{size});
-Given an @code{mmalloc} descriptor @var{md} and a pointer to memory
-previously allocated by @code{mmalloc} in @var{ptr}, reallocate the
-memory to be @var{size} bytes long, possibly moving the existing
-contents of memory if necessary.
-
-@item void *mvalloc (void *@var{md}, size_t @var{size});
-Like @code{mmalloc} but the resulting memory is aligned on a page boundary.
-
-@item void mfree (void *@var{md}, void *@var{ptr});
-Given an @code{mmalloc} descriptor @var{md} and a pointer to memory previously
-allocated by @code{mmalloc} in @var{ptr}, free the previously allocated memory.
-
-@item int mmalloc_errno (void *@var{md});
-Given a @code{mmalloc} descriptor, if the last @code{mmalloc} operation
-failed for some reason due to a system call failure, then
-returns the associated @code{errno}.  Returns 0 otherwise.
-(This function is not yet implemented).
-@end table
-
-@bye
diff --git a/src/xbt/mmalloc/mmorecore.c b/src/xbt/mmalloc/mmorecore.c
deleted file mode 100644 (file)
index a5f9ff5..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* Support for an sbrk-like function that uses mmap. */
-
-/* Copyright (c) 2010-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Copyright 1992, 2000 Free Software Foundation, Inc.
-
-   Contributed by Fred Fish at Cygnus Support.   fnf@cygnus.com */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-#include <errno.h>
-
-#include "mmprivate.h"
-
-#ifndef MAP_ANONYMOUS
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
-#define PAGE_ALIGN(addr) (void*)(((unsigned long)(addr) + mmalloc_pagesize - 1) & ~(mmalloc_pagesize - 1))
-
-/** @brief Add memory to this heap
- *
- *  Get core for the memory region specified by MDP, using SIZE as the
- *  amount to either add to or subtract from the existing region.  Works
- *  like sbrk(), but using mmap().
- *
- *  It never returns NULL. Instead, it dies verbosely on errors.
- *
- *  @param mdp  The heap
- *  @param size Bytes to allocate for this heap (or <0 to free memory from this heap)
- */
-void *mmorecore(struct mdesc *mdp, ssize_t size)
-{
-  void* result;                 // please keep it uninitialized to track issues
-  size_t mapbytes;              /* Number of bytes to map */
-  void* moveto;                 /* Address where we wish to move "break value" to */
-  void* mapto;                  /* Address we actually mapped to */
-
-  if (size == 0) {
-    /* Just return the current "break" value. */
-    return mdp->breakval;
-  }
-
-  static unsigned long mmalloc_pagesize = 0;
-  if (!mmalloc_pagesize)
-    mmalloc_pagesize = (unsigned long)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. */
-    if (((char*)mdp->breakval) + size >= (char*)mdp->base) {
-      result        = mdp->breakval;
-      mdp->breakval = (char*)mdp->breakval + size;
-      moveto = PAGE_ALIGN(mdp->breakval);
-      munmap(moveto, (size_t)(((char*)mdp->top) - ((char*)moveto)) - 1);
-      mdp->top = moveto;
-    } else {
-      fprintf(stderr,"Internal error: mmap was asked to deallocate more memory than it previously allocated. Bailling out now!\n");
-      abort();
-    }
-  } else if ((char*)mdp->breakval + size > (char*)mdp->top) {
-    /* The request would move us past the end of the currently mapped memory, so map in enough more memory to satisfy
-       the request.  This means we also have to grow the mapped-to file by an appropriate amount, since mmap cannot
-       be used to extend a file. */
-    moveto   = PAGE_ALIGN((char*)mdp->breakval + size);
-    mapbytes = (char*)moveto - (char*)mdp->top;
-
-    /* Let's call mmap. Note that it is possible that mdp->top is 0. In this case mmap will choose the address for us.
-       This call might very well overwrite an already existing memory mapping (leading to weird bugs).
-    */
-    mapto = mmap(mdp->top, mapbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
-
-    if (mapto == MAP_FAILED) {
-      char buff[1024];
-      fprintf(stderr, "Internal error: mmap returned MAP_FAILED! pagesize:%lu 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))
-        fprintf(stderr, "Something went wrong when trying to %s\n", buff);
-      sleep(1);
-      abort();
-    }
-
-    if (mdp->top == 0)
-      mdp->base = mdp->breakval = mapto;
-
-    mdp->top      = PAGE_ALIGN((char*)mdp->breakval + size);
-    result        = mdp->breakval;
-    mdp->breakval = (char*)mdp->breakval + size;
-  } else {
-    /* Memory is already mapped, we only need to increase the breakval: */
-    result        = mdp->breakval;
-    mdp->breakval = (char*)mdp->breakval + size;
-  }
-  return result;
-}
diff --git a/src/xbt/mmalloc/mmprivate.h b/src/xbt/mmalloc/mmprivate.h
deleted file mode 100644 (file)
index e7ae79a..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/* Declarations for `mmalloc' and friends. */
-
-/* Copyright (c) 2010-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Copyright 1990, 1991, 1992 Free Software Foundation
-
-   Written May 1989 by Mike Haertel.
-   Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com) */
-
-#ifndef XBT_MMPRIVATE_H
-#define XBT_MMPRIVATE_H 1
-
-#include "src/internal_config.h"
-#include "src/xbt/mmalloc/mmalloc.h"
-#include "swag.h"
-
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.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_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 */
-#define MMALLOC_VERSION    2       /* Current mmalloc version */
-
-/* The allocator divides the heap into blocks of fixed size; large
-   requests receive one or more whole blocks, and small requests
-   receive a fragment of a block.  Fragment sizes are powers of two,
-   and all fragments of a block are the same size.  When all the
-   fragments in a block have been freed, the block itself is freed.
-
-   FIXME: we are not targeting 16bits machines anymore; update values */
-
-#define INT_BIT    (CHAR_BIT * sizeof(int))
-#define BLOCKLOG  (INT_BIT > 16 ? 12 : 9)
-#define BLOCKSIZE  ((unsigned int) 1 << BLOCKLOG)
-#define BLOCKIFY(SIZE)  (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
-
-/* We keep fragment-specific meta-data for introspection purposes, and these
- * information are kept in fixed length arrays. Here is the computation of
- * that size.
- *
- * 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 (32 * sizeof(void*))
-#define MAX_FRAGMENT_PER_BLOCK (BLOCKSIZE / SMALLEST_POSSIBLE_MALLOC)
-
-/* The difference between two pointers is a signed int.  On machines where
-   the data addresses have the high bit set, we need to ensure that the
-   difference becomes an unsigned int when we are using the address as an
-   integral value.  In addition, when using with the '%' operator, the
-   sign of the result is machine dependent for negative values, so force
-   it to be treated as an unsigned int. */
-
-#define ADDR2UINT(addr)  ((uintptr_t) (addr))
-#define RESIDUAL(addr,bsize) ((uintptr_t) (ADDR2UINT (addr) % (bsize)))
-
-/* Determine the amount of memory spanned by the initial heap table
-   (not an absolute limit).  */
-
-#define HEAP    (INT_BIT > 16 ? 4194304 : 65536)
-
-/* Number of contiguous free blocks allowed to build up at the end of
-   memory before they will be returned to the system.
-   FIXME: this is not used anymore: we never return memory to the system. */
-#define FINAL_FREE_BLOCKS  8
-
-/* Where to start searching the free list when looking for new memory.
-   The two possible values are 0 and heapindex.  Starting at 0 seems
-   to reduce total memory usage, while starting at heapindex seems to
-   run faster.  */
-
-#define MALLOC_SEARCH_START  mdp -> heapindex
-
-/* Address to block number and vice versa.  */
-
-#define BLOCK(A) ((size_t)(((char*)(A) - (char*)mdp->heapbase) / BLOCKSIZE + 1))
-
-#define ADDRESS(B) ((void*) (((ADDR2UINT(B)) - 1) * BLOCKSIZE + (char*) mdp -> heapbase))
-
-SG_BEGIN_DECL
-
-/* Statistics available to the user. */
-struct mstats
-{
-  size_t bytes_total;    /* Total size of the heap. */
-  size_t chunks_used;    /* Chunks allocated by the user. */
-  size_t bytes_used;    /* Byte total of user-allocated chunks. */
-  size_t chunks_free;    /* Chunks in the free list. */
-  size_t bytes_free;    /* Byte total of chunks in the free list. */
-};
-
-#define MMALLOC_TYPE_HEAPINFO (-2)
-#define MMALLOC_TYPE_FREE (-1)
-#define MMALLOC_TYPE_UNFRAGMENTED 0
-/* >0 values are fragmented blocks */
-
-/* Data structure giving per-block information.
- *
- * There is one such structure in the mdp->heapinfo array per block used in that heap,
- *    the array index is the block number.
- *
- * There is several types of blocks in memory:
- *  - full busy blocks: used when we are asked to malloc a block which size is > BLOCKSIZE/2
- *    In this situation, the full block is given to the malloc.
- *
- *  - fragmented busy blocks: when asked for smaller amount of memory.
- *    Fragment sizes are only power of 2. When looking for such a free fragment,
- *    we get one from mdp->fraghead (that contains a linked list of blocks fragmented at that
- *    size and containing a free fragment), or we get a fresh block that we fragment.
- *
- *  - free blocks are grouped by clusters, that are chained together.
- *    When looking for free blocks, we traverse the mdp->heapinfo looking
- *    for a cluster of free blocks that would be large enough.
- *
- *    The size of the cluster is only to be trusted in the first block of the cluster, not in the middle blocks.
- *
- * The type field is consistently updated for every blocks, even within clusters of blocks.
- * You can crawl the array and rely on that value.
- *
- */
-typedef struct {
-  s_xbt_swag_hookup_t freehook; /* to register this block as having empty frags when needed */
-  int type; /*  0: busy large block
-                >0: busy fragmented (fragments of size 2^type bytes)
-                <0: free block */
-
-  union {
-    /* Heap information for a busy block.  */
-    struct {
-      size_t nfree;               /* Free fragments in a fragmented block.  */
-      ssize_t frag_size[MAX_FRAGMENT_PER_BLOCK];
-      int ignore[MAX_FRAGMENT_PER_BLOCK];
-    } busy_frag;
-    struct {
-      size_t size; /* Size (in blocks) of a large cluster.  */
-      size_t busy_size; /* Actually used space, in bytes */
-      int ignore;
-    } busy_block;
-    /* Heap information for a free block (that may be the first of a free cluster).  */
-    struct {
-      size_t size;                /* Size (in blocks) of a free cluster.  */
-      size_t next;                /* Index of next free cluster.  */
-      size_t prev;                /* Index of previous free cluster.  */
-    } free_block;
-  };
-} malloc_info;
-
-/** @brief Descriptor of a mmalloc area
- *
- * Internal structure that defines the format of the malloc-descriptor.
- * This gets written to the base address of the region that mmalloc is
- * managing, and thus also becomes the file header for the mapped file,
- * if such a file exists.
- * */
-struct mdesc {
-  /** @brief Chained lists of mdescs */
-  struct mdesc *next_mdesc;
-
-  /** @brief The "magic number" for an mmalloc file. */
-  char magic[MMALLOC_MAGIC_SIZE];
-
-  /** @brief The size in bytes of this structure
-   *
-   * Used as a sanity check when reusing a previously created mapped file.
-   * */
-  unsigned int headersize;
-
-  /** @brief Version number of the mmalloc package that created this file. */
-  unsigned char version;
-
-  unsigned int options;
-
-  /** @brief Some flag bits to keep track of various internal things. */
-  unsigned int flags;
-
-  /** @brief Number of info entries.  */
-  size_t heapsize;
-
-  /** @brief Pointer to first block of the heap (base of the first block).  */
-  void *heapbase;
-
-  /** @brief Current search index for the heap table.
-   *
-   *  Search index in the info table.
-   */
-  size_t heapindex;
-
-  /** @brief Limit of valid info table indices.  */
-  size_t heaplimit;
-
-  /** @brief Block information table.
-   *
-   * Table indexed by block number giving per-block information.
-   */
-  malloc_info *heapinfo;
-
-  /* @brief List of all blocks containing free fragments of a given size.
-   *
-   * The array index is the log2 of requested size.
-   * Actually only the sizes 8->11 seem to be used, but who cares? */
-  s_xbt_swag_t fraghead[BLOCKLOG];
-
-  /* @brief Base address of the memory region for this malloc heap
-   *
-   * This is the location where the bookkeeping data for mmap and
-   * for malloc begins.
-   */
-  void *base;
-
-  /** @brief End of memory in use
-   *
-   *  Some memory might be already mapped by the OS but not used
-   *  by the heap.
-   * */
-  void *breakval;
-
-  /** @brief End of the current memory region for this malloc heap.
-   *
-   *  This is the first location past the end of mapped memory.
-   *
-   *  Compared to breakval, this value is rounded to the next memory page.
-   */
-  void *top;
-
-  /* @brief Instrumentation */
-  struct mstats heapstats;
-};
-
-/* Bits to look at in the malloc descriptor flags word */
-
-#define MMALLOC_DEVZERO    (1 << 0)        /* Have mapped to /dev/zero */
-#define MMALLOC_INITIALIZED (1 << 1)      /* Initialized mmalloc */
-
-/* A default malloc descriptor for the single sbrk() managed region. */
-
-XBT_PUBLIC_DATA struct mdesc* __mmalloc_default_mdp;
-
-XBT_PUBLIC void* mmorecore(struct mdesc* mdp, ssize_t size);
-
-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
diff --git a/src/xbt/mmalloc/mrealloc.c b/src/xbt/mmalloc/mrealloc.c
deleted file mode 100644 (file)
index 662cc0a..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* Change the size of a block allocated by `mmalloc'. */
-
-/* Copyright (c) 2010-2023. The SimGrid Team.
- * All rights reserved.                                                     */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Copyright 1990, 1991 Free Software Foundation
-   Written May 1989 by Mike Haertel. */
-
-#include <string.h>             /* Prototypes for memcpy, memmove, memset, etc */
-#include <stdlib.h> /* abort */
-
-#include "mmprivate.h"
-
-#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
-/* Resize the given region to the new size, returning a pointer to the (possibly moved) region. This is optimized for
- * speed; some benchmarks seem to indicate that greater compactness is achieved by unconditionally allocating and
- * copying to a new region.  This module has incestuous knowledge of the internals of both mfree and mmalloc. */
-
-void *mrealloc(xbt_mheap_t mdp, void *ptr, size_t size)
-{
-  void *result;
-  size_t blocks;
-
-  /* Only keep real realloc, and reroute hidden malloc and free to the relevant functions */
-  if (size == 0) {
-    mfree(mdp, ptr);
-    return mmalloc(mdp, 0);
-  } else if (ptr == NULL) {
-    return mmalloc(mdp, size);
-  }
-
-  if ((char *) ptr < (char *) mdp->heapbase || BLOCK(ptr) > mdp->heapsize) {
-    // Don't trust xbt_assert and friends in malloc-level library, you fool!
-    fprintf(stderr, "This pointer is not mine, refusing to realloc it (maybe you wanted to malloc it instead?)\n");
-    abort();
-  }
-
-  size_t requested_size = size; // The amount of memory requested by user, for real
-
-  /* Work even if the user was stupid enough to ask a ridiculously small block (even 0-length),
-   *    ie return a valid block that can be realloced and freed.
-   * glibc malloc does not use this trick but return a constant pointer, but we need to enlist the free fragments later on.
-   */
-  if (size < SMALLEST_POSSIBLE_MALLOC)
-    size = SMALLEST_POSSIBLE_MALLOC;
-
-  size_t block = BLOCK(ptr);
-
-  int type = mdp->heapinfo[block].type;
-
-  switch (type) {
-  case MMALLOC_TYPE_HEAPINFO:
-    fprintf(stderr, "Asked realloc a fragment coming from a heapinfo block. I'm confused.\n");
-    abort();
-    break;
-
-  case MMALLOC_TYPE_FREE:
-    fprintf(stderr, "Asked realloc a fragment coming from a *free* block. I'm puzzled.\n");
-    abort();
-    break;
-
-  case MMALLOC_TYPE_UNFRAGMENTED:
-    /* Maybe reallocate a large block to a small fragment.  */
-
-    if (size <= BLOCKSIZE / 2) { // Full block -> Fragment; no need to optimize for time
-
-      result = mmalloc(mdp, size);
-      memcpy(result, ptr, requested_size);
-      mfree(mdp, ptr);
-      return result;
-    }
-
-    /* Full blocks -> Full blocks; see if we can hold it in place. */
-    blocks = BLOCKIFY(size);
-    if (blocks < mdp->heapinfo[block].busy_block.size) {
-      /* The new size is smaller; return excess memory to the free list. */
-      for (size_t it = block + blocks; it < mdp->heapinfo[block].busy_block.size; it++) {
-        mdp->heapinfo[it].type = MMALLOC_TYPE_UNFRAGMENTED; // FIXME that should be useless, type should already be 0 here
-        mdp->heapinfo[it].busy_block.ignore = 0;
-        mdp->heapinfo[it].busy_block.size = 0;
-        mdp->heapinfo[it].busy_block.busy_size = 0;
-      }
-
-      mdp->heapinfo[block + blocks].busy_block.size = mdp->heapinfo[block].busy_block.size - blocks;
-      mfree(mdp, ADDRESS(block + blocks));
-
-      mdp->heapinfo[block].busy_block.size = blocks;
-      mdp->heapinfo[block].busy_block.busy_size = requested_size;
-      mdp->heapinfo[block].busy_block.ignore = 0;
-
-      result = ptr;
-    } else if (blocks == mdp->heapinfo[block].busy_block.size) {
-
-      /* No block size change necessary; only update the requested size  */
-      result = ptr;
-      mdp->heapinfo[block].busy_block.busy_size = requested_size;
-      mdp->heapinfo[block].busy_block.ignore = 0;
-
-    } else {
-      /* Won't fit, so allocate a new region that will.
-         Free the old region first in case there is sufficient adjacent free space to grow without moving.
-         This trick mandates using a specific version of mmalloc that does not memset the memory to 0 after
-           action for obvious reasons. */
-      blocks = mdp->heapinfo[block].busy_block.size;
-      /* Prevent free from actually returning memory to the system.  */
-      size_t oldlimit = mdp->heaplimit;
-      mdp->heaplimit = 0;
-      mfree(mdp, ptr);
-      mdp->heaplimit = oldlimit;
-
-      result = mmalloc_no_memset(mdp, requested_size);
-
-      if (ptr != result)
-        memmove(result, ptr, blocks * BLOCKSIZE);
-      /* FIXME: we should memset the end of the recently area */
-    }
-    break;
-
-  default: /* Fragment -> ??; type=logarithm to base two of the fragment size.  */
-
-    if (type <= 0) {
-      fprintf(stderr, "Unknown mmalloc block type.\n");
-      abort();
-    }
-
-    if (size > ((size_t)1 << (type - 1)) && size <= ((size_t)1 << type)) {
-      /* The new size is the same kind of fragment.  */
-
-      result = ptr;
-      uintptr_t frag_nb                                 = RESIDUAL(result, BLOCKSIZE) >> type;
-      mdp->heapinfo[block].busy_frag.frag_size[frag_nb] = requested_size;
-      mdp->heapinfo[block].busy_frag.ignore[frag_nb] = 0;
-
-    } else { /* fragment -> Either other fragment, or block */
-      /* The new size is different; allocate a new space,
-         and copy the lesser of the new size and the old. */
-
-      result = mmalloc(mdp, requested_size);
-
-      memcpy(result, ptr, MIN(requested_size, (size_t) 1 << type));
-      mfree(mdp, ptr);
-    }
-    break;
-  }
-  return result;
-}
diff --git a/src/xbt/mmalloc/swag.c b/src/xbt/mmalloc/swag.c
deleted file mode 100644 (file)
index eff8368..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Copyright (c) 2004-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Warning, this module is done to be efficient and performs tons of
-   cast and dirty things. So avoid using it unless you really know
-   what you are doing. */
-
-/* This type should be added to a type that is to be used in such a swag */
-
-#include "swag.h"
-#include "mmprivate.h" // mmalloc_assert
-
-typedef s_xbt_swag_hookup_t *xbt_swag_hookup_t;
-typedef struct xbt_swag* xbt_swag_t;
-typedef const struct xbt_swag* const_xbt_swag_t;
-
-#define xbt_swag_getPrev(obj, offset) (((xbt_swag_hookup_t)(((char*)(obj)) + (offset)))->prev)
-#define xbt_swag_getNext(obj, offset) (((xbt_swag_hookup_t)(((char*)(obj)) + (offset)))->next)
-#define xbt_swag_belongs(obj, swag) (xbt_swag_getNext((obj), (swag)->offset) || (swag)->tail == (obj))
-
-static inline void *xbt_swag_getFirst(const_xbt_swag_t swag)
-{
-  return swag->head;
-}
-
-/*
- * @brief Offset computation
- * @arg var a variable of type <tt>struct</tt> something
- * @arg field a field of <tt>struct</tt> something
- * @return the offset of @a field in <tt>struct</tt> something.
- * @hideinitializer
- *
- * It is very similar to offsetof except that is done at runtime and that you have to declare a variable. Why defining
- * such a macro then ? Because it is portable...
- */
-#define xbt_swag_offset(var, field) ((char*)&((var).field) - (char*)&(var))
-/* @} */
-
-/* Creates a new swag.
- * @param swag the swag to initialize
- * @param offset where the hookup is located in the structure
- * @see xbt_swag_offset
- *
- * Usage : xbt_swag_init(swag,&obj.setA-&obj);
- */
-static inline void xbt_swag_init(xbt_swag_t swag, size_t offset)
-{
-  swag->tail   = NULL;
-  swag->head   = NULL;
-  swag->offset = offset;
-  swag->count  = 0;
-}
-
-/*
- * @param obj the object to insert in the swag
- * @param swag a swag
- *
- * insert (at the tail... you probably had a very good reason to do that, I hope you know what you're doing) @a obj in
- * @a swag
- */
-static inline void xbt_swag_insert(void *obj, xbt_swag_t swag)
-{
-
-  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) {
-    mmalloc_assert(!(swag->tail), "Inconsistent swag.");
-    swag->head = obj;
-    swag->tail = obj;
-    swag->count++;
-  } else if (obj != swag->tail && !xbt_swag_getNext(obj, swag->offset)) {
-    xbt_swag_getPrev(obj, swag->offset)        = swag->tail;
-    xbt_swag_getNext(swag->tail, swag->offset) = obj;
-    swag->tail = obj;
-    swag->count++;
-  }
-}
-
-/*
- * @param obj the object to remove from the swag
- * @param swag a swag
- * @return @a obj if it was in the @a swag and NULL otherwise
- *
- * removes @a obj from @a swag
- */
-static inline void *xbt_swag_remove(void *obj, xbt_swag_t swag)
-{
-  if (!obj)
-    return NULL;
-
-  size_t offset = swag->offset;
-  void* prev    = xbt_swag_getPrev(obj, offset);
-  void* next    = xbt_swag_getNext(obj, offset);
-
-  if (prev) {
-    xbt_swag_getNext(prev, offset) = next;
-    xbt_swag_getPrev(obj, offset)  = NULL;
-    if (next) {
-      xbt_swag_getPrev(next, offset) = prev;
-      xbt_swag_getNext(obj, offset)  = NULL;
-    } else {
-      swag->tail = prev;
-    }
-    swag->count--;
-  } else if (next) {
-    xbt_swag_getPrev(next, offset) = NULL;
-    xbt_swag_getNext(obj, offset)  = NULL;
-    swag->head = next;
-    swag->count--;
-  } else if (obj == swag->head) {
-    swag->head = swag->tail = NULL;
-    swag->count--;
-  }
-
-  return obj;
-}
-
-/*
- * @param swag a swag
- * @return the number of objects in @a swag
- */
-static inline int xbt_swag_size(const_xbt_swag_t swag)
-{
-  return swag->count;
-}
diff --git a/src/xbt/mmalloc/swag.h b/src/xbt/mmalloc/swag.h
deleted file mode 100644 (file)
index 7997da2..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright (c) 2004-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Warning, this module is done to be efficient and performs tons of cast and dirty things. So avoid using it unless
- * you really know what you are doing. */
-
-#ifndef XBT_SWAG_H
-#define XBT_SWAG_H
-
-/*
- * XBT_swag: a O(1) set based on linked lists
- *
- *  Warning, this module is done to be efficient and performs tons of cast and dirty things. So make sure you know what
- *  you are doing while using it.
- *  It is basically a fifo but with restrictions so that it can be used as a set. Any operation (add, remove, belongs)
- *  is O(1) and no call to malloc/free is done.
- *
- *  @deprecated If you are using C++, you might want to use `boost::intrusive::set` instead.
- */
-
-/* Swag types
- *
- *  Specific set.
- *
- *  These typedefs are public so that the compiler can do his job but believe me, you don't want to try to play with
- *  those structs directly. Use them as an abstract datatype.
- */
-
-typedef struct xbt_swag_hookup {
-  void *next;
-  void *prev;
-} s_xbt_swag_hookup_t;
-
-/* This type should be added to a type that is to be used in a swag.
- *
- *  Whenever a new object with this struct is created, all fields have to be set to NULL
- *
- * Here is an example like that :
-
-\code
-typedef struct foo {
-  s_xbt_swag_hookup_t set1_hookup;
-  s_xbt_swag_hookup_t set2_hookup;
-
-  double value;
-} s_foo_t, *foo_t;
-...
-{
-  s_foo_t elem;
-  xbt_swag_t set1=NULL;
-  xbt_swag_t set2=NULL;
-
-  set1 = xbt_swag_new(xbt_swag_offset(elem, set1_hookup));
-  set2 = xbt_swag_new(xbt_swag_offset(elem, set2_hookup));
-
-}
-\endcode
-*/
-
-struct xbt_swag {
-  void *head;
-  void *tail;
-  size_t offset;
-  int count;
-};
-typedef struct xbt_swag s_xbt_swag_t;
-
-#endif /* XBT_SWAG_H */
index 7c02fa1..2835abe 100644 (file)
@@ -282,7 +282,7 @@ template <typename T> typename Parmap<T>::Synchro* Parmap<T>::new_synchro(e_xbt_
 /** @brief Main function of a worker thread */
 template <typename T> void Parmap<T>::worker_main(ThreadData* data)
 {
-  auto engine                       = simgrid::kernel::EngineImpl::get_instance();
+  const auto* engine                = simgrid::kernel::EngineImpl::get_instance();
   Parmap<T>& parmap                 = data->parmap;
   unsigned round                    = 0;
   kernel::context::Context* context = engine->get_context_factory()->create_context(std::function<void()>(), nullptr);
index e865995..60c73ea 100644 (file)
@@ -12,8 +12,8 @@
 namespace simgrid::xbt {
 
 template <typename T> struct ref_or_value {
-  using type = std::conditional_t<std::is_lvalue_reference<T>::value,
-                                  std::reference_wrapper<typename std::remove_reference<T>::type>, T>;
+  using type =
+      std::conditional_t<std::is_lvalue_reference_v<T>, std::reference_wrapper<typename std::remove_reference_t<T>>, T>;
 };
 template <typename T> using ref_or_value_t = typename ref_or_value<T>::type;
 
@@ -48,7 +48,7 @@ private:
   friend constexpr iterator_wrapping<IteratorType, Arguments...> make_iterator_wrapping_explicit(Arguments... args);
 
 public:
-  iterator_wrapping(Args&&... begin_iteration) : m_args(std::forward<ref_or_value_t<Args>>(begin_iteration)...) {}
+  iterator_wrapping(Args&&... begin_iteration) : m_args(ref_or_value_t<Args>(begin_iteration)...) {}
   iterator_wrapping(const iterator_wrapping&)            = delete;
   iterator_wrapping(iterator_wrapping&&)                 = delete;
   iterator_wrapping& operator=(const iterator_wrapping&) = delete;
@@ -70,7 +70,7 @@ constexpr iterator_wrapping<Iterator, Args...> make_iterator_wrapping(Args&&...
 template <typename Iterator, typename... Args>
 constexpr iterator_wrapping<Iterator, Args...> make_iterator_wrapping_explicit(Args... args)
 {
-  return iterator_wrapping<Iterator, Args...>(std::forward<Args>(args)...);
+  return iterator_wrapping<Iterator, Args...>(args...);
 }
 
 } // namespace simgrid::xbt
index 1ce6a93..68e0970 100644 (file)
@@ -29,7 +29,7 @@ namespace simgrid::xbt {
 template <class Iterator>
 struct powerset_iterator : public boost::iterator_facade<powerset_iterator<Iterator>, const std::vector<Iterator>,
                                                          boost::forward_traversal_tag> {
-  powerset_iterator() = default;
+  powerset_iterator()                                                                 = default;
   explicit powerset_iterator(Iterator begin, Iterator end = Iterator());
 
 private:
@@ -40,8 +40,6 @@ private:
   std::optional<subsets_iterator<Iterator>> current_subset_iter     = std::nullopt;
   std::optional<subsets_iterator<Iterator>> current_subset_iter_end = std::nullopt;
 
-  const std::vector<Iterator> empty_subset = std::vector<Iterator>();
-
   // boost::iterator_facade<...> interface to implement
   void increment();
   bool equal(const powerset_iterator<Iterator>& other) const;
@@ -70,13 +68,14 @@ template <typename Iterator> const std::vector<Iterator>& powerset_iterator<Iter
   if (current_subset_iter.has_value()) {
     return *current_subset_iter.value();
   }
+  static const std::vector<Iterator> empty_subset;
   return empty_subset;
 }
 
 template <typename Iterator> void powerset_iterator<Iterator>::increment()
 {
-  if (!current_subset_iter.has_value() || !current_subset_iter_end.has_value() ||
-      !current_subset_iter.has_value() || !iterator_end.has_value()) {
+  if (not current_subset_iter.has_value() || not current_subset_iter_end.has_value() ||
+      not current_subset_iter.has_value() || not iterator_end.has_value()) {
     return; // We've traversed all subsets at this point, or we're the "last" iterator
   }
 
index 1abea21..ec3cac8 100644 (file)
@@ -73,7 +73,7 @@ subsets_iterator<Iterator>::subsets_iterator(unsigned k, Iterator begin, Iterato
 
 template <typename Iterator> bool subsets_iterator<Iterator>::equal(const subsets_iterator<Iterator>& other) const
 {
-  if (this->end == std::nullopt and other.end == std::nullopt) {
+  if (this->end == std::nullopt && other.end == std::nullopt) {
     return true;
   }
   if (this->k != other.k) {
@@ -82,7 +82,7 @@ template <typename Iterator> bool subsets_iterator<Iterator>::equal(const subset
   if (this->k == 0) { // this->k == other.k == 0
     return true;
   }
-  return this->end != std::nullopt and other.end != std::nullopt and this->P[0] == other.P[0];
+  return this->end != std::nullopt && other.end != std::nullopt && this->P[0] == other.P[0];
 }
 
 template <typename Iterator> const std::vector<Iterator>& subsets_iterator<Iterator>::dereference() const
@@ -103,14 +103,13 @@ template <typename Iterator> void subsets_iterator<Iterator>::increment()
   ++current_subset[k - 1];
   ++P[k - 1];
 
-  const auto end                  = this->end.value();
-  const bool shift_other_elements = current_subset[k - 1] == end;
+  const bool shift_other_elements = current_subset[k - 1] == end.value();
 
   if (shift_other_elements) {
     if (k == 1) {
       // We're done in the case that k = 1; here, we've iterated
       // through the list once, which is all that is needed
-      this->end = std::nullopt;
+      end = std::nullopt;
       return;
     }
 
@@ -150,7 +149,7 @@ template <typename Iterator> void subsets_iterator<Iterator>::increment()
     // element can be located. Thus, if `P[0] > (n - k)`, this means
     // we've sucessfully iterated through all subsets so we're done
     if (P[0] > (n - k)) {
-      this->end = std::nullopt;
+      end = std::nullopt;
       return;
     }
 
index 41bdf41..fd7cee5 100644 (file)
@@ -26,7 +26,7 @@ TEST_CASE("simgrid::xbt::subsets_iterator: Iteration General Properties")
   SECTION("Each element of each subset is distinct")
   {
     for (unsigned k = 0; static_cast<size_t>(k) < example_vec.size(); k++) {
-      for (auto& subset : make_k_subsets_iter(k, example_vec)) {
+      for (const auto& subset : make_k_subsets_iter(k, example_vec)) {
         // Each subset must have size `k`
         REQUIRE(subset.size() == k);
 
@@ -49,12 +49,12 @@ TEST_CASE("simgrid::xbt::powerset_iterator: Iteration General Properties")
   SECTION("Each element of each subset is distinct and appears half of the time in all subsets iteration")
   {
     // Each element is expected to be found in half of the sets
-    const unsigned k         = static_cast<unsigned>(example_vec.size());
+    const auto k             = static_cast<unsigned>(example_vec.size());
     const int expected_count = integer_power(2, k - 1);
 
     std::unordered_map<int, int> element_counts(k);
 
-    for (auto& subset : make_powerset_iter(example_vec)) {
+    for (const auto& subset : make_powerset_iter(example_vec)) {
       // Each subset must be comprised only of distinct elements
       std::unordered_set<int> elements_seen(k);
       for (const auto& element_ptr : subset) {
@@ -65,8 +65,8 @@ TEST_CASE("simgrid::xbt::powerset_iterator: Iteration General Properties")
       }
     }
 
-    for (const auto& iter : element_counts) {
-      REQUIRE(iter.second == expected_count);
+    for (const auto& [_, count] : element_counts) {
+      REQUIRE(count == expected_count);
     }
   }
 }
@@ -187,4 +187,4 @@ TEST_CASE("simgrid::xbt::variable_for_loop: Edge Cases")
               (outer_loop1.size() * outer_loop2.size() * outer_loop3.size() * outer_loop4.size() * outer_loop5.size()));
     }
   }
-}
\ No newline at end of file
+}
index bd5d29a..f283f66 100644 (file)
@@ -51,7 +51,7 @@ public:
     const auto has_effect =
         std::none_of(collections.begin(), collections.end(), [](const auto& c) { return c.get().empty(); });
 
-    if (has_effect and (not collections.empty())) {
+    if (has_effect && (not collections.empty())) {
       std::transform(collections.begin(), collections.end(), std::back_inserter(current_subset),
                      [](const auto& c) { return c.get().cbegin(); });
       underlying_collections = std::move(collections);
@@ -76,7 +76,7 @@ template <typename IterableType> void variable_for_loop<IterableType>::increment
 {
   // Termination occurs when `current_subset := the empty set`
   // or if we have nothing to iterate over
-  if (current_subset.empty() or underlying_collections.empty()) {
+  if (current_subset.empty() || underlying_collections.empty()) {
     return;
   }
 
@@ -85,11 +85,11 @@ template <typename IterableType> void variable_for_loop<IterableType>::increment
 
   for (auto j = k; j != std::numeric_limits<size_t>::max(); j--) {
     // Attempt to move to the next element of the `j`th collection
-    const auto& new_position = ++current_subset[j];
+    ++current_subset[j];
 
     // If the `j`th element has reached its own end, reset it
     // back to the beginning and keep moving forward
-    if (new_position == underlying_collections[j].get().cend()) {
+    if (current_subset[j] == underlying_collections[j].get().cend()) {
       current_subset[j] = underlying_collections[j].get().cbegin();
     } else {
       // Otherwise we've found the largest element which needed to
index b6a16ad..f0d5401 100644 (file)
@@ -40,11 +40,11 @@ double xbt_os_time(void)
 #if HAVE_GETTIMEOFDAY
   struct timeval tv;
   gettimeofday(&tv, NULL);
+
+  return (double)tv.tv_sec + (double)tv.tv_usec / 1e6;
 #else                           /* no gettimeofday => poor resolution */
   return (double) (time(NULL));
 #endif                          /* HAVE_GETTIMEOFDAY? */
-
-  return (double)tv.tv_sec + (double)tv.tv_usec / 1e6;
 }
 
 void xbt_os_sleep(double sec)
@@ -59,7 +59,7 @@ void xbt_os_sleep(double sec)
   struct timeval timeout;
 
   timeout.tv_sec  = (long)sec;
-  timeout.tv_usec = (long)(sec - floor(sec)) * 1e6);
+  timeout.tv_usec = (long)(sec - floor(sec)) * 1e6;
 
   select(0, NULL, NULL, NULL, &timeout);
 #endif
index 129923d..5ec629a 100644 (file)
@@ -1,10 +1,5 @@
-if (NOT SIMGRID_HAVE_MC)
-  set(dwarf_disable 1)
-  set(dwarf-expression_disable 1)
-endif()
-
 
-foreach(x dwarf dwarf-expression random-bug mutex-handling)
+foreach(x random-bug mutex-handling)
 
   if(NOT DEFINED ${x}_sources)
     set(${x}_sources ${x}/${x}.cpp)
@@ -36,13 +31,8 @@ set_target_properties(without-mutex-handling PROPERTIES COMPILE_FLAGS -DDISABLE_
 set_target_properties(without-mutex-handling PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mutex-handling)
 add_dependencies(tests-mc without-mutex-handling)
 
-set(teshsuite_src  ${teshsuite_src}                                                                        PARENT_SCOPE)
-set(tesh_files     ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/random-bug/random-bug-replay.tesh
-                                    ${CMAKE_CURRENT_SOURCE_DIR}/mutex-handling/without-mutex-handling.tesh PARENT_SCOPE)
-
+ADD_TESH(mc-random-bug-replay                --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/mc/random-bug --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/mc/random-bug random-bug-replay.tesh)
 IF(SIMGRID_HAVE_MC)
-  ADD_TESH(tesh-mc-dwarf                       --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/mc/dwarf            --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/mc/dwarf dwarf.tesh)
-  ADD_TESH(tesh-mc-dwarf-expression            --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/mc/dwarf-expression --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/mc/dwarf-expression dwarf-expression.tesh)
   ADD_TESH(tesh-mc-mutex-handling              --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/mc/mutex-handling --setenv srcdir=${CMAKE_HOME_DIRECTORY} --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/mc/mutex-handling mutex-handling.tesh --cfg=model-check/reduction:none)
   ADD_TESH(tesh-mc-mutex-handling-dpor         --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/mc/mutex-handling --setenv srcdir=${CMAKE_HOME_DIRECTORY} --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/mc/mutex-handling mutex-handling.tesh --cfg=model-check/reduction:dpor)
   ADD_TESH(tesh-mc-without-mutex-handling      --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/mc/mutex-handling --setenv srcdir=${CMAKE_HOME_DIRECTORY} --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/mc/mutex-handling without-mutex-handling.tesh --cfg=model-check/reduction:none)
@@ -50,8 +40,53 @@ IF(SIMGRID_HAVE_MC)
   ADD_TESH(mc-random-bug                       --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/mc/random-bug --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/mc/random-bug random-bug.tesh)
 ENDIF()
 
-ADD_TESH(mc-random-bug-replay                  --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/mc/random-bug --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/mc/random-bug random-bug-replay.tesh)
-
 if(enable_coverage)
   ADD_TEST(cover-mc-mutex-handling ${CMAKE_CURRENT_BINARY_DIR}/mutex-handling/mutex-handling ${CMAKE_HOME_DIRECTORY}/examples/platforms/small_platform.xml)
 endif()
+
+
+foreach(x
+            simple_barrier_ok              simple_barrier_deadlock
+            simple_barrier_with_threads_ok simple_barrier_with_threads_deadlock
+
+#            simple_cond_ok 
+
+#            simple_cond_broadcast_ok                simple_cond_broadcast_deadlock
+#            simple_cond_broadcast_with_semaphore_ok 
+#                   simple_cond_broadcast_with_semaphore_deadlock1  simple_cond_broadcast_with_semaphore_deadlock2
+
+#                 simple_cond_deadlock
+             simple_mutex_ok simple_mutex_deadlock
+             simple_mutex_with_threads_ok simple_mutex_with_threads_deadlock
+
+             simple_semaphore_deadlock simple_semaphores_deadlock
+             simple_semaphores_ok
+             simple_semaphores_with_threads_ok simple_semaphores_with_threads_deadlock
+            
+             simple_threads_ok
+
+             barber_shop_ok             barber_shop_deadlock
+             philosophers_semaphores_ok philosophers_semaphores_deadlock
+             philosophers_mutex_ok      philosophers_mutex_deadlock
+             producer_consumer_ok       producer_consumer_deadlock    
+             
+             # philosophers_spurious_deadlock # infinite no-op loop             
+             # producer_consumer_spurious_nok # infinite no-op loop
+             )
+
+  set(teshsuite_src  ${teshsuite_src} ${CMAKE_CURRENT_SOURCE_DIR}/mcmini/${x}.c)
+  set(tesh_files     ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/mcmini/${x}.tesh)
+
+  if("${CMAKE_SYSTEM}" MATCHES "Linux" AND ${enable_testsuite_McMini})
+    add_executable       (mcmini-${x}  EXCLUDE_FROM_ALL mcmini/${x}.c)         
+    set_target_properties(mcmini-${x}  PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mcmini)
+    target_link_libraries(mcmini-${x}  PRIVATE Threads::Threads)
+    add_dependencies(tests-mc mcmini-${x})
+
+    ADD_TESH(mc-mini-${x} --setenv libdir=${CMAKE_BINARY_DIR}/lib --setenv bindir=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/mcmini/${x}.tesh)
+  endif()
+endforeach()
+
+set(teshsuite_src  ${teshsuite_src}                                                                        PARENT_SCOPE)
+set(tesh_files     ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/random-bug/random-bug-replay.tesh
+                                    ${CMAKE_CURRENT_SOURCE_DIR}/mutex-handling/without-mutex-handling.tesh PARENT_SCOPE)
diff --git a/teshsuite/mc/dwarf-expression/dwarf-expression.cpp b/teshsuite/mc/dwarf-expression/dwarf-expression.cpp
deleted file mode 100644 (file)
index cccdce3..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifdef NDEBUG
-#undef NDEBUG
-#endif
-
-#include "src/mc/mc_private.hpp"
-
-#include "src/mc/inspect/ObjectInformation.hpp"
-#include "src/mc/inspect/Type.hpp"
-#include "src/mc/inspect/Variable.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-
-#include <array>
-#include <cassert>
-#include <cstdlib>
-#include <limits>
-#include <xbt/random.hpp>
-
-static uintptr_t rnd_engine()
-{
-  return simgrid::xbt::random::uniform_int(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
-}
-
-static uintptr_t eval_binary_operation(simgrid::dwarf::ExpressionContext const& state, uint8_t op, uintptr_t a,
-                                       uintptr_t b)
-{
-  std::array<Dwarf_Op, 15> ops;
-  ops[0].atom = DW_OP_const8u;
-  ops[0].number = a;
-  ops[1].atom = DW_OP_const8u;
-  ops[1].number = b;
-  ops[2].atom = op;
-
-  simgrid::dwarf::ExpressionStack stack;
-  try {
-    simgrid::dwarf::execute(ops.data(), 3, state, stack);
-  } catch (const simgrid::dwarf::evaluation_error&) {
-    fprintf(stderr,"Expression evaluation error");
-  }
-
-  assert(stack.size() == 1);
-  return stack.top();
-}
-
-static void basic_test(simgrid::dwarf::ExpressionContext const& state)
-{
-  std::array<Dwarf_Op, 60> ops;
-
-  uintptr_t a = rnd_engine();
-  uintptr_t b = rnd_engine();
-
-  simgrid::dwarf::ExpressionStack stack;
-
-  bool caught_ex = false;
-  try {
-    ops[0].atom = DW_OP_drop;
-    simgrid::dwarf::execute(ops.data(), 1, state, stack);
-  } catch (const simgrid::dwarf::evaluation_error&) {
-    caught_ex = true;
-  }
-  if (not caught_ex)
-    fprintf(stderr, "Exception expected");
-
-  try {
-    ops[0].atom = DW_OP_lit21;
-    simgrid::dwarf::execute(ops.data(), 1, state, stack);
-    assert(stack.size() == 1);
-    assert(stack.top() == 21);
-
-    ops[0].atom   = DW_OP_const8u;
-    ops[0].number = a;
-    simgrid::dwarf::execute(ops.data(), 1, state, stack);
-    assert(stack.size() == 2);
-    assert(stack.top() == a);
-
-    ops[0].atom = DW_OP_drop;
-    ops[1].atom = DW_OP_drop;
-    simgrid::dwarf::execute(ops.data(), 2, state, stack);
-    assert(stack.empty());
-
-    stack.clear();
-    ops[0].atom   = DW_OP_lit21;
-    ops[1].atom   = DW_OP_plus_uconst;
-    ops[1].number = a;
-    simgrid::dwarf::execute(ops.data(), 2, state, stack);
-    assert(stack.size() == 1);
-    assert(stack.top() == a + 21);
-
-    stack.clear();
-    ops[0].atom   = DW_OP_const8u;
-    ops[0].number = a;
-    ops[1].atom   = DW_OP_dup;
-    ops[2].atom   = DW_OP_plus;
-    simgrid::dwarf::execute(ops.data(), 3, state, stack);
-    assert(stack.size() == 1);
-    assert(stack.top() == a + a);
-
-    stack.clear();
-    ops[0].atom   = DW_OP_const8u;
-    ops[0].number = a;
-    ops[1].atom   = DW_OP_const8u;
-    ops[1].number = b;
-    ops[2].atom   = DW_OP_over;
-    simgrid::dwarf::execute(ops.data(), 3, state, stack);
-    assert(stack.size() == 3);
-    assert(stack.top() == a);
-    assert(stack.top(1) == b);
-    assert(stack.top(2) == a);
-
-    stack.clear();
-    ops[0].atom   = DW_OP_const8u;
-    ops[0].number = a;
-    ops[1].atom   = DW_OP_const8u;
-    ops[1].number = b;
-    ops[2].atom   = DW_OP_swap;
-    simgrid::dwarf::execute(ops.data(), 3, state, stack);
-    assert(stack.size() == 2);
-    assert(stack.top() == a);
-    assert(stack.top(1) == b);
-  } catch (const simgrid::dwarf::evaluation_error&) {
-    fprintf(stderr,"Expression evaluation error");
-  }
-}
-
-static void test_deref(simgrid::dwarf::ExpressionContext const& state)
-{
-  try {
-    uintptr_t foo = 42;
-
-    std::array<Dwarf_Op, 60> ops;
-    ops[0].atom   = DW_OP_const8u;
-    ops[0].number = (uintptr_t)&foo;
-    ops[1].atom   = DW_OP_deref;
-
-    simgrid::dwarf::ExpressionStack stack;
-
-    simgrid::dwarf::execute(ops.data(), 2, state, stack);
-    assert(stack.size() == 1);
-    assert(stack.top() == foo);
-  } catch (const simgrid::dwarf::evaluation_error&) {
-    fprintf(stderr,"Expression evaluation error");
-  }
-}
-
-int main()
-{
-  auto* process = new simgrid::mc::RemoteProcessMemory(getpid(), nullptr);
-
-  simgrid::dwarf::ExpressionContext state;
-  state.address_space = (simgrid::mc::AddressSpace*) process;
-
-  basic_test(state);
-
-  for(int i=0; i!=100; ++i) {
-    uintptr_t a = rnd_engine();
-    uintptr_t b = rnd_engine();
-    assert(eval_binary_operation(state, DW_OP_plus, a, b) == (a + b));
-  }
-
-  for(int i=0; i!=100; ++i) {
-    uintptr_t a = rnd_engine();
-    uintptr_t b = rnd_engine();
-    assert(eval_binary_operation(state, DW_OP_or, a, b) == (a | b));
-  }
-
-  for(int i=0; i!=100; ++i) {
-    uintptr_t a = rnd_engine();
-    uintptr_t b = rnd_engine();
-    assert(eval_binary_operation(state, DW_OP_and, a, b) == (a & b));
-  }
-
-  for(int i=0; i!=100; ++i) {
-    uintptr_t a = rnd_engine();
-    uintptr_t b = rnd_engine();
-    assert(eval_binary_operation(state, DW_OP_xor, a, b) == (a ^ b));
-  }
-
-  test_deref(state);
-
-  return 0;
-}
diff --git a/teshsuite/mc/dwarf-expression/dwarf-expression.tesh b/teshsuite/mc/dwarf-expression/dwarf-expression.tesh
deleted file mode 100644 (file)
index 787f2bc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env tesh
-
-$ ${bindir:=.}/dwarf-expression
diff --git a/teshsuite/mc/dwarf/dwarf.cpp b/teshsuite/mc/dwarf/dwarf.cpp
deleted file mode 100644 (file)
index aa86545..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* Copyright (c) 2014-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#ifdef NDEBUG
-#undef NDEBUG
-#endif
-
-#include <simgrid/s4u/Engine.hpp>
-
-#include "src/mc/datatypes.h"
-#include "src/mc/mc.h"
-#include "src/mc/mc_private.hpp"
-
-#include "src/mc/inspect/ObjectInformation.hpp"
-#include "src/mc/inspect/Type.hpp"
-#include "src/mc/inspect/Variable.hpp"
-#include "src/mc/sosp/RemoteProcessMemory.hpp"
-
-#include <cassert>
-#include <cstring>
-
-#include <elfutils/version.h>
-#if _ELFUTILS_VERSION < 171
-// Elder elfutils/libdw broken with multi-dimensional arrays. See https://sourceware.org/bugzilla/show_bug.cgi?id=22546
-int test_some_array[4 * 5 * 6];
-#else
-int test_some_array[4][5][6];
-#endif
-
-struct some_struct {
-  int first;
-  int second[4][5];
-};
-some_struct test_some_struct;
-
-static simgrid::mc::Frame* find_function_by_name(
-    simgrid::mc::ObjectInformation* info, const char* name)
-{
-  for (auto& [_, entry] : info->subprograms)
-    if (entry.name == name)
-      return &entry;
-  return nullptr;
-}
-
-static simgrid::mc::Variable* find_local_variable(
-    simgrid::mc::Frame* frame, const char* argument_name)
-{
-  for (simgrid::mc::Variable& variable : frame->variables)
-    if(argument_name == variable.name)
-      return &variable;
-
-  for (simgrid::mc::Frame& scope : frame->scopes) {
-    simgrid::mc::Variable* variable = find_local_variable(
-      &scope, argument_name);
-    if(variable)
-      return variable;
-  }
-
-  return nullptr;
-}
-
-static void test_local_variable(simgrid::mc::ObjectInformation* info, const char* function, const char* variable,
-                                const void* address, unw_cursor_t* cursor)
-{
-  simgrid::mc::Frame* subprogram = find_function_by_name(info, function);
-  assert(subprogram);
-  // TODO, Lookup frame by IP and test against name instead
-
-  const simgrid::mc::Variable* var = find_local_variable(subprogram, variable);
-  assert(var);
-
-  void* frame_base = subprogram->frame_base(*cursor);
-  simgrid::dwarf::Location location = simgrid::dwarf::resolve(var->location_list, info, cursor, frame_base, nullptr);
-
-  xbt_assert(location.in_memory(), "Expected the variable %s of function %s to be in memory", variable, function);
-  xbt_assert(location.address() == address, "Bad resolution of local variable %s of %s", variable, function);
-}
-
-static const simgrid::mc::Variable* test_global_variable(const simgrid::mc::RemoteProcessMemory& process,
-                                                         simgrid::mc::ObjectInformation* info, const char* name,
-                                                         void* address, long byte_size)
-{
-  const simgrid::mc::Variable* variable = info->find_variable(name);
-  xbt_assert(variable, "Global variable %s was not found", name);
-  xbt_assert(variable->name == name, "Name mismatch for %s", name);
-  xbt_assert(variable->global, "Variable %s is not global", name);
-  xbt_assert(variable->address == address, "Address mismatch for %s : %p expected but %p found", name, address,
-             variable->address);
-
-  auto i = process.binary_info->types.find(variable->type_id);
-  xbt_assert(i != process.binary_info->types.end(), "Missing type for %s", name);
-  const simgrid::mc::Type* type = &i->second;
-  xbt_assert(type->byte_size == byte_size, "Byte size mismatch for %s", name);
-  return variable;
-}
-
-static simgrid::mc::Member* find_member(simgrid::mc::Type& type, const char* name)
-{
-  for (simgrid::mc::Member& member : type.members)
-    if(member.name == name)
-      return &member;
-  return nullptr;
-}
-
-int some_local_variable = 0;
-
-struct s_foo {
-  int i;
-};
-
-static void test_type_by_name(const simgrid::mc::RemoteProcessMemory& process, s_foo /*my_foo*/)
-{
-  assert(process.binary_info->full_types_by_name.find("struct s_foo") != process.binary_info->full_types_by_name.end());
-}
-
-int main(int argc, char** argv)
-{
-  simgrid::s4u::Engine::get_instance(&argc, argv);
-
-  const simgrid::mc::Variable* var;
-  simgrid::mc::Type* type;
-
-  simgrid::mc::RemoteProcessMemory process(getpid(), nullptr);
-
-  test_global_variable(process, process.binary_info.get(), "some_local_variable", &some_local_variable, sizeof(int));
-
-  var = test_global_variable(process, process.binary_info.get(), "test_some_array", &test_some_array,
-                             sizeof(test_some_array));
-  auto i = process.binary_info->types.find(var->type_id);
-  xbt_assert(i != process.binary_info->types.end(), "Missing type");
-  type = &i->second;
-  xbt_assert(type->element_count == 6 * 5 * 4, "element_count mismatch in test_some_array : %i / %i",
-             type->element_count, 6 * 5 * 4);
-
-  var = test_global_variable(process, process.binary_info.get(), "test_some_struct", &test_some_struct,
-                             sizeof(test_some_struct));
-  i = process.binary_info->types.find(var->type_id);
-  xbt_assert(i != process.binary_info->types.end(), "Missing type");
-  type = &i->second;
-
-  assert(type);
-  assert(find_member(*type, "first")->offset() == 0);
-  assert(find_member(*type, "second")->offset() ==
-         ((const char*)&test_some_struct.second) - (const char*)&test_some_struct);
-
-  unw_context_t context;
-  unw_cursor_t cursor;
-  unw_getcontext(&context);
-  unw_init_local(&cursor, &context);
-
-  test_local_variable(process.binary_info.get(), "main", "argc", &argc, &cursor);
-
-  int lexical_block_variable = 50;
-  test_local_variable(process.binary_info.get(), "main", "lexical_block_variable", &lexical_block_variable, &cursor);
-
-  s_foo my_foo = {0};
-  test_type_by_name(process, my_foo);
-
-  return 0;
-}
diff --git a/teshsuite/mc/dwarf/dwarf.tesh b/teshsuite/mc/dwarf/dwarf.tesh
deleted file mode 100644 (file)
index f6c817b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env tesh
-
-$ ${bindir:=.}/dwarf
diff --git a/teshsuite/mc/mcmini/barber_shop_deadlock.c b/teshsuite/mc/mcmini/barber_shop_deadlock.c
new file mode 100644 (file)
index 0000000..c10c970
--- /dev/null
@@ -0,0 +1,107 @@
+#define _REENTRANT
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+// The maximum number of customer threads.
+#define MAX_CUSTOMERS 10
+
+// Define the semaphores.
+sem_t waitingRoom;
+sem_t barberChair;
+sem_t barberPillow;
+sem_t seatBelt;
+
+// Flag to stop the barber thread when all customers have been serviced.
+int allDone = 0;
+int DEBUG = 0;
+
+static void *customer(void *number) {
+    int num = *(int *)number;
+
+    if(DEBUG) printf("Customer %d leaving for barber shop.\n", num);
+    if(DEBUG) printf("Customer %d arrived at barber shop.\n", num);
+
+    sem_wait(&waitingRoom);
+
+    if(DEBUG) printf("Customer %d entering waiting room.\n", num);
+
+    sem_wait(&barberChair);
+
+    if(DEBUG) printf("Customer %d waking the barber.\n", num);
+    sem_post(&barberPillow);
+
+    sem_wait(&seatBelt);
+
+    sem_post(&barberChair);
+    if(DEBUG) printf("Customer %d leaving barber shop.\n", num);
+    return NULL;
+}
+
+static void *barber(void *junk) {
+    while (!allDone) {
+        if(DEBUG) printf("The barber is sleeping\n");
+        sem_wait(&barberPillow);
+
+        if (!allDone) {
+            if(DEBUG) printf("The barber is cutting hair\n");
+            if(DEBUG) printf("The barber has finished cutting hair.\n");
+            sem_post(&seatBelt);
+        }
+        else {
+            if(DEBUG) printf("The barber is going home for the day.\n");
+        }
+    }
+    return NULL;
+}
+
+int main(int argc, char *argv[]) {
+    if(argc != 5){
+        printf("Usage: %s numCustomers numChairs RandSeed DEBUG\n", argv[0]);
+        return 1;
+    }
+
+    pthread_t btid;
+    pthread_t tid[MAX_CUSTOMERS];
+    int i, numCustomers, numChairs;
+    long RandSeed;
+    int Number[MAX_CUSTOMERS];
+
+    numCustomers = atoi(argv[1]);
+    numChairs = atoi(argv[2]);
+    RandSeed = atol(argv[3]);
+    DEBUG = atoi(argv[4]);
+
+    if (numCustomers > MAX_CUSTOMERS) {
+        printf("The maximum number of Customers is %d.\n", MAX_CUSTOMERS);
+        exit(-1);
+    }
+
+    srand48(RandSeed);
+
+    for (i=0; i<MAX_CUSTOMERS; i++) {
+        Number[i] = i;
+    }
+
+    sem_init(&waitingRoom, 0, numChairs);
+    sem_init(&barberChair, 0, 1);
+    sem_init(&barberPillow, 0, 0);
+    sem_init(&seatBelt, 0, 0);
+
+    pthread_create(&btid, NULL, barber, NULL);
+
+    for (i=0; i<numCustomers; i++) {
+        pthread_create(&tid[i], NULL, customer, (void *)&Number[i]);
+    }
+
+    for (i=0; i<numCustomers; i++) {
+        pthread_join(tid[i],NULL);
+    }
+
+    allDone = 1;
+    sem_post(&barberPillow);
+    pthread_join(btid,NULL);
+}
diff --git a/teshsuite/mc/mcmini/barber_shop_deadlock.tesh b/teshsuite/mc/mcmini/barber_shop_deadlock.tesh
new file mode 100644 (file)
index 0000000..3756e4c
--- /dev/null
@@ -0,0 +1,58 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-barber_shop_deadlock 5 3 0 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 4 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:6)
+> [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall SEM_WAIT(sem_id:2 not granted)
+> [0.000000] [ker_engine/INFO] Actor 6 (thread 5@Lilibeth) simcall SEM_WAIT(sem_id:0 not granted)
+> [0.000000] [ker_engine/INFO] Actor 7 (thread 6@Lilibeth) simcall SEM_WAIT(sem_id:0 not granted)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 2, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 2)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_WAIT(semaphore: 0, capacity: 2, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_ASYNC_LOCK(semaphore: 1, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_WAIT(semaphore: 1, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_UNLOCK(semaphore: 2, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 2, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_UNLOCK(semaphore: 3, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 2, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_ASYNC_LOCK(semaphore: 3, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_WAIT(semaphore: 3, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_UNLOCK(semaphore: 1, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall ActorJoin(target 3, no timeout)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_WAIT(semaphore: 0, capacity: 1, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_ASYNC_LOCK(semaphore: 1, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_WAIT(semaphore: 1, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_UNLOCK(semaphore: 2, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 2, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_UNLOCK(semaphore: 3, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 2, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_ASYNC_LOCK(semaphore: 3, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_WAIT(semaphore: 3, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_UNLOCK(semaphore: 1, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall ActorJoin(target 4, no timeout)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall SEM_WAIT(semaphore: 0, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall SEM_ASYNC_LOCK(semaphore: 1, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall SEM_WAIT(semaphore: 1, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall SEM_UNLOCK(semaphore: 2, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 2, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_UNLOCK(semaphore: 3, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 2, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall SEM_ASYNC_LOCK(semaphore: 3, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall SEM_WAIT(semaphore: 3, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall SEM_UNLOCK(semaphore: 1, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall ActorJoin(target 5, no timeout)
+> [0.000000] [mc_global/INFO]   Actor 6 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 7 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;3;3;3;3;3;2;2;2;3;3;3;1;4;4;4;4;4;2;2;2;4;4;4;1;5;5;5;5;5;2;2;2;5;5;5;1;6;7'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 40 unique states visited; 0 backtracks (0 transition replays, 40 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/barber_shop_ok.c b/teshsuite/mc/mcmini/barber_shop_ok.c
new file mode 100644 (file)
index 0000000..827b8db
--- /dev/null
@@ -0,0 +1,185 @@
+#ifdef _REENTRANT
+#undef _REENTRANT
+#endif
+#define _REENTRANT
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// The maximum number of customer threads.
+#define MAX_CUSTOMERS 25
+
+// Define the semaphores.
+
+// waitingRoom Limits the # of customers allowed
+// to enter the waiting room at one time.
+sem_t waitingRoom;
+
+// barberChair ensures mutually exclusive access to
+// the barber chair.
+sem_t barberChair;
+
+// barberPillow is used to allow the barber to sleep
+// until a customer arrives.
+sem_t barberPillow;
+
+// seatBelt is used to make the customer to wait until
+// the barber is done cutting his/her hair.
+sem_t seatBelt;
+
+// Flag to stop the barber thread when all customers
+// have been serviced.
+int allDone = 0;
+int DEBUG   = 0;
+
+static void randwait(int secs)
+{
+  int len;
+
+  // Generate a random number...
+  len = (int)((drand48() * secs) + 1);
+  sleep(len);
+}
+
+static void* customer(void* number)
+{
+  int num = *(int*)number;
+
+  // Leave for the shop and take some random amount of
+  // time to arrive.
+  if (DEBUG)
+    printf("Customer %d leaving for barber shop.\n", num);
+  randwait(5);
+  if (DEBUG)
+    printf("Customer %d arrived at barber shop.\n", num);
+
+  // Wait for space to open up in the waiting room...
+  sem_wait(&waitingRoom);
+  if (DEBUG)
+    printf("Customer %d entering waiting room.\n", num);
+
+  // Wait for the barber chair to become free.
+  sem_wait(&barberChair);
+
+  // The chair is free so give up your spot in the
+  // waiting room.
+  sem_post(&waitingRoom);
+
+  // Wake up the barber...
+  if (DEBUG)
+    printf("Customer %d waking the barber.\n", num);
+  sem_post(&barberPillow);
+
+  // Wait for the barber to finish cutting your hair.
+  sem_wait(&seatBelt);
+
+  // Give up the chair.
+  sem_post(&barberChair);
+  if (DEBUG)
+    printf("Customer %d leaving barber shop.\n", num);
+  return NULL;
+}
+
+static void* barber(void* junk)
+{
+  // While there are still customers to be serviced...
+  // Our barber is omnicient and can tell if there are
+  // customers still on the way to his shop.
+  while (!allDone) {
+
+    // Sleep until someone arrives and wakes you..
+    if (DEBUG)
+      printf("The barber is sleeping\n");
+    sem_wait(&barberPillow);
+
+    // Skip this stuff at the end...
+    if (!allDone) {
+
+      // Take a random amount of time to cut the
+      // customer's hair.
+      if (DEBUG)
+        printf("The barber is cutting hair\n");
+      randwait(3);
+      if (DEBUG)
+        printf("The barber has finished cutting hair.\n");
+
+      // Release the customer when done cutting...
+      sem_post(&seatBelt);
+    } else {
+      if (DEBUG)
+        printf("The barber is going home for the day.\n");
+    }
+  }
+  return NULL;
+}
+
+int main(int argc, char* argv[])
+{
+  pthread_t btid;
+  pthread_t tid[MAX_CUSTOMERS];
+  long RandSeed;
+  int i, numCustomers, numChairs;
+  int Number[MAX_CUSTOMERS];
+
+  // Check to make sure there are the right number of
+  // command line arguments.
+  if (argc != 5) {
+    printf("Use: SleepBarber <Num Customers> <Num Chairs> <rand seed> <DEBUG>\n");
+    exit(-1);
+  }
+
+  // Get the command line arguments and convert them
+  // into integers.
+  numCustomers = atoi(argv[1]);
+  numChairs    = atoi(argv[2]);
+  RandSeed     = atol(argv[3]);
+  DEBUG        = atoi(argv[4]);
+
+  // Make sure the number of threads is less than the number of
+  // customers we can support.
+  if (numCustomers > MAX_CUSTOMERS) {
+    printf("The maximum number of Customers is %d.\n", MAX_CUSTOMERS);
+    exit(-1);
+  }
+
+  if (DEBUG) {
+    printf("\nSleepBarber.c\n\n");
+    printf("A solution to the sleeping barber problem using semaphores.\n");
+  }
+
+  // Initialize the random number generator with a new seed.
+  srand48(RandSeed);
+
+  // Initialize the numbers array.
+  for (i = 0; i < MAX_CUSTOMERS; i++) {
+    Number[i] = i;
+  }
+
+  // Initialize the semaphores with initial values...
+  sem_init(&waitingRoom, 0, numChairs);
+  sem_init(&barberChair, 0, 1);
+  sem_init(&barberPillow, 0, 0);
+  sem_init(&seatBelt, 0, 0);
+
+  // Create the barber.
+  pthread_create(&btid, NULL, barber, NULL);
+
+  // Create the customers.
+  for (i = 0; i < numCustomers; i++) {
+    pthread_create(&tid[i], NULL, customer, (void*)&Number[i]);
+  }
+
+  // Join each of the threads to wait for them to finish.
+  for (i = 0; i < numCustomers; i++) {
+    pthread_join(tid[i], NULL);
+  }
+
+  // When all of the customers are finished, kill the
+  // barber thread.
+  allDone = 1;
+  sem_post(&barberPillow); // Wake the barber so he will exit.
+  pthread_join(btid, NULL);
+}
diff --git a/teshsuite/mc/mcmini/barber_shop_ok.tesh b/teshsuite/mc/mcmini/barber_shop_ok.tesh
new file mode 100644 (file)
index 0000000..954547e
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-barber_shop_ok 4 2 0 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 1897 unique states visited; 50 backtracks (893 transition replays, 2840 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/philosophers_mutex_deadlock.c b/teshsuite/mc/mcmini/philosophers_mutex_deadlock.c
new file mode 100644 (file)
index 0000000..4497df7
--- /dev/null
@@ -0,0 +1,59 @@
+// Naive dining philosophers solution, which leads to deadlock.
+
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+int DEBUG = 0;
+
+struct forks {
+    int philosopher;
+    pthread_mutex_t *left_fork;
+    pthread_mutex_t *right_fork;
+} *forks;
+
+static void * philosopher_doit(void *forks_arg) {
+    struct forks *forks = forks_arg;
+    pthread_mutex_lock(forks->left_fork);
+    pthread_mutex_lock(forks->right_fork);
+
+    if(DEBUG) printf("Philosopher %d just ate.\n", forks->philosopher);
+    
+    pthread_mutex_unlock(forks->left_fork);
+    pthread_mutex_unlock(forks->right_fork);
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    if(argc != 3){
+        printf("Usage: %s NUM_PHILOSOPHERS DEBUG\n", argv[0]);
+        return 1;
+    }
+
+    int NUM_THREADS = atoi(argv[1]);
+    DEBUG = atoi(argv[2]);
+
+    pthread_t thread[NUM_THREADS];
+    pthread_mutex_t mutex_resource[NUM_THREADS];
+
+    forks = malloc(NUM_THREADS * sizeof(struct forks));
+
+    int i;
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_mutex_init(&mutex_resource[i], NULL);
+        forks[i] = (struct forks){i,
+                                  &mutex_resource[i], &mutex_resource[(i+1) % NUM_THREADS]};
+    }
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_create(&thread[i], NULL, &philosopher_doit, &forks[i]);
+    }
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_join(thread[i], NULL);
+    }
+
+    free(forks);
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/philosophers_mutex_deadlock.tesh b/teshsuite/mc/mcmini/philosophers_mutex_deadlock.tesh
new file mode 100644 (file)
index 0000000..9092bf9
--- /dev/null
@@ -0,0 +1,36 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-philosophers_mutex_deadlock 5 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 6 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:2)
+> [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall MUTEX_WAIT(mutex_id:1 owner:3)
+> [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall MUTEX_WAIT(mutex_id:2 owner:4)
+> [0.000000] [ker_engine/INFO] Actor 4 (thread 3@Lilibeth) simcall MUTEX_WAIT(mutex_id:3 owner:5)
+> [0.000000] [ker_engine/INFO] Actor 5 (thread 4@Lilibeth) simcall MUTEX_WAIT(mutex_id:4 owner:6)
+> [0.000000] [ker_engine/INFO] Actor 6 (thread 5@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_WAIT(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_WAIT(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall MUTEX_ASYNC_LOCK(mutex: 2, owner: 4)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 2, owner: 4)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall MUTEX_WAIT(mutex: 2, owner: 4)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall MUTEX_ASYNC_LOCK(mutex: 3, owner: 5)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall MUTEX_ASYNC_LOCK(mutex: 3, owner: 5)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall MUTEX_WAIT(mutex: 3, owner: 5)
+> [0.000000] [mc_global/INFO]   Actor 6 in simcall MUTEX_ASYNC_LOCK(mutex: 4, owner: 6)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall MUTEX_ASYNC_LOCK(mutex: 4, owner: 6)
+> [0.000000] [mc_global/INFO]   Actor 6 in simcall MUTEX_WAIT(mutex: 4, owner: 6)
+> [0.000000] [mc_global/INFO]   Actor 6 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;2;3;2;3;4;3;4;5;4;5;6;5;6;6'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 317 unique states visited; 15 backtracks (224 transition replays, 556 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/philosophers_mutex_ok.c b/teshsuite/mc/mcmini/philosophers_mutex_ok.c
new file mode 100644 (file)
index 0000000..8c30821
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+int DEBUG = 0;
+
+struct forks {
+    int philosopher;
+    pthread_mutex_t *left_fork;
+    pthread_mutex_t *right_fork;
+    pthread_mutex_t *dining_fork;
+};
+
+static void * philosopher_doit(void *forks_arg) {
+    struct forks *forks = forks_arg;
+    pthread_mutex_lock(forks->dining_fork);
+    pthread_mutex_lock(forks->left_fork);
+    pthread_mutex_lock(forks->right_fork);
+    pthread_mutex_unlock(forks->dining_fork);
+
+    if(DEBUG)
+        printf("Philosopher %d is eating.\n", forks->philosopher);
+        
+    pthread_mutex_unlock(forks->left_fork);
+    pthread_mutex_unlock(forks->right_fork);
+    return NULL;
+}
+
+int main(int argc, char* argv[])
+{
+    if(argc != 3){
+        printf("Usage: %s NUM_THREADS DEBUG\n", argv[0]);
+        return 1;
+    }
+
+    int NUM_THREADS = atoi(argv[1]);
+    DEBUG = atoi(argv[2]);
+
+    pthread_t thread[NUM_THREADS];
+    pthread_mutex_t mutex_resource[NUM_THREADS];
+    struct forks forks[NUM_THREADS];
+
+    pthread_mutex_t dining_fork;
+    pthread_mutex_init(&dining_fork, NULL);
+
+    int i;
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_mutex_init(&mutex_resource[i], NULL);
+        forks[i] = (struct forks){i,
+                                  &mutex_resource[i],
+                                  &mutex_resource[(i+1) % NUM_THREADS],
+                                  &dining_fork};
+    }
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_create(&thread[i], NULL, &philosopher_doit, &forks[i]);
+    }
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_join(thread[i], NULL);
+    }
+
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/philosophers_mutex_ok.tesh b/teshsuite/mc/mcmini/philosophers_mutex_ok.tesh
new file mode 100644 (file)
index 0000000..6a93b85
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-philosophers_mutex_ok 5 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 4190 unique states visited; 119 backtracks (1811 transition replays, 6120 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/philosophers_semaphores_deadlock.c b/teshsuite/mc/mcmini/philosophers_semaphores_deadlock.c
new file mode 100644 (file)
index 0000000..92e58b1
--- /dev/null
@@ -0,0 +1,67 @@
+// Dining philosophers solution with semaphores
+
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+
+struct forks {
+    int philosopher;
+    pthread_mutex_t *left_fork;
+    pthread_mutex_t *right_fork;
+    sem_t* sem_dining;
+    int DEBUG;
+} *forks;
+
+static void * philosopher_doit(void *forks_arg) {
+    struct forks *forks = forks_arg;
+    sem_wait(forks->sem_dining);
+    pthread_mutex_lock(forks->left_fork);
+    pthread_mutex_lock(forks->right_fork);
+
+    if(forks->DEBUG) printf("Philosopher %d just ate.\n", forks->philosopher);
+    
+    pthread_mutex_unlock(forks->left_fork);
+    pthread_mutex_unlock(forks->right_fork);
+    sem_post(forks->sem_dining);
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    if(argc != 3){
+        printf("Usage: %s NUM_PHILOSOPHERS DEBUG\n", argv[0]);
+        return 1;
+    }
+
+    int NUM_THREADS = atoi(argv[1]);
+    int DEBUG = atoi(argv[2]);
+
+    pthread_t thread[NUM_THREADS];
+    pthread_mutex_t mutex_resource[NUM_THREADS];
+    sem_t sem_dining;
+    sem_init(&sem_dining, 0, NUM_THREADS);
+
+    forks = malloc(NUM_THREADS * sizeof(struct forks));
+
+    int i;
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_mutex_init(&mutex_resource[i], NULL);
+        forks[i] = (struct forks){i,
+                                  &mutex_resource[i],
+                                  &mutex_resource[(i+1) % NUM_THREADS],
+                                  &sem_dining,
+                                  DEBUG};
+    }
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_create(&thread[i], NULL, &philosopher_doit, &forks[i]);
+    }
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_join(thread[i], NULL);
+    }
+
+    free(forks);
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/philosophers_semaphores_deadlock.tesh b/teshsuite/mc/mcmini/philosophers_semaphores_deadlock.tesh
new file mode 100644 (file)
index 0000000..80fd205
--- /dev/null
@@ -0,0 +1,33 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-philosophers_semaphores_deadlock 3 0
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 4 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:2)
+> [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall MUTEX_WAIT(mutex_id:1 owner:3)
+> [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall MUTEX_WAIT(mutex_id:2 owner:4)
+> [0.000000] [ker_engine/INFO] Actor 4 (thread 3@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 0, capacity: 2, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_WAIT(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_WAIT(semaphore: 0, capacity: 1, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_WAIT(mutex: 1, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall SEM_WAIT(semaphore: 0, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall MUTEX_ASYNC_LOCK(mutex: 2, owner: 4)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 2, owner: 4)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall MUTEX_WAIT(mutex: 2, owner: 4)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;2;2;2;3;3;3;2;3;4;4;4;3;4;4'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 321 unique states visited; 32 backtracks (424 transition replays, 777 states visited overall)
diff --git a/teshsuite/mc/mcmini/philosophers_semaphores_ok.c b/teshsuite/mc/mcmini/philosophers_semaphores_ok.c
new file mode 100644 (file)
index 0000000..b11e49f
--- /dev/null
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+
+int DEBUG = 0;
+
+struct forks {
+    int philosopher;
+    pthread_mutex_t *left_fork;
+    pthread_mutex_t *right_fork;
+    sem_t* sem_dining;
+};
+
+static void * philosopher_doit(void *forks_arg) {
+    struct forks *forks = forks_arg;
+    sem_wait(forks->sem_dining);
+    pthread_mutex_lock(forks->left_fork);
+    pthread_mutex_lock(forks->right_fork);
+
+    if(DEBUG)
+        printf("Philosopher %d is eating.\n", forks->philosopher);
+        
+    pthread_mutex_unlock(forks->left_fork);
+    pthread_mutex_unlock(forks->right_fork);
+    sem_post(forks->sem_dining);
+    return NULL;
+}
+
+int main(int argc, char* argv[])
+{
+    if(argc != 3){
+        printf("Usage: %s NUM_THREADS DEBUG\n", argv[0]);
+        return 1;
+    }
+
+    int NUM_THREADS = atoi(argv[1]);
+    DEBUG = atoi(argv[2]);
+
+    pthread_t thread[NUM_THREADS];
+    pthread_mutex_t mutex_resource[NUM_THREADS];
+    struct forks forks[NUM_THREADS];
+
+    sem_t sem_dining;
+    sem_init(&sem_dining, 0, NUM_THREADS - 1);
+
+    int i;
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_mutex_init(&mutex_resource[i], NULL);
+        forks[i] = (struct forks){i,
+                                  &mutex_resource[i],
+                                  &mutex_resource[(i+1) % NUM_THREADS],
+                                  &sem_dining};
+    }
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_create(&thread[i], NULL, &philosopher_doit, &forks[i]);
+    }
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        pthread_join(thread[i], NULL);
+    }
+
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/philosophers_semaphores_ok.tesh b/teshsuite/mc/mcmini/philosophers_semaphores_ok.tesh
new file mode 100644 (file)
index 0000000..16b02c8
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-philosophers_semaphores_ok 3 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 209 unique states visited; 10 backtracks (50 transition replays, 269 states visited overall)
diff --git a/teshsuite/mc/mcmini/producer_consumer_deadlock.c b/teshsuite/mc/mcmini/producer_consumer_deadlock.c
new file mode 100644 (file)
index 0000000..2cf1ee6
--- /dev/null
@@ -0,0 +1,83 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+int MaxItems; // Maximum items a producer can produce or a consumer can consume
+int BufferSize; // Size of the buffer
+
+sem_t empty;
+sem_t full;
+int in = 0;
+int out = 0;
+int *buffer;
+pthread_mutex_t mutex;
+
+int DEBUG = 0; // Debug flag
+
+static void *producer(void *pno)
+{
+    int item;
+    for(int i = 0; i < MaxItems; i++) {
+        item = rand(); // Produce a random item
+        pthread_mutex_lock(&mutex);
+        sem_wait(&empty);
+        buffer[in] = item;
+        if(DEBUG) printf("Producer %d: Insert Item %d at %d\n", *((int *)pno),buffer[in],in);
+        in = (in+1)%BufferSize;
+        pthread_mutex_unlock(&mutex);
+        sem_post(&full);
+    }
+    return NULL;
+}
+
+static void *consumer(void *cno)
+{
+    for(int i = 0; i < MaxItems; i++) {
+        pthread_mutex_lock(&mutex);
+        sem_wait(&full);
+        int item = buffer[out];
+        if(DEBUG) printf("Consumer %d: Remove Item %d from %d\n",*((int *)cno),item, out);
+        out = (out+1)%BufferSize;
+        pthread_mutex_unlock(&mutex);
+        sem_post(&empty);
+    }
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    if(argc != 4){
+        printf("Usage: %s MAX_ITEMS BUFFER_SIZE DEBUG\n", argv[0]);
+        return 1;
+    }
+
+    MaxItems = atoi(argv[1]);
+    BufferSize = atoi(argv[2]);
+    DEBUG = atoi(argv[3]);
+
+    buffer = (int*) malloc(BufferSize * sizeof(int));
+
+    pthread_t pro[5],con[5];
+    pthread_mutex_init(&mutex, NULL);
+    sem_init(&empty,0,BufferSize);
+    sem_init(&full,0,0);
+
+    int a[5] = {1,2,3,4,5}; //Just used for numbering the producer and consumer
+
+    for(int i = 0; i < 5; i++) {
+        pthread_create(&pro[i], NULL, producer, (void *)&a[i]);
+    }
+    for(int i = 0; i < 5; i++) {
+        pthread_create(&con[i], NULL, consumer, (void *)&a[i]);
+    }
+
+    for(int i = 0; i < 5; i++) {
+        pthread_join(pro[i], NULL);
+    }
+    for(int i = 0; i < 5; i++) {
+        pthread_join(con[i], NULL);
+    }
+
+    free(buffer);
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/producer_consumer_deadlock.tesh b/teshsuite/mc/mcmini/producer_consumer_deadlock.tesh
new file mode 100644 (file)
index 0000000..759c43f
--- /dev/null
@@ -0,0 +1,56 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-producer_consumer_deadlock 5 3 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 11 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:2)
+> [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall SEM_WAIT(sem_id:0 not granted)
+> [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [ker_engine/INFO] Actor 4 (thread 3@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [ker_engine/INFO] Actor 5 (thread 4@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [ker_engine/INFO] Actor 6 (thread 5@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [ker_engine/INFO] Actor 7 (thread 6@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [ker_engine/INFO] Actor 8 (thread 7@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [ker_engine/INFO] Actor 9 (thread 8@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [ker_engine/INFO] Actor 10 (thread 9@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [ker_engine/INFO] Actor 11 (thread 10@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:2)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_WAIT(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 0, capacity: 2, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_UNLOCK(mutex: 0, owner: -1)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_UNLOCK(semaphore: 1, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_WAIT(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 0, capacity: 1, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_UNLOCK(mutex: 0, owner: -1)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_UNLOCK(semaphore: 1, capacity: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_WAIT(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 0, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_UNLOCK(mutex: 0, owner: -1)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_UNLOCK(semaphore: 1, capacity: 3)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_WAIT(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 5 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 6 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 7 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 8 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 9 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 10 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 11 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 2)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;3;4;5;6;7;8;9;10;11'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 31 unique states visited; 0 backtracks (0 transition replays, 31 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/producer_consumer_ok.c b/teshsuite/mc/mcmini/producer_consumer_ok.c
new file mode 100644 (file)
index 0000000..9fc1583
--- /dev/null
@@ -0,0 +1,93 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#define MaxBufferSize 5
+
+sem_t empty;
+sem_t full;
+int in = 0;
+int out = 0;
+int buffer[MaxBufferSize];
+pthread_mutex_t mutex;
+int BufferSize;
+int ItemCount;
+int DEBUG;
+
+static void *producer(void *pno)
+{
+    int item;
+    for(int i = 0; i < ItemCount; i++) {
+        item = rand(); // Produce an random item
+        sem_wait(&empty);
+        pthread_mutex_lock(&mutex);
+        buffer[in] = item;
+        if (DEBUG) {
+          printf("Producer %d: Insert Item %d at %d\n",
+                 *((int *)pno),buffer[in],in);
+        }
+        in = (in+1)%BufferSize;
+        pthread_mutex_unlock(&mutex);
+        sem_post(&full);
+    }
+    return NULL;
+}
+
+static void *consumer(void *cno)
+{
+    for(int i = 0; i < ItemCount; i++) {
+        sem_wait(&full);
+        pthread_mutex_lock(&mutex);
+        int item = buffer[out];
+        if (DEBUG) {
+          printf("Consumer %d: Remove Item %d from %d\n",
+                 *((int *)cno),item, out);
+        }
+        out = (out+1)%BufferSize;
+        pthread_mutex_unlock(&mutex);
+        sem_post(&empty);
+    }
+    return NULL;
+}
+
+int main(int argc, char* argv[]) 
+{
+    if (argc < 6) {
+      printf("Usage: %s <NUM_PRODUCERS> <NUM_CONSUMERS> <ITEM_COUNT> <BUFFER_SIZE> <DEBUG>\n", argv[0]);
+      return 1;
+    }
+  
+    int NUM_PRODUCERS = atoi(argv[1]);
+    int NUM_CONSUMERS = atoi(argv[2]);
+    ItemCount = atoi(argv[3]);
+    BufferSize = atoi(argv[4]);
+    DEBUG = atoi(argv[5]);
+
+    pthread_t pro[NUM_PRODUCERS],con[NUM_CONSUMERS];
+
+    pthread_mutex_init(&mutex, NULL);
+    sem_init(&empty,0,BufferSize);
+    sem_init(&full,0,0);
+
+    int a[NUM_PRODUCERS > NUM_CONSUMERS ? NUM_PRODUCERS : NUM_CONSUMERS];
+
+    for(int i = 0; i < NUM_PRODUCERS; i++) {
+        a[i] = i+1;
+        pthread_create(&pro[i], NULL, producer, (void *)&a[i]);
+    }
+    for(int i = 0; i < NUM_CONSUMERS; i++) {
+        a[i] = i+1;
+        pthread_create(&con[i], NULL, consumer, (void *)&a[i]);
+    }
+
+    for(int i = 0; i < NUM_PRODUCERS; i++) {
+        pthread_join(pro[i], NULL);
+    }
+    for(int i = 0; i < NUM_CONSUMERS; i++) {
+        pthread_join(con[i], NULL);
+    }
+
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/producer_consumer_ok.tesh b/teshsuite/mc/mcmini/producer_consumer_ok.tesh
new file mode 100644 (file)
index 0000000..4cac945
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-producer_consumer_ok 2 2 2 1 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 1388 unique states visited; 35 backtracks (485 transition replays, 1908 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/simple_barrier_deadlock.c b/teshsuite/mc/mcmini/simple_barrier_deadlock.c
new file mode 100644 (file)
index 0000000..16805ad
--- /dev/null
@@ -0,0 +1,10 @@
+#include <pthread.h>
+
+pthread_barrier_t barrier;
+
+int main(int argc, char* argv[]) {
+    pthread_barrier_init(&barrier, NULL, 2);
+    pthread_barrier_wait(&barrier);
+    return 0;
+}
+
diff --git a/teshsuite/mc/mcmini/simple_barrier_deadlock.tesh b/teshsuite/mc/mcmini/simple_barrier_deadlock.tesh
new file mode 100644 (file)
index 0000000..0b5980f
--- /dev/null
@@ -0,0 +1,17 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_barrier_deadlock
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 1 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall BARRIER_WAIT(barrier_id:0)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall BARRIER_ASYNC_LOCK(barrier: 0)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 2 unique states visited; 0 backtracks (0 transition replays, 2 states visited overall)
diff --git a/teshsuite/mc/mcmini/simple_barrier_ok.c b/teshsuite/mc/mcmini/simple_barrier_ok.c
new file mode 100644 (file)
index 0000000..1cfdd2a
--- /dev/null
@@ -0,0 +1,11 @@
+#include <pthread.h>
+
+pthread_barrier_t barrier;
+
+int main(int argc, char* argv[])
+{
+    pthread_barrier_init(&barrier, NULL, 1);
+    pthread_barrier_wait(&barrier);
+    return 0;
+}
+
diff --git a/teshsuite/mc/mcmini/simple_barrier_ok.tesh b/teshsuite/mc/mcmini/simple_barrier_ok.tesh
new file mode 100644 (file)
index 0000000..187ac5a
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_barrier_ok
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 3 unique states visited; 0 backtracks (0 transition replays, 3 states visited overall)
diff --git a/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c b/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c
new file mode 100644 (file)
index 0000000..f63f4ba
--- /dev/null
@@ -0,0 +1,43 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int THREAD_NUM; 
+int DEBUG = 0;
+
+pthread_barrier_t barrier;
+pthread_t *thread;
+
+static void * thread_doit(void *unused)
+{
+    if(DEBUG) printf("Thread %lu: Waiting at barrier\n", (unsigned long)pthread_self());
+    pthread_barrier_wait(&barrier);
+    if(DEBUG) printf("Thread %lu: Passed the barrier\n", (unsigned long)pthread_self());
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    if(argc != 3){
+        printf("Usage: %s THREAD_NUM DEBUG_FLAG\n", argv[0]);
+        return 1;
+    }
+
+    THREAD_NUM = atoi(argv[1]);
+    DEBUG = atoi(argv[2]);
+
+    thread = (pthread_t*) malloc(THREAD_NUM * sizeof(pthread_t));
+
+    pthread_barrier_init(&barrier, NULL, THREAD_NUM);
+    for(int i = 0; i < THREAD_NUM; i++) {
+        pthread_create(&thread[i], NULL, &thread_doit, NULL);
+    }
+
+    pthread_barrier_wait(&barrier);
+
+    for(int i = 0; i < THREAD_NUM; i++) {
+        pthread_join(thread[i], NULL);
+    }
+
+    free(thread);
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh b/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh
new file mode 100644 (file)
index 0000000..4f04dd7
--- /dev/null
@@ -0,0 +1,26 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_barrier_with_threads_deadlock 3 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 2 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:4)
+> [0.000000] [ker_engine/INFO] Actor 4 (thread 3@Lilibeth) simcall BARRIER_WAIT(barrier_id:0)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall BARRIER_ASYNC_LOCK(barrier: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall BARRIER_ASYNC_LOCK(barrier: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall BARRIER_ASYNC_LOCK(barrier: 0)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall BARRIER_WAIT(barrier: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall BARRIER_WAIT(barrier: 0)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall ActorJoin(target 2, no timeout)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall BARRIER_WAIT(barrier: 0)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall ActorJoin(target 3, no timeout)
+> [0.000000] [mc_global/INFO]   Actor 4 in simcall BARRIER_ASYNC_LOCK(barrier: 0)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;2;3;1;2;1;3;1;4'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 10 unique states visited; 0 backtracks (0 transition replays, 10 states visited overall)
diff --git a/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c b/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c
new file mode 100644 (file)
index 0000000..0e38451
--- /dev/null
@@ -0,0 +1,54 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int DEBUG;
+
+pthread_barrier_t barrier;
+
+static void * thread_doit(void *t)
+{
+    int *tid = (int*)t;
+    if(DEBUG) {
+        printf("Thread %d: Waiting at barrier\n", *tid);
+    }
+    pthread_barrier_wait(&barrier);
+    if(DEBUG) {
+        printf("Thread %d: Crossed barrier\n", *tid);
+    }
+    return NULL;
+}
+
+int main(int argc, char* argv[])
+{
+    if(argc < 3) {
+        printf("Expected usage: %s THREAD_NUM DEBUG_FLAG\n", argv[0]);
+        printf("DEBUG_FLAG: 0 - Don't display debug information, 1 - Display debug information\n");
+        return -1;
+    }
+
+    int THREAD_NUM = atoi(argv[1]);
+    DEBUG = atoi(argv[2]);
+
+    pthread_t *threads = malloc(sizeof(pthread_t) * THREAD_NUM);
+
+    pthread_barrier_init(&barrier, NULL, THREAD_NUM);
+
+    int *tids = malloc(sizeof(int) * THREAD_NUM);
+    for(int i = 0; i < THREAD_NUM; i++) {
+        tids[i] = i;
+        pthread_create(&threads[i], NULL, &thread_doit, &tids[i]);
+    }
+
+    for(int i = 0; i < THREAD_NUM; i++) {
+        pthread_join(threads[i], NULL);
+    }
+
+    free(threads);
+    free(tids);
+    pthread_barrier_destroy(&barrier);
+    
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh b/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh
new file mode 100644 (file)
index 0000000..9e33a34
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_barrier_with_threads_ok 3 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 10 unique states visited; 0 backtracks (0 transition replays, 10 states visited overall)
diff --git a/teshsuite/mc/mcmini/simple_mutex_deadlock.c b/teshsuite/mc/mcmini/simple_mutex_deadlock.c
new file mode 100644 (file)
index 0000000..cfdfd73
--- /dev/null
@@ -0,0 +1,18 @@
+#include <pthread.h>
+
+pthread_mutex_t mutex1;
+pthread_mutex_t mutex2;
+
+int main(int argc, char* argv[]) {
+    pthread_mutex_init(&mutex1, NULL);
+    pthread_mutex_init(&mutex2, NULL);
+
+    pthread_mutex_lock(&mutex1);
+    pthread_mutex_lock(&mutex2);
+    pthread_mutex_unlock(&mutex2);
+    pthread_mutex_lock(&mutex1);
+    pthread_mutex_unlock(&mutex1);
+
+    return 0;
+}
+
diff --git a/teshsuite/mc/mcmini/simple_mutex_deadlock.tesh b/teshsuite/mc/mcmini/simple_mutex_deadlock.tesh
new file mode 100644 (file)
index 0000000..8f214b2
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_mutex_deadlock
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 9 unique states visited; 0 backtracks (0 transition replays, 9 states visited overall)
diff --git a/teshsuite/mc/mcmini/simple_mutex_ok.c b/teshsuite/mc/mcmini/simple_mutex_ok.c
new file mode 100644 (file)
index 0000000..66189bc
--- /dev/null
@@ -0,0 +1,26 @@
+#include <pthread.h>
+#include <stdio.h>
+
+pthread_mutex_t mutex1;
+pthread_mutex_t mutex2;
+
+int main(int argc, char* argv[]) {
+
+    if(argc != 1) {
+        printf("Expected usage: %s \n", argv[0]);
+        return -1;
+    }
+
+    pthread_mutex_init(&mutex1, NULL);
+    pthread_mutex_init(&mutex2, NULL);
+
+    pthread_mutex_lock(&mutex1);
+    pthread_mutex_lock(&mutex2);
+    pthread_mutex_unlock(&mutex2);
+    pthread_mutex_unlock(&mutex1);
+
+    pthread_mutex_destroy(&mutex1);
+    pthread_mutex_destroy(&mutex2);
+
+    return 0;
+}
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/simple_mutex_ok.tesh b/teshsuite/mc/mcmini/simple_mutex_ok.tesh
new file mode 100644 (file)
index 0000000..65e6c56
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_mutex_ok
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 7 unique states visited; 0 backtracks (0 transition replays, 7 states visited overall)
diff --git a/teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.c b/teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.c
new file mode 100644 (file)
index 0000000..4cf361d
--- /dev/null
@@ -0,0 +1,35 @@
+#include <pthread.h>
+
+pthread_mutex_t mutex1;
+pthread_mutex_t mutex2;
+pthread_t thread1, thread2;
+
+static void * thread_doit1(void *forks_arg) {
+    pthread_mutex_lock(&mutex2);
+    pthread_mutex_lock(&mutex1);
+    pthread_mutex_unlock(&mutex1);
+    pthread_mutex_unlock(&mutex2);
+    return NULL;
+}
+
+static void * thread_doit2(void *forks_arg) {
+    pthread_mutex_lock(&mutex1);
+    pthread_mutex_lock(&mutex2);
+    pthread_mutex_unlock(&mutex2);
+    pthread_mutex_unlock(&mutex1);
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    pthread_mutex_init(&mutex1, NULL);
+    pthread_mutex_init(&mutex2, NULL);
+
+    pthread_create(&thread1, NULL, &thread_doit1, NULL);
+    pthread_create(&thread2, NULL, &thread_doit2, NULL);
+
+    pthread_join(thread1, NULL);
+    pthread_join(thread2, NULL);
+
+    return 0;
+}
+
diff --git a/teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.tesh b/teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.tesh
new file mode 100644 (file)
index 0000000..5fa24c4
--- /dev/null
@@ -0,0 +1,24 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_mutex_with_threads_deadlock
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 3 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:2)
+> [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall MUTEX_WAIT(mutex_id:0 owner:3)
+> [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall MUTEX_WAIT(mutex_id:1 owner:2)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 1, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_WAIT(mutex: 1, owner: 2)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall MUTEX_ASYNC_LOCK(mutex: 0, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_WAIT(mutex: 0, owner: 3)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall MUTEX_ASYNC_LOCK(mutex: 1, owner: 2)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;2;3;2;3;3'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 19 unique states visited; 1 backtracks (2 transition replays, 22 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/simple_mutex_with_threads_ok.c b/teshsuite/mc/mcmini/simple_mutex_with_threads_ok.c
new file mode 100644 (file)
index 0000000..d460e89
--- /dev/null
@@ -0,0 +1,48 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+pthread_mutex_t mutex1;
+pthread_mutex_t mutex2;
+
+static void * thread_doit(void *unused) {
+    pthread_mutex_lock(&mutex1);
+    pthread_mutex_lock(&mutex2);
+    pthread_mutex_unlock(&mutex2);
+    pthread_mutex_unlock(&mutex1);
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+
+    if(argc < 2) {
+        printf("Expected usage: %s THREAD_NUM\n", argv[0]);
+        return -1;
+    }
+
+    int THREAD_NUM = atoi(argv[1]);
+
+    if(THREAD_NUM < 2) {
+        printf("At least 2 threads are required\n");
+        return -1;
+    }
+
+    pthread_t *threads = malloc(sizeof(pthread_t) * THREAD_NUM);
+
+    pthread_mutex_init(&mutex1, NULL);
+    pthread_mutex_init(&mutex2, NULL);
+
+    for(int i = 0; i < THREAD_NUM; i++) {
+        pthread_create(&threads[i], NULL, &thread_doit, NULL);
+    }
+
+    for(int i = 0; i < THREAD_NUM; i++) {
+        pthread_join(threads[i], NULL);
+    }
+
+    free(threads);
+    pthread_mutex_destroy(&mutex1);
+    pthread_mutex_destroy(&mutex2);
+
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/simple_mutex_with_threads_ok.tesh b/teshsuite/mc/mcmini/simple_mutex_with_threads_ok.tesh
new file mode 100644 (file)
index 0000000..f2f23c1
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_mutex_with_threads_ok 4
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 548 unique states visited; 23 backtracks (125 transition replays, 696 states visited overall)
diff --git a/teshsuite/mc/mcmini/simple_semaphore_deadlock.c b/teshsuite/mc/mcmini/simple_semaphore_deadlock.c
new file mode 100644 (file)
index 0000000..1b7d7b3
--- /dev/null
@@ -0,0 +1,36 @@
+#include <pthread.h>
+#include <semaphore.h>
+
+sem_t sem1;
+sem_t sem2;
+pthread_t thread1, thread2;
+
+static void * thread_doit1(void *forks_arg) {
+    sem_wait(&sem2);
+    sem_wait(&sem1);
+    sem_post(&sem1);
+    sem_post(&sem2);
+    return NULL;
+}
+
+static void * thread_doit2(void *forks_arg) {
+    sem_wait(&sem1);
+    sem_wait(&sem2);
+    sem_post(&sem2);
+    sem_post(&sem1);
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    sem_init(&sem1, 0, 1);
+    sem_init(&sem2, 0, 1);
+
+    pthread_create(&thread1, NULL, &thread_doit1, NULL);
+    pthread_create(&thread2, NULL, &thread_doit2, NULL);
+
+    pthread_join(thread1, NULL);
+    pthread_join(thread2, NULL);
+
+    return 0;
+}
+
diff --git a/teshsuite/mc/mcmini/simple_semaphore_deadlock.tesh b/teshsuite/mc/mcmini/simple_semaphore_deadlock.tesh
new file mode 100644 (file)
index 0000000..ed0cf3d
--- /dev/null
@@ -0,0 +1,24 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_semaphore_deadlock
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 3 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:2)
+> [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall SEM_WAIT(sem_id:0 not granted)
+> [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall SEM_WAIT(sem_id:1 not granted)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 1, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 1, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_WAIT(semaphore: 0, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_ASYNC_LOCK(semaphore: 1, capacity: 0)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;2;3;2;3;3'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 19 unique states visited; 1 backtracks (2 transition replays, 22 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/simple_semaphores_deadlock.c b/teshsuite/mc/mcmini/simple_semaphores_deadlock.c
new file mode 100644 (file)
index 0000000..ef8b34a
--- /dev/null
@@ -0,0 +1,16 @@
+#include <pthread.h>
+#include <semaphore.h>
+
+sem_t sem;
+
+int main(int argc, char* argv[]) {
+    sem_init(&sem, 0, 0);
+
+    sem_post(&sem);
+    sem_post(&sem);
+    sem_wait(&sem);
+    sem_wait(&sem);
+    sem_wait(&sem);
+    return 0;
+}
+
diff --git a/teshsuite/mc/mcmini/simple_semaphores_deadlock.tesh b/teshsuite/mc/mcmini/simple_semaphores_deadlock.tesh
new file mode 100644 (file)
index 0000000..b023c3f
--- /dev/null
@@ -0,0 +1,23 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_semaphores_deadlock
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 1 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall SEM_WAIT(sem_id:0 not granted)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall SEM_UNLOCK(semaphore: 0, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall SEM_UNLOCK(semaphore: 0, capacity: 2)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 1)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall SEM_WAIT(semaphore: 0, capacity: 1, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall SEM_WAIT(semaphore: 0, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 1 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;1;1;1;1;1;1'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 8 unique states visited; 0 backtracks (0 transition replays, 8 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/simple_semaphores_ok.c b/teshsuite/mc/mcmini/simple_semaphores_ok.c
new file mode 100644 (file)
index 0000000..92509cd
--- /dev/null
@@ -0,0 +1,32 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+sem_t sem;
+
+int main(int argc, char* argv[]) {
+    if(argc < 2) {
+        printf("Expected usage: %s START_NUM\n", argv[0]);
+        return -1;
+    }
+
+    int start_num = atoi(argv[1]);
+
+    sem_init(&sem, 0, start_num);
+
+    for(int i = 0; i < start_num; i++) {
+        sem_wait(&sem);
+    }
+
+    sem_post(&sem);
+    sem_post(&sem);
+    sem_wait(&sem);
+    sem_wait(&sem);
+
+    sem_destroy(&sem);
+
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/simple_semaphores_ok.tesh b/teshsuite/mc/mcmini/simple_semaphores_ok.tesh
new file mode 100644 (file)
index 0000000..144d78d
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_semaphores_ok 5
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 17 unique states visited; 0 backtracks (0 transition replays, 17 states visited overall)
\ No newline at end of file
diff --git a/teshsuite/mc/mcmini/simple_semaphores_with_threads_deadlock.c b/teshsuite/mc/mcmini/simple_semaphores_with_threads_deadlock.c
new file mode 100644 (file)
index 0000000..5f783fb
--- /dev/null
@@ -0,0 +1,49 @@
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int START_NUM;
+int DEBUG = 0;
+
+sem_t sem1, sem2;
+pthread_t thread1, thread2;
+
+static void * thread1_doit(void *forks_arg) {
+    sem_wait(&sem2);
+    sem_wait(&sem2);
+    if(DEBUG) printf("Thread 1: Posted to sem1\n");
+    sem_post(&sem1);
+    return NULL;
+}
+
+static void * thread2_doit(void *forks_arg) {
+    for( int i = 0; i < START_NUM+1; i++) {
+        if(DEBUG) printf("Thread 2: Waiting for sem1\n");
+        sem_wait(&sem1);
+    }
+    if(DEBUG) printf("Thread 2: Posted to sem2\n");
+    sem_post(&sem2);
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    if(argc != 3){
+        printf("Usage: %s START_NUM DEBUG_FLAG\n", argv[0]);
+        return 1;
+    }
+
+    START_NUM = atoi(argv[1]);
+    DEBUG = atoi(argv[2]);
+
+    sem_init(&sem1, 0, START_NUM);
+    sem_init(&sem2, 0, 1);
+
+    pthread_create(&thread1, NULL, &thread1_doit, NULL);
+    pthread_create(&thread2, NULL, &thread2_doit, NULL);
+
+    pthread_join(thread1, NULL);
+    pthread_join(thread2, NULL);
+
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/simple_semaphores_with_threads_deadlock.tesh b/teshsuite/mc/mcmini/simple_semaphores_with_threads_deadlock.tesh
new file mode 100644 (file)
index 0000000..931802a
--- /dev/null
@@ -0,0 +1,25 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+! expect return 3
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_semaphores_with_threads_deadlock 1 0
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED ***
+> [0.000000] [mc_global/INFO] **************************
+> [0.000000] [ker_engine/INFO] 3 actors are still running, waiting for something.
+> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
+> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:2)
+> [0.000000] [ker_engine/INFO] Actor 2 (thread 1@Lilibeth) simcall SEM_WAIT(sem_id:1 not granted)
+> [0.000000] [ker_engine/INFO] Actor 3 (thread 2@Lilibeth) simcall SEM_WAIT(sem_id:0 not granted)
+> [0.000000] [mc_global/INFO] Counter-example execution trace:
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 1, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_WAIT(semaphore: 1, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 2 in simcall SEM_ASYNC_LOCK(semaphore: 1, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_WAIT(semaphore: 0, capacity: 0, granted: yes)
+> [0.000000] [mc_global/INFO]   Actor 3 in simcall SEM_ASYNC_LOCK(semaphore: 0, capacity: 0)
+> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'2;2;2;3;3;3'
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 7 unique states visited; 0 backtracks (0 transition replays, 7 states visited overall)
+
diff --git a/teshsuite/mc/mcmini/simple_semaphores_with_threads_ok.c b/teshsuite/mc/mcmini/simple_semaphores_with_threads_ok.c
new file mode 100644 (file)
index 0000000..4e1ff7a
--- /dev/null
@@ -0,0 +1,46 @@
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+sem_t sem1, sem2;
+pthread_t thread1, thread2;
+
+static void * thread1_doit(void *unused) {
+    sem_wait(&sem2);
+    sem_post(&sem1);
+    sem_wait(&sem2);
+    return NULL;
+}
+
+static void * thread2_doit(void *sem_count) {
+    int start_num = *((int*)sem_count);
+    for(int i = 0; i < start_num + 1; i++) {
+        sem_wait(&sem1);
+    }
+    sem_post(&sem2);
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    if(argc < 2) {
+        printf("Expected usage: %s START_NUM\n", argv[0]);
+        return -1;
+    }
+
+    int start_num = atoi(argv[1]);
+
+    sem_init(&sem1, 0, start_num);
+    sem_init(&sem2, 0, 1);
+
+    pthread_create(&thread1, NULL, &thread1_doit, NULL);
+    pthread_create(&thread2, NULL, &thread2_doit, &start_num);
+
+    pthread_join(thread1, NULL);
+    pthread_join(thread2, NULL);
+
+    sem_destroy(&sem1);
+    sem_destroy(&sem2);
+
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/simple_semaphores_with_threads_ok.tesh b/teshsuite/mc/mcmini/simple_semaphores_with_threads_ok.tesh
new file mode 100644 (file)
index 0000000..a782781
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_semaphores_with_threads_ok 3
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 24 unique states visited; 1 backtracks (1 transition replays, 26 states visited overall)
diff --git a/teshsuite/mc/mcmini/simple_threads_ok.c b/teshsuite/mc/mcmini/simple_threads_ok.c
new file mode 100644 (file)
index 0000000..44c716c
--- /dev/null
@@ -0,0 +1,33 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+static void * thread_doit(void *unused) {
+    int len = (int) ((drand48() * 5) + 1);
+    sleep(len);
+    return NULL;
+}
+
+int main(int argc, char* argv[]) {
+    if(argc < 2) {
+        printf("Expected usage: %s THREAD_NUM\n", argv[0]);
+        return -1;
+    }
+
+    int thread_num = atoi(argv[1]);
+
+    pthread_t *threads = malloc(sizeof(pthread_t) * thread_num);
+
+    for(int i = 0; i < thread_num; i++) {
+        pthread_create(&threads[i], NULL, &thread_doit, NULL);
+    }
+
+    for(int i = 0; i < thread_num; i++) {
+        pthread_join(threads[i], NULL);
+    }
+
+    free(threads);
+
+    return 0;
+}
diff --git a/teshsuite/mc/mcmini/simple_threads_ok.tesh b/teshsuite/mc/mcmini/simple_threads_ok.tesh
new file mode 100644 (file)
index 0000000..b8a82c5
--- /dev/null
@@ -0,0 +1,7 @@
+# We ignore the LD_PRELOAD lines from the expected output because they contain the build path
+! ignore .*LD_PRELOAD.*
+
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_threads_ok 3
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor.
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 7 unique states visited; 0 backtracks (0 transition replays, 7 states visited overall)
\ No newline at end of file
index adb9519..8f98636 100644 (file)
@@ -30,7 +30,7 @@ XBT_LOG_NEW_DEFAULT_CATEGORY(mutex_handling, "Messages specific for this test");
 
 static int receiver(const char* box_name)
 {
-  auto mb = simgrid::s4u::Mailbox::by_name(box_name);
+  auto* mb = simgrid::s4u::Mailbox::by_name(box_name);
   std::unique_ptr<int> payload;
 
   payload = mb->get_unique<int>();
@@ -45,7 +45,7 @@ static int receiver(const char* box_name)
 static int sender(const char* box_name, simgrid::s4u::MutexPtr mutex, int value)
 {
   auto* payload = new int(value);
-  auto mb      = simgrid::s4u::Mailbox::by_name(box_name);
+  auto* mb      = simgrid::s4u::Mailbox::by_name(box_name);
 
   std::unique_lock<simgrid::s4u::Mutex> lock;
   if (mutex)
index 426c301..278ad03 100644 (file)
@@ -1,4 +1,4 @@
 #!/usr/bin/env tesh
 ! expect return 1
 ! output display
-$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/mutex-handling ${srcdir:=.}/examples/platforms/small_platform.xml
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/mutex-handling ${srcdir:=.}/examples/platforms/small_platform.xml
index 53136bf..f594963 100644 (file)
@@ -2,4 +2,4 @@
 ! expect return 1
 ! output display
 ! timeout 30
-$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/without-mutex-handling ${srcdir:=.}/examples/platforms/small_platform.xml
+$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/without-mutex-handling ${srcdir:=.}/examples/platforms/small_platform.xml
index 9bade15..80b910e 100644 (file)
@@ -3,6 +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 <csignal>
 #include <cstring>
 #include <simgrid/modelchecker.h>
 #include <simgrid/s4u.hpp>
@@ -30,11 +31,8 @@ static void app()
     if (x == 3 && y == 4)
       abort();
   } else if (behavior == Behavior::SEGV) {
-#ifndef __clang_analyzer__
-    int* A = nullptr;
     if (x == 3 && y == 4)
-      *A = 1;
-#endif
+      raise(SIGSEGV); // Simulate a segfault without displeasing the static analyzers
   } else {
     DIE_IMPOSSIBLE;
   }
index 952ba8e..9300200 100644 (file)
@@ -1,20 +1,20 @@
 #!/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
+$ $VALGRIND_NO_TRACE_CHILDREN ${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@) 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@) **************************
 > [  0.000000] (0:maestro@) Counter-example execution trace:
-> [  0.000000] (0:maestro@)   1: Random([0;5] ~> 3)
-> [  0.000000] (0:maestro@)   1: Random([0;5] ~> 4)
+> [  0.000000] (0:maestro@)   Actor 1 in simcall Random([0;5] ~> 3)
+> [  0.000000] (0:maestro@)   Actor 1 in simcall Random([0;5] ~> 4)
 > [  0.000000] (0:maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1/3;1/4'
-> [  0.000000] (0:maestro@) DFS exploration ended. 27 unique states visited; 22 backtracks (68 transition replays, 19 states visited overall)
+> [  0.000000] (0:maestro@) DFS exploration ended. 27 unique states visited; 22 backtracks (19 transition replays, 68 states visited overall)
 
 ! 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
+$ $VALGRIND_NO_TRACE_CHILDREN ${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@) Behavior: abort
 > [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) **************************
@@ -22,21 +22,20 @@ $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug abort ${platfdir}
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) From signal: Aborted
 > [  0.000000] (0:maestro@) Counter-example execution trace:
-> [  0.000000] (0:maestro@)   1: Random([0;5] ~> 3)
-> [  0.000000] (0:maestro@)   1: Random([0;5] ~> 4)
+> [  0.000000] (0:maestro@)   Actor 1 in simcall Random([0;5] ~> 3)
+> [  0.000000] (0:maestro@)   Actor 1 in simcall Random([0;5] ~> 4)
 > [  0.000000] (0:maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1/3;1/4'
-> [  0.000000] (0:maestro@) DFS exploration ended. 27 unique states visited; 22 backtracks (68 transition replays, 19 states visited overall)
-> [  0.000000] (0:maestro@) Stack trace not displayed because you passed --log=no_loc
+> [  0.000000] (0:maestro@) DFS exploration ended. 27 unique states visited; 22 backtracks (19 transition replays, 68 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
+$ $VALGRIND_NO_TRACE_CHILDREN ${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@) 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)
+> [  0.000000] (0:maestro@) DFS exploration ended. 43 unique states visited; 35 backtracks (30 transition replays, 108 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
+$ $VALGRIND_NO_TRACE_CHILDREN ${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@) Behavior: segv
 > [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > Segmentation fault.
@@ -45,8 +44,7 @@ $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug segv ${platfdir}/
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) From signal: Segmentation fault
 > [  0.000000] (0:maestro@) Counter-example execution trace:
-> [  0.000000] (0:maestro@)   1: Random([0;5] ~> 3)
-> [  0.000000] (0:maestro@)   1: Random([0;5] ~> 4)
+> [  0.000000] (0:maestro@)   Actor 1 in simcall Random([0;5] ~> 3)
+> [  0.000000] (0:maestro@)   Actor 1 in simcall Random([0;5] ~> 4)
 > [  0.000000] (0:maestro@) You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1/3;1/4'
-> [  0.000000] (0:maestro@) DFS exploration ended. 27 unique states visited; 22 backtracks (68 transition replays, 19 states visited overall)
-> [  0.000000] (0:maestro@) Stack trace not displayed because you passed --log=no_loc
+> [  0.000000] (0:maestro@) DFS exploration ended. 27 unique states visited; 22 backtracks (19 transition replays, 68 states visited overall)
index 5f2c22e..1751a7d 100644 (file)
@@ -112,11 +112,8 @@ int main(int argc, char** argv)
     links[name] = zone->create_link(name, 1e9)->set_latency(1e-9)->seal();
   }
   links["L0"] = zone->create_link("L0", 1e3)->seal();
-  zone->add_route(hosts["S1"]->get_netpoint(), hosts["C1"]->get_netpoint(), nullptr, nullptr,
-                  {sg4::LinkInRoute(links["L1"]), sg4::LinkInRoute(links["L0"]), sg4::LinkInRoute(links["L2"])});
-  zone->add_route(hosts["S2"]->get_netpoint(), hosts["C2"]->get_netpoint(), nullptr, nullptr,
-                  {sg4::LinkInRoute(links["L3"]), sg4::LinkInRoute(links["L0"]), sg4::LinkInRoute(links["L4"])});
-
+  zone->add_route(hosts["S1"], hosts["C1"], {links["L1"], links["L0"], links["L2"]});
+  zone->add_route(hosts["S2"], hosts["C2"], {links["L3"], links["L0"], links["L4"]});
   zone->seal();
 
   sg4::Actor::create("", hosts["S1"], sender, "C1", nullptr);
index 966f548..4dfd24f 100644 (file)
@@ -86,7 +86,7 @@ int main(int argc, char** argv)
   auto const* host1 = zone->create_host("host1", 1e6)->seal();
   auto const* host2 = zone->create_host("host2", 1e6)->seal();
   auto* testlink    = zone->create_link("L1", 1e10)->seal();
-  zone->add_route(host1->get_netpoint(), host2->get_netpoint(), nullptr, nullptr, {sg4::LinkInRoute(testlink)});
+  zone->add_route(host1, host2, {testlink});
 
   simgrid::s4u::Actor::create("dispatcher", engine.host_by_name("host1"), main_dispatcher, testlink);
   engine.run();
index 8268a37..c9df586 100644 (file)
@@ -15,13 +15,13 @@ namespace sg4 = simgrid::s4u;
 XBT_LOG_NEW_DEFAULT_CATEGORY(issue105, "Issue105");
 static void load_generator(sg4::Mailbox* mailbox)
 {
-  std::vector<sg4::CommPtr> comms;
+  sg4::ActivitySet comms;
 
   // Send the task messages
   for (int i = 0; i < 100; i++) {
     auto* payload     = new int(i);
     sg4::CommPtr comm = mailbox->put_async(payload, 1024);
-    comms.push_back(comm);
+    comms.push(comm);
     sg4::this_actor::sleep_for(1.0);
   }
 
@@ -29,10 +29,10 @@ static void load_generator(sg4::Mailbox* mailbox)
   auto* payload     = new int(-1);
   sg4::CommPtr comm = mailbox->put_async(payload, 1024);
   XBT_INFO("Sent shutdown");
-  comms.push_back(comm);
+  comms.push(comm);
 
   // Wait for all messages to be consumed before ending the simulation
-  sg4::Comm::wait_all(comms);
+  comms.wait_all();
   XBT_INFO("Load generator finished");
 }
 
@@ -75,8 +75,7 @@ int main(int argc, char* argv[])
                                 ->set_bandwidth_profile(linkSaBandwidthProfile)
                                 ->seal();
 
-  world->add_route(hostGl01->get_netpoint(), hostSa01->get_netpoint(), nullptr, nullptr,
-                   {{linkSa, sg4::LinkInRoute::Direction::NONE}}, true);
+  world->add_route(hostGl01, hostSa01, {{linkSa, sg4::LinkInRoute::Direction::NONE}}, true);
   world->seal();
 
   sg4::Mailbox* mb1 = e.mailbox_by_name_or_create("Mailbox 1");
index 4a13429..4cea0bb 100644 (file)
@@ -47,8 +47,8 @@ int main(int argc, char* argv[])
   auto* rootzone = sg4::create_full_zone("root");
   auto* hostA    = rootzone->create_host("hostA", 1e9);
   auto* hostB    = rootzone->create_host("hostB", 1e9);
-  sg4::LinkInRoute link(rootzone->create_link("backbone", "1")->set_latency("1s")->seal());
-  rootzone->add_route(hostA->get_netpoint(), hostB->get_netpoint(), nullptr, nullptr, {link}, true);
+  auto* backb    = rootzone->create_link("backbone", "1")->set_latency("1s")->seal();
+  rootzone->add_route(hostA, hostB, {backb});
   rootzone->seal();
 
   sg4::Actor::create("ptask", hostA, ptask, hostA, hostB);
index 75836a0..b9e1ff2 100644 (file)
@@ -3,7 +3,7 @@ $ ${bindir:=.}/flatifier ./one_cluster.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="bob0.hamburger.edu" speed="1e+09"/>
 >   <host id="bob2.hamburger.edu" speed="1e+09"/>
 >   <host id="bob3.hamburger.edu" speed="1e+09"/>
@@ -127,14 +127,14 @@ $ ${bindir:=.}/flatifier ./one_cluster.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%
 >   <route src="bobbob_cluster_router.hamburger.edu" dst="bob6.hamburger.edu">
 >   <link_ctn id="bob_cluster_backbone"/><link_ctn id="bob_cluster_link_6_DOWN"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./one_cluster_multicore.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="bob0.hamburger.edu" speed="1e+09" core="6"/>
 >   <host id="bob2.hamburger.edu" speed="1e+09" core="6"/>
 >   <host id="bob3.hamburger.edu" speed="1e+09" core="6"/>
@@ -257,14 +257,14 @@ $ ${bindir:=.}/flatifier ./one_cluster_multicore.xml "--log=root.fmt:[%10.6r]%e[
 >   <route src="bobbob_cluster_router.hamburger.edu" dst="bob6.hamburger.edu">
 >   <link_ctn id="bob_cluster_link_6_DOWN"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./host_attributes.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="alice" speed="1e+09"/>
 >   <host id="bob" speed="1e+09"/>
 >   <host id="carol" speed="5e+08"/>
@@ -290,14 +290,14 @@ $ ${bindir:=.}/flatifier ./host_attributes.xml "--log=root.fmt:[%10.6r]%e[%i:%a@
 >   <route src="erin" dst="erin">
 >   <link_ctn id="__loopback__"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./link_attributes.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="bob" speed="5e+08"/>
 >   <link id="__loopback__" bandwidth="1e+10" latency="0" sharing_policy="FATPIPE"/>
 >   <link id="link1" bandwidth="1.25e+08" latency="5e-05"/>
@@ -307,14 +307,14 @@ $ ${bindir:=.}/flatifier ./link_attributes.xml "--log=root.fmt:[%10.6r]%e[%i:%a@
 >   <route src="bob" dst="bob">
 >   <link_ctn id="__loopback__"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./three_hosts_non_symmetric_route.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="alice" speed="5e+08"/>
 >   <host id="bob" speed="1e+09"/>
 >   <host id="trudy" speed="2.5e+08"/>
@@ -349,14 +349,14 @@ $ ${bindir:=.}/flatifier ./three_hosts_non_symmetric_route.xml "--log=root.fmt:[
 >   <route src="trudy" dst="trudy">
 >   <link_ctn id="__loopback__"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./two_clusters.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="alice0.crepe.fr" speed="1e+09"/>
 >   <host id="alice1.crepe.fr" speed="1e+09"/>
 >   <host id="bob0.hamburger.edu" speed="1e+09"/>
@@ -477,14 +477,14 @@ $ ${bindir:=.}/flatifier ./two_clusters.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]
 >   <route src="bobbob_cluster_router.hamburger.edu" dst="bob1.hamburger.edu">
 >   <link_ctn id="bob_cluster_backbone"/><link_ctn id="bob_cluster_link_1_DOWN"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./two_hosts_multi_hop.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="alice" speed="5e+08"/>
 >   <host id="bob" speed="1e+09"/>
 >   <link id="__loopback__" bandwidth="1e+10" latency="0" sharing_policy="FATPIPE"/>
@@ -503,14 +503,14 @@ $ ${bindir:=.}/flatifier ./two_hosts_multi_hop.xml "--log=root.fmt:[%10.6r]%e[%i
 >   <route src="bob" dst="bob">
 >   <link_ctn id="__loopback__"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./two_hosts_one_link.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="alice" speed="5e+08"/>
 >   <host id="bob" speed="1e+09"/>
 >   <link id="__loopback__" bandwidth="1e+10" latency="0" sharing_policy="FATPIPE"/>
@@ -527,14 +527,14 @@ $ ${bindir:=.}/flatifier ./two_hosts_one_link.xml "--log=root.fmt:[%10.6r]%e[%i:
 >   <route src="bob" dst="bob">
 >   <link_ctn id="__loopback__"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ${srcdir:=.}/examples/platforms/bypassZoneRoute.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="1" speed="1e+09"/>
 >   <host id="2" speed="1e+09"/>
 >   <host id="3" speed="1e+09"/>
@@ -651,14 +651,14 @@ $ ${bindir:=.}/flatifier ${srcdir:=.}/examples/platforms/bypassZoneRoute.xml "--
 >   <route src="my_cluster_3_router" dst="3">
 >   <link_ctn id="my_cluster_3_link_3_DOWN"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ${srcdir:=.}/examples/platforms/cluster_torus.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="world" routing="Full">
+> <zone id="world" routing="Full">
 >   <host id="node-0.simgrid.org" speed="1e+09"/>
 >   <host id="node-1.simgrid.org" speed="1e+09"/>
 >   <host id="node-10.simgrid.org" speed="1e+09"/>
@@ -1188,14 +1188,14 @@ $ ${bindir:=.}/flatifier ${srcdir:=.}/examples/platforms/cluster_torus.xml "--lo
 >   <route src="node-9.simgrid.org" dst="node-9.simgrid.org">
 >   <link_ctn id="bob_cluster_link_9_loopback"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./cluster_dragonfly_noncontiguous_rad.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="world" routing="Full">
+> <zone id="world" routing="Full">
 >   <host id="node-0.simgrid.org" speed="1e+09"/>
 >   <host id="node-1002.simgrid.org" speed="1e+09"/>
 >   <host id="node-1003.simgrid.org" speed="1e+09"/>
@@ -1277,14 +1277,14 @@ $ ${bindir:=.}/flatifier ./cluster_dragonfly_noncontiguous_rad.xml "--log=root.f
 >   <route src="node-1004.simgrid.org" dst="node-1004.simgrid.org">
 >   <link_ctn id="bob_cluster_link_1004_loopback"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./cluster_fat_tree_noncontiguous_rad.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="world" routing="Full">
+> <zone id="world" routing="Full">
 >   <host id="node-100.simgrid.org" speed="1e+09"/>
 >   <host id="node-101.simgrid.org" speed="1e+09"/>
 >   <host id="node-119.simgrid.org" speed="1e+09"/>
@@ -1374,14 +1374,14 @@ $ ${bindir:=.}/flatifier ./cluster_fat_tree_noncontiguous_rad.xml "--log=root.fm
 >   <route src="node-120.simgrid.org" dst="node-120.simgrid.org">
 >   <link_ctn id="bob_cluster_link_120_loopback"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./cluster_torus_noncontiguous_rad.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="world" routing="Full">
+> <zone id="world" routing="Full">
 >   <host id="node-0.simgrid.org" speed="1e+09"/>
 >   <host id="node-1.simgrid.org" speed="1e+09"/>
 >   <host id="node-102.simgrid.org" speed="1e+09"/>
@@ -1467,14 +1467,14 @@ $ ${bindir:=.}/flatifier ./cluster_torus_noncontiguous_rad.xml "--log=root.fmt:[
 >   <route src="node-103.simgrid.org" dst="node-103.simgrid.org">
 >   <link_ctn id="bob_cluster_link_103_loopback"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
 
 $ ${bindir:=.}/flatifier ./two_hosts_one_link_splitduplex.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
 > <?xml version='1.0'?>
 > <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
 > <platform version="4.1">
-> <AS id="AS0" routing="Full">
+> <zone id="AS0" routing="Full">
 >   <host id="alice" speed="5e+08"/>
 >   <host id="bob" speed="1e+09"/>
 >   <link id="__loopback__" bandwidth="1e+10" latency="0" sharing_policy="FATPIPE"/>
@@ -1492,5 +1492,5 @@ $ ${bindir:=.}/flatifier ./two_hosts_one_link_splitduplex.xml "--log=root.fmt:[%
 >   <route src="bob" dst="bob">
 >   <link_ctn id="__loopback__"/>
 >   </route>
-> </AS>
+> </zone>
 > </platform>
index a28a532..9859b54 100644 (file)
@@ -59,12 +59,13 @@ def load_platform():
     host1.create_disk("disk1", 1e5, 1e4).seal()
     host1.create_disk("disk2", "1MBps", "1Mbps").seal()
     host1.seal()
+    dijkstra.set_gateway(host1)
     host2 = dijkstra.create_host("host2", ["1Gf", "1Mf"]).seal()
     hosts.append(host2)
     link1 = dijkstra.create_link("link1_up", [1e9]).set_latency(1e-3).set_concurrency_limit(10).seal()
     link2 = dijkstra.create_link("link1_down", ["1GBps"]).set_latency("1ms").seal()
-    dijkstra.add_route(host1.netpoint, host2.netpoint, None, None, [LinkInRoute(link1)], False)
-    dijkstra.add_route(host2.netpoint, host1.netpoint, None, None, [LinkInRoute(link2)], False)
+    dijkstra.add_route(host1, host2, [LinkInRoute(link1)], False)
+    dijkstra.add_route(host2, host1, [LinkInRoute(link2)], False)
     dijkstra.seal()
 
     # vivaldi
@@ -72,6 +73,7 @@ def load_platform():
     this_actor.info(msg_base + vivaldi.name)
     vivaldi.set_parent(root)
     host3 = vivaldi.create_host("host3", 1e9).set_coordinates("1 1 1").seal()
+    vivaldi.set_gateway(host3)
     host4 = vivaldi.create_host("host4", "1Gf").set_coordinates("2 2 2").seal()
     hosts.append(host3)
     hosts.append(host4)
@@ -81,6 +83,7 @@ def load_platform():
     this_actor.info(msg_base + empty.name)
     empty.set_parent(root)
     host5 = empty.create_host("host5", 1e9)
+    empty.set_gateway(host5)
     hosts.append(host5)
     empty.seal()
 
@@ -89,6 +92,7 @@ def load_platform():
     this_actor.info(msg_base + wifi.name)
     wifi.set_parent(root)
     router = wifi.create_router("wifi_router")
+    wifi.set_gateway(router)
     wifi.set_property("access_point", "wifi_router")
     host6 = wifi.create_host(
         "host6", ["100.0Mf", "50.0Mf", "20.0Mf"]).seal()
@@ -101,9 +105,9 @@ def load_platform():
     link_a = vivaldi.create_link("linkA", 1e9).seal()
     link_b = vivaldi.create_link("linkB", "1GBps").seal()
     link_c = vivaldi.create_link("linkC", "1GBps").seal()
-    root.add_route(dijkstra.netpoint, vivaldi.netpoint, host1.netpoint, host3.netpoint, [LinkInRoute(link_a)], True)
-    root.add_route(vivaldi.netpoint, empty.netpoint, host3.netpoint, host5.netpoint, [LinkInRoute(link_b)], True)
-    root.add_route(empty.netpoint, wifi.netpoint, host5.netpoint, router, [LinkInRoute(link_c)], True)
+    root.add_route(dijkstra, vivaldi, [link_a])
+    root.add_route(vivaldi, empty, [link_b])
+    root.add_route(empty, wifi, [link_c])
 
     # create actors Sender/Receiver
     Actor.create("sender", hosts[0], Sender(hosts))
index 83969f8..a21866a 100644 (file)
@@ -6,7 +6,7 @@ endforeach()
 
 foreach(x actor actor-autorestart actor-suspend
         activity-lifecycle
-        comm-get-sender comm-pt2pt comm-fault-scenarios wait-all-for wait-any-for
+        comm-get-sender comm-pt2pt comm-fault-scenarios
         cloud-interrupt-migration cloud-two-execs
        monkey-masterworkers monkey-semaphore
         concurrent_rw
@@ -39,7 +39,7 @@ set_property(TARGET activity-lifecycle APPEND PROPERTY INCLUDE_DIRECTORIES "${IN
 
 ## Add the tests.
 ## Some need to be run with all factories, some don't need tesh to run
-foreach(x actor actor-autorestart actor-suspend activity-lifecycle comm-get-sender wait-all-for wait-any-for
+foreach(x actor actor-autorestart actor-suspend activity-lifecycle comm-get-sender
         cloud-interrupt-migration cloud-two-execs concurrent_rw dag-incomplete-simulation dependencies io-set-bw io-stream
              vm-live-migration vm-suicide)
   set(tesh_files    ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/${x}/${x}.tesh)
@@ -105,7 +105,7 @@ if(SIMGRID_HAVE_NS3)
     add_executable       (${x}  EXCLUDE_FROM_ALL ${x}/${x}.cpp)
     target_link_libraries(${x}  simgrid)
     set_target_properties(${x}  PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${x})
-    add_dependencies(tests ${x})
+    add_dependencies(tests-ns3 ${x})
     ADD_TESH(tesh-s4u-${x} --setenv srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/s4u/${x} --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --cd ${CMAKE_BINARY_DIR}/teshsuite/s4u/${x} ${CMAKE_HOME_DIRECTORY}/teshsuite/s4u/${x}/${x}.tesh)
   endforeach()
 endif()
index f485fc8..f00b25b 100644 (file)
@@ -312,9 +312,9 @@ TEST_CASE("Activity lifecycle: comm activities")
     simgrid::s4u::ActorPtr receiver = simgrid::s4u::Actor::create("receiver", all_hosts[1], []() {
       assert_exit(true, 2);
       int* data;
-      simgrid::s4u::CommPtr comm                       = simgrid::s4u::Mailbox::by_name("mb")->get_async<int>(&data);
-      std::vector<simgrid::s4u::CommPtr> pending_comms = {comm};
-      REQUIRE_NETWORK_FAILURE(simgrid::s4u::Comm::wait_any(pending_comms));
+      simgrid::s4u::CommPtr comm = simgrid::s4u::Mailbox::by_name("mb")->get_async<int>(&data);
+      simgrid::s4u::ActivitySet pending_comms({comm});
+      REQUIRE_NETWORK_FAILURE(pending_comms.wait_any());
     });
 
     simgrid::s4u::ActorPtr sender = simgrid::s4u::Actor::create("sender", all_hosts[2], []() {
index 4b9d72f..769763b 100644 (file)
@@ -123,7 +123,7 @@ TEST_CASE("Activity lifecycle: direct communication (sendto) activities")
     });
 
     simgrid::s4u::this_actor::yield();
-    auto link = simgrid::s4u::Engine::get_instance()->link_by_name("link1");
+    auto* link = simgrid::s4u::Engine::get_instance()->link_by_name("link1");
     link->turn_off();
     link->turn_on();
 
@@ -139,7 +139,7 @@ TEST_CASE("Activity lifecycle: direct communication (sendto) activities")
     });
 
     simgrid::s4u::this_actor::sleep_for(2);
-    auto link = simgrid::s4u::Engine::get_instance()->link_by_name("link1");
+    auto* link = simgrid::s4u::Engine::get_instance()->link_by_name("link1");
     link->turn_off();
     link->turn_on();
 
@@ -160,7 +160,7 @@ TEST_CASE("Activity lifecycle: direct communication (sendto) activities")
     simgrid::s4u::Actor::create("killer", all_hosts[0], []() {
       simgrid::s4u::this_actor::sleep_for(5);
       XBT_VERB("Killer!");
-      auto link = simgrid::s4u::Engine::get_instance()->link_by_name("link1");
+      auto* link = simgrid::s4u::Engine::get_instance()->link_by_name("link1");
       link->turn_off();
       link->turn_on();
     });
index 35867e0..855f56e 100644 (file)
@@ -60,19 +60,21 @@ template <int Duration, typename Activity> bool tester_wait_any(const Activity&
   const double timeout      = simgrid::s4u::Engine::get_clock() + duration;
   bool ret;
   try {
-    std::vector<Activity> activities = {activity};
+    simgrid::s4u::ActivitySet set;
+    set.push(activity);
+
     XBT_DEBUG("calling wait_any_for(%f)", duration);
-    ssize_t index = Activity::element_type::wait_any_for(activities, duration);
-    if (index == -1) {
-      XBT_DEBUG("wait_any_for() timed out");
-      INFO("wait_any_for() timeout should expire at expected date: " << timeout);
-      REQUIRE(simgrid::s4u::Engine::get_clock() == Approx(timeout));
-      ret = false;
-    } else {
-      XBT_DEBUG("wait_any_for() returned index %zd", index);
-      REQUIRE(index == 0);
-      ret = true;
-    }
+    auto waited_activity = set.wait_any_for(duration);
+
+    XBT_DEBUG("wait_any_for() returned activity %p", waited_activity.get());
+    REQUIRE(waited_activity.get() == activity);
+    ret = true;
+
+  } catch (const simgrid::TimeoutException& e) {
+    XBT_DEBUG("wait_any_for() timed out");
+    INFO("wait_any_for() timeout should expire at expected date: " << timeout);
+    REQUIRE(simgrid::s4u::Engine::get_clock() == Approx(timeout));
+    ret = false;
   } catch (const simgrid::Exception& e) {
     XBT_DEBUG("wait_any_for() threw an exception: %s", e.what());
     ret = true;
index ed4d1ed..91aad4d 100644 (file)
@@ -19,7 +19,7 @@ public:
   void operator()() const
   {
     XBT_INFO("Starting.");
-    auto mailbox = simgrid::s4u::Mailbox::by_name("receiver");
+    auto* mailbox = simgrid::s4u::Mailbox::by_name("receiver");
     int data     = *mailbox->get<int>();
     XBT_INFO("Got %d at the end", data);
   }
@@ -42,7 +42,7 @@ public:
     simgrid::s4u::this_actor::sleep_for(10);
 
     XBT_INFO("Sending a message to the receiver...");
-    auto mailbox = simgrid::s4u::Mailbox::by_name("receiver");
+    auto* mailbox   = simgrid::s4u::Mailbox::by_name("receiver");
     static int data = 42;
     mailbox->put(&data, 4);
 
index 2a3d976..5fdbb08 100644 (file)
@@ -1,47 +1,49 @@
 ! output sort
 
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/one_cluster.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms one_cluster.xml --log=root.fmt=%m%n
 > Workstation number: 5, link number: 12
 
 ! output sort
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/host_attributes.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms host_attributes.xml --log=root.fmt=%m%n
 > Workstation number: 5, link number: 1
 
 ! output sort
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/link_attributes.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms link_attributes.xml --log=root.fmt=%m%n
 > Workstation number: 1, link number: 5
 
 ! output sort
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/three_hosts_non_symmetric_route.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms three_hosts_non_symmetric_route.xml --log=root.fmt=%m%n
 > Workstation number: 3, link number: 4
 
 ! output sort
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/two_clusters.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms two_clusters.xml --log=root.fmt=%m%n
 > Workstation number: 4, link number: 12
 
 ! output sort
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/two_hosts_multi_hop.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms two_hosts_multi_hop.xml --log=root.fmt=%m%n
 > Workstation number: 2, link number: 4
 
 ! output sort
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/two_hosts_one_link.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms two_hosts_one_link.xml --log=root.fmt=%m%n
 > Workstation number: 2, link number: 2
 
 ! output sort
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/four_hosts_floyd.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms four_hosts_floyd.xml --log=root.fmt=%m%n
 > Workstation number: 4, link number: 5
 
 ! output sort
 $ ${bindir:=.}/basic-parsing-test ${platfdir:=.}/cloud.xml --log=root.fmt=%m%n
 > Workstation number: 510, link number: 1056
 
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/properties.xml --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms properties.xml --log=root.fmt=%m%n
 > Configuration change: Set 'cpu/optim' to 'TI'
+> The custom configuration 'path' is already defined by user!
 > Configuration change: Set 'precision/work-amount' to '0.000010'
 > Workstation number: 1, link number: 1
 
-$ ${bindir:=.}/basic-parsing-test ${srcdir:=.}/../../platforms/properties.xml --cfg=cpu/optim:TI --log=root.fmt=%m%n
+$ ${bindir:=.}/basic-parsing-test --cfg=path:${srcdir:=.}/../../platforms properties.xml --cfg=cpu/optim:TI --log=root.fmt=%m%n
 > Configuration change: Set 'cpu/optim' to 'TI'
 > The custom configuration 'cpu/optim' is already defined by user!
+> The custom configuration 'path' is already defined by user!
 > Configuration change: Set 'precision/work-amount' to '0.000010'
 > Workstation number: 1, link number: 1
index 3843601..b996076 100644 (file)
@@ -409,11 +409,10 @@ int main(int argc, char* argv[])
   pr::Profile* profile_link = pr::ProfileBuilder::from_string("link_profile", ctx.link_profile.str(), 0);
   sg4::Link const* link =
       zone->create_link("link", LinkBandwidth)->set_latency(LinkLatency)->set_state_profile(profile_link)->seal();
-  zone->add_route(sender_host->get_netpoint(), receiver_host->get_netpoint(), nullptr, nullptr,
-                  {sg4::LinkInRoute{link}}, false);
+  zone->add_route(sender_host, receiver_host, {link});
   zone->seal();
 
-  sg4::Host::on_state_change_cb([mbox](sg4::Host const& host) {
+  sg4::Host::on_onoff_cb([mbox](sg4::Host const& host) {
     XBT_DEBUG("Host %s is now %s", host.get_cname(), host.is_on() ? "ON " : "OFF");
     if (not host.is_on()) {
       mbox.eager->clear();
@@ -421,7 +420,7 @@ int main(int argc, char* argv[])
     }
   });
 
-  sg4::Link::on_state_change_cb(
+  sg4::Link::on_onoff_cb(
       [](sg4::Link const& lnk) { XBT_DEBUG("Link %s is now %s", lnk.get_cname(), lnk.is_on() ? "ON " : "OFF"); });
 
   e.run_until(end_time);
index d81bce5..140d969 100644 (file)
@@ -23,7 +23,7 @@ int main(int argc, char** argv)
   simgrid::s4u::Engine e(&argc, argv);
   e.load_platform(argv[1]);
 
-  auto host = e.host_by_name("cpu0");
+  auto* host = e.host_by_name("cpu0");
   /* creation of the tasks and their dependencies */
   simgrid::s4u::ExecPtr Init = simgrid::s4u::Exec::init()->set_name("Init")->set_flops_amount(0)->start();
   simgrid::s4u::CommPtr A = simgrid::s4u::Comm::sendto_init()->set_name("A")->set_payload_size(1e9)->start();
index b229d70..fa1e49d 100644 (file)
@@ -13,12 +13,9 @@ int main(int argc, char** argv)
   xbt_assert(argc > 1, "Usage: %s platform_file\n\nExample: %s two_clusters.xml", argv[0], argv[0]);
   engine.load_platform(argv[1]);
 
-  simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
-    const auto* exec = dynamic_cast<simgrid::s4u::Exec const*>(&activity);
-    if (exec == nullptr) // Only Execs are concerned here
-      return;
-    XBT_INFO("Exec '%s' start time: %f, finish time: %f", exec->get_cname(), exec->get_start_time(),
-             exec->get_finish_time());
+  simgrid::s4u::Exec::on_completion_cb([](simgrid::s4u::Exec const& exec) {
+    XBT_INFO("Exec '%s' start time: %f, finish time: %f", exec.get_cname(), exec.get_start_time(),
+             exec.get_finish_time());
   });
 
   /* creation of the activities and their dependencies */
index c1d70c4..fcc42cb 100644 (file)
@@ -39,7 +39,7 @@ static void commRX()
 {
   XBT_INFO("  Start RX");
   try {
-    auto payload = simgrid::s4u::Mailbox::by_name("comm")->get<std::string>();
+    const auto* payload = simgrid::s4u::Mailbox::by_name("comm")->get<std::string>();
     XBT_INFO("  Receive message: %s", payload->c_str());
   } catch (const simgrid::HostFailureException&) {
     XBT_INFO("  Receive message: HOST_FAILURE");
index e3eb658..6977fbc 100644 (file)
@@ -106,8 +106,8 @@ int main(int argc, char** argv)
   auto* bob  = zone->create_host("bob", 1e6);
   auto* alice  = zone->create_host("alice", 1e6);
 
-  sg4::LinkInRoute link(zone->create_link("link", "2MBps")->set_latency("50us")->seal());
-  zone->add_route(bob->get_netpoint(), alice->get_netpoint(), nullptr, nullptr, {link}, true);
+  auto* link = zone->create_link("link", "2MBps")->set_latency("50us");
+  zone->add_route(bob, alice, {link});
 
   bob->create_disk("bob_disk", "1MBps", "500kBps");
   alice->create_disk("alice_disk", "4MBps", "4MBps");
index e3833b2..7983e49 100644 (file)
@@ -9,7 +9,7 @@
 
 static void runner()
 {
-  auto e                    = simgrid::s4u::Engine::get_instance();
+  const auto* e             = simgrid::s4u::Engine::get_instance();
   simgrid::s4u::Host* host0 = e->host_by_name("c1_0");
   simgrid::s4u::Host* host1 = e->host_by_name("c2_0");
 
index 2775b84..4a4fca3 100644 (file)
@@ -9,7 +9,7 @@
  * It is not written to be pleasant to read, but instead to resist the aggressions of the monkey:
  * - Workers keep going until after a global variable `todo` reaches 0.
  * - The master is a daemon that just sends infinitely tasks
- *   (simgrid simulations stop as soon as all non-daemon actors are done).
+ *   (SimGrid simulations stop as soon as all non-daemon actors are done).
  * - The platform is created programmatically to remove path issues and control the problem size.
  *
  * Command-line configuration items:
@@ -114,8 +114,8 @@ int main(int argc, char* argv[])
   for (int i = 1; i < cfg_host_count; i++) {
     auto hostname = "lilibeth " + std::to_string(i);
     auto* host    = rootzone->create_host(hostname, 1e9);
-    sg4::LinkInRoute link(rootzone->create_link(hostname, "1MBps")->set_latency("24us")->seal());
-    rootzone->add_route(master_host->get_netpoint(), host->get_netpoint(), nullptr, nullptr, {link}, true);
+    auto* link    = rootzone->create_link(hostname, "1MBps")->set_latency("24us")->seal();
+    rootzone->add_route(master_host, host, {link});
     worker_hosts.push_back(host);
   }
   rootzone->seal();
index 6db4f0c..863b392 100644 (file)
@@ -10,7 +10,7 @@
  It is not written to be pleasant to read, but instead to resist the aggressions of the monkey:
  - Workers keep going until after a global variable `todo` reaches 0.
  - The master is a daemon that just sends infinitely tasks
-   (simgrid simulations stop as soon as all non-daemon actors are done).
+   (SimGrid simulations stop as soon as all non-daemon actors are done).
  - The platform is created programmatically to remove path issues and control the problem size.
 
  See the simgrid-monkey script for more information.
@@ -92,7 +92,7 @@ if __name__ == '__main__':
   for i in range(1, host_count):
     link = rootzone.create_split_duplex_link(f"link {i}", "1MBps").set_latency("24us")
     host = rootzone.create_host(f"lilibeth {i}", 1e9)
-    rootzone.add_route(main.netpoint, host.netpoint, None, None, [LinkInRoute(link, LinkInRoute.Direction.UP)], True)
+    rootzone.add_route(main, host, [link])
     Actor.create("worker", host, worker, i).set_auto_restart(True)
 
   e.netzone_root.seal()
index 828303a..6e73575 100644 (file)
@@ -116,8 +116,8 @@ int main(int argc, char** argv)
   auto* rootzone = sg4::create_full_zone("root");
   auto* paul     = rootzone->create_host("Paul", 1e9);
   auto* carol    = rootzone->create_host("Carol", 1e9);
-  sg4::LinkInRoute link(rootzone->create_link("link", "1MBps")->set_latency("24us")->seal());
-  rootzone->add_route(paul->get_netpoint(), carol->get_netpoint(), nullptr, nullptr, {link}, true);
+  auto* link     = rootzone->create_link("link", "1MBps")->set_latency("24us")->seal();
+  rootzone->add_route(paul, carol, {link});
 
   SharedBuffer buffer;
   sg4::Actor::create("producer", paul, producer, std::ref(buffer))->set_auto_restart();
index ff4e558..b6f9251 100644 (file)
@@ -3,6 +3,6 @@ p We just want to check that the ns-3 bindings of SimGrid are working correctly,
 
 $ ./ns3-from-src-to-itself ${platfdir}/ns3-big-cluster.xml --cfg=network/model:ns-3 "--log=root.fmt:[%h:%a(%i)]%e[%c/%p]%e%m%n"
 > [:maestro(0)] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'ns-3'
-> [:maestro(0)] [res_ns3/WARNING] Sending from a host c-01.rennes to itself is not supported by ns-3. Every such communication finishes immediately upon startup.
+> [:maestro(0)] [res_ns3/WARNING] Sending from a host c-01.rennes to itself is not supported by ns-3. Every such communication finishes immediately upon startup in the SimGrid+ns-3 system.
 > [c-01.rennes:receiver(1)] [s4u_test/INFO] Done receiving from 2 senders, each of them sending 5 messages
 
index 8d66af5..d32d2d9 100644 (file)
@@ -6,7 +6,7 @@
 #include "simgrid/s4u.hpp"
 namespace sg4 = simgrid::s4u;
 
-XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_torus_multicpu, "Messages specific for this s4u example");
+XBT_LOG_NEW_DEFAULT_CATEGORY(seal_platform, "Messages specific for this s4u example");
 
 class Sender {
   long msg_size = 1e6; /* message size in bytes */
@@ -17,7 +17,7 @@ public:
   void operator()() const
   {
     /* Vector in which we store all ongoing communications */
-    std::vector<sg4::CommPtr> pending_comms;
+    sg4::ActivitySet pending_comms;
     /* Make a vector of the mailboxes to use */
     std::vector<sg4::Mailbox*> mboxes;
 
@@ -25,16 +25,16 @@ public:
     for (const auto* host : hosts_) {
       auto* payload = new std::string(msg_content);
       /* Create a communication representing the ongoing communication, and store it in pending_comms */
-      auto mbox = sg4::Mailbox::by_name(host->get_name());
+      auto* mbox = sg4::Mailbox::by_name(host->get_name());
       mboxes.push_back(mbox);
       sg4::CommPtr comm = mbox->put_async(payload, msg_size);
-      pending_comms.push_back(comm);
+      pending_comms.push(comm);
     }
 
     XBT_INFO("Done dispatching all messages");
 
     /* Now that all message exchanges were initiated, wait for their completion in one single call */
-    sg4::Comm::wait_all(pending_comms);
+    pending_comms.wait_all();
 
     XBT_INFO("Goodbye now!");
   }
@@ -45,7 +45,7 @@ class Receiver {
 public:
   void operator()() const
   {
-    auto mbox     = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
+    auto* mbox    = sg4::Mailbox::by_name(sg4::this_actor::get_host()->get_name());
     auto received = mbox->get_unique<std::string>();
     XBT_INFO("I got a '%s'.", received->c_str());
 
@@ -58,17 +58,16 @@ public:
 /*************************************************************************************************/
 static sg4::NetZone* create_zone(const sg4::NetZone* root, const std::string& id)
 {
-  auto* zone = sg4::create_floyd_zone(id);
-  zone->set_parent(root);
+  auto* zone = sg4::create_star_zone(id)->set_parent(root);
   constexpr int n_host = 2;
 
-  auto* router = zone->create_router("router" + id);
+  zone->set_gateway(zone->create_router("router" + id));
   for (int i = 0; i < n_host; i++) {
     std::string hostname = id + "-cpu-" + std::to_string(i);
     auto* host           = zone->create_host(hostname, 1e9);
     host->create_disk("disk-" + hostname, 1e9, 1e6);
     const auto* link = zone->create_link("link-" + hostname, 1e9);
-    zone->add_route(host->get_netpoint(), router, nullptr, nullptr, {sg4::LinkInRoute(link)});
+    zone->add_route(host, nullptr, {link});
   }
   return zone;
 }
@@ -84,8 +83,7 @@ int main(int argc, char* argv[])
   auto* zoneA = create_zone(root, "A");
   auto* zoneB = create_zone(root, "B");
   const auto* link = root->create_link("root-link", 1e10);
-  root->add_route(zoneA->get_netpoint(), zoneB->get_netpoint(), e.netpoint_by_name("routerA"),
-                  e.netpoint_by_name("routerB"), {sg4::LinkInRoute(link)});
+  root->add_route(zoneA, zoneB, {sg4::LinkInRoute(link)}, true);
 
   std::vector<sg4::Host*> host_list = e.get_all_hosts();
   /* create the sender actor running on first host */
index 11ea6df..187501c 100644 (file)
@@ -1,11 +1,11 @@
 $ ./seal-platform
-> [A-cpu-0:sender:(1) 0.000000] [s4u_torus_multicpu/INFO] Done dispatching all messages
-> [A-cpu-0:receiver-A-cpu-0:(2) 0.000103] [s4u_torus_multicpu/INFO] I got a 'Hello, I'm alive and running on A-cpu-0'.
-> [B-cpu-1:receiver-B-cpu-1:(5) 0.003247] [s4u_torus_multicpu/INFO] I got a 'Hello, I'm alive and running on A-cpu-0'.
-> [B-cpu-0:receiver-B-cpu-0:(4) 0.003247] [s4u_torus_multicpu/INFO] I got a 'Hello, I'm alive and running on A-cpu-0'.
-> [A-cpu-1:receiver-A-cpu-1:(3) 0.003247] [s4u_torus_multicpu/INFO] I got a 'Hello, I'm alive and running on A-cpu-0'.
-> [A-cpu-0:sender:(1) 0.003247] [s4u_torus_multicpu/INFO] Goodbye now!
-> [A-cpu-0:receiver-A-cpu-0:(2) 4.000103] [s4u_torus_multicpu/INFO] Wrote 4000000 bytes on 'disk-A-cpu-0'
-> [B-cpu-1:receiver-B-cpu-1:(5) 4.003247] [s4u_torus_multicpu/INFO] Wrote 4000000 bytes on 'disk-B-cpu-1'
-> [B-cpu-0:receiver-B-cpu-0:(4) 4.003247] [s4u_torus_multicpu/INFO] Wrote 4000000 bytes on 'disk-B-cpu-0'
-> [A-cpu-1:receiver-A-cpu-1:(3) 4.003247] [s4u_torus_multicpu/INFO] Wrote 4000000 bytes on 'disk-A-cpu-1'
+> [A-cpu-0:sender:(1) 0.000000] [seal_platform/INFO] Done dispatching all messages
+> [B-cpu-1:receiver-B-cpu-1:(5) 0.004330] [seal_platform/INFO] I got a 'Hello, I'm alive and running on A-cpu-0'.
+> [B-cpu-0:receiver-B-cpu-0:(4) 0.004330] [seal_platform/INFO] I got a 'Hello, I'm alive and running on A-cpu-0'.
+> [A-cpu-1:receiver-A-cpu-1:(3) 0.004330] [seal_platform/INFO] I got a 'Hello, I'm alive and running on A-cpu-0'.
+> [A-cpu-0:receiver-A-cpu-0:(2) 0.004330] [seal_platform/INFO] I got a 'Hello, I'm alive and running on A-cpu-0'.
+> [A-cpu-0:sender:(1) 0.004330] [seal_platform/INFO] Goodbye now!
+> [B-cpu-1:receiver-B-cpu-1:(5) 4.004330] [seal_platform/INFO] Wrote 4000000 bytes on 'disk-B-cpu-1'
+> [B-cpu-0:receiver-B-cpu-0:(4) 4.004330] [seal_platform/INFO] Wrote 4000000 bytes on 'disk-B-cpu-0'
+> [A-cpu-1:receiver-A-cpu-1:(3) 4.004330] [seal_platform/INFO] Wrote 4000000 bytes on 'disk-A-cpu-1'
+> [A-cpu-0:receiver-A-cpu-0:(2) 4.004330] [seal_platform/INFO] Wrote 4000000 bytes on 'disk-A-cpu-0'
\ No newline at end of file
index 9439fc2..8170ff0 100644 (file)
@@ -76,18 +76,17 @@ static void get_set_disk_data(simgrid::s4u::Disk* disk)
 {
   XBT_INFO("*** GET/SET DATA for disk: %s ***", disk->get_cname());
 
-  const std::string* data = disk->get_data<std::string>();
+  auto data = disk->get_unique_data<std::string>();
   XBT_INFO("Get data: '%s'", data ? data->c_str() : "No User Data");
   disk->set_data(new std::string("Some data"));
-  data = disk->get_data<std::string>();
+  data = disk->get_unique_data<std::string>();
   XBT_INFO("  Set and get data: '%s'", data->c_str());
-  delete data;
 }
 
 static void dump_platform_disks()
 {
-  for (auto const& h : simgrid::s4u::Engine::get_instance()->get_all_hosts())
-    for (auto const& d : h->get_disks()) {
+  for (auto const* h : simgrid::s4u::Engine::get_instance()->get_all_hosts())
+    for (auto* d : h->get_disks()) {
       if (h == d->get_host())
         XBT_INFO("%s is attached to %s", d->get_cname(), d->get_host()->get_cname());
       d->set_property("other usage", "gpfs");
@@ -98,7 +97,7 @@ static void disk_info(const simgrid::s4u::Host* host)
 {
   XBT_INFO("*** Disk info on %s ***", host->get_cname());
 
-  for (auto const& disk : host->get_disks()) {
+  for (auto const* disk : host->get_disks()) {
     const char* mount_name = sg_disk_get_mount_point(disk);
     XBT_INFO("  Disk name: %s, mount name: %s", disk->get_cname(), mount_name);
 
index 733d9a5..69cdf86 100644 (file)
@@ -27,14 +27,14 @@ static void print_status(const std::vector<simgrid::s4u::Host*>& hosts)
 {
   XBT_INFO("---- HOSTS and VMS STATUS ----");
   XBT_INFO("--- HOSTS ---");
-  for (auto const& host : hosts) {
+  for (auto const* host : hosts) {
     XBT_INFO("+ Name:%s Load:%f", host->get_cname(), host->get_load());
     for (auto const& actor : host->get_all_actors())
       XBT_INFO("++ actor: %s", actor->get_cname());
   }
   XBT_INFO("--- VMS ---");
-  for (auto const& host : simgrid::s4u::Engine::get_instance()->get_all_hosts()) {
-    if (auto vm = dynamic_cast<simgrid::s4u::VirtualMachine*>(host)) {
+  for (auto const* host : simgrid::s4u::Engine::get_instance()->get_all_hosts()) {
+    if (auto const* vm = dynamic_cast<const simgrid::s4u::VirtualMachine*>(host)) {
       XBT_INFO("+ Name:%s Host:%s Load:%f State: %s", vm->get_cname(), vm->get_pm()->get_cname(), vm->get_load(),
                simgrid::s4u::VirtualMachine::to_c_str(vm->get_state()));
       for (auto const& actor : host->get_all_actors())
diff --git a/teshsuite/s4u/wait-all-for/wait-all-for.cpp b/teshsuite/s4u/wait-all-for/wait-all-for.cpp
deleted file mode 100644 (file)
index ea4efa1..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (c) 2019-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <cstdlib>
-#include <iostream>
-#include <simgrid/s4u.hpp>
-#include <string>
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(meh, "meh");
-
-static void worker()
-{
-  auto mbox  = simgrid::s4u::Mailbox::by_name("meh");
-  int input1 = 42;
-  int input2 = 51;
-
-  XBT_INFO("Sending and receiving %d and %d asynchronously", input1, input2);
-
-  auto put1 = mbox->put_async(&input1, 1000 * 1000 * 500);
-  auto put2 = mbox->put_async(&input2, 1000 * 1000 * 1000);
-
-  int* out1;
-  auto get1 = mbox->get_async<int>(&out1);
-
-  int* out2;
-  auto get2 = mbox->get_async<int>(&out2);
-
-  XBT_INFO("All comms have started");
-  std::vector<simgrid::s4u::CommPtr> comms = {put1, put2, get1, get2};
-
-  while (not comms.empty()) {
-    size_t index = simgrid::s4u::Comm::wait_all_for(comms, 0.5);
-    if (index < comms.size())
-      XBT_INFO("wait_all_for: Timeout reached");
-    XBT_INFO("wait_all_for: %zu comms finished (#comms=%zu)", index, comms.size());
-    comms.erase(comms.begin(), comms.begin() + index);
-  }
-
-  XBT_INFO("All comms have finished");
-  XBT_INFO("Got %d and %d", *out1, *out2);
-}
-
-int main(int argc, char* argv[])
-
-{
-  simgrid::s4u::Engine e(&argc, argv);
-  e.load_platform(argv[1]);
-  simgrid::s4u::Actor::create("worker", e.host_by_name("Tremblay"), worker);
-  e.run();
-  return 0;
-}
diff --git a/teshsuite/s4u/wait-all-for/wait-all-for.tesh b/teshsuite/s4u/wait-all-for/wait-all-for.tesh
deleted file mode 100644 (file)
index c7b30a9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env tesh
-
-p Testing the wait_all_for feature of S4U
-
-! output sort 19
-$ ${bindir:=.}/wait-all-for ${platfdir:=.}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (1:worker@Tremblay) Sending and receiving 42 and 51 asynchronously
-> [  0.000000] (1:worker@Tremblay) All comms have started
-> [  0.500000] (1:worker@Tremblay) wait_all_for: Timeout reached
-> [  0.500000] (1:worker@Tremblay) wait_all_for: 0 comms finished (#comms=4)
-> [  1.000000] (1:worker@Tremblay) wait_all_for: Timeout reached
-> [  1.000000] (1:worker@Tremblay) wait_all_for: 0 comms finished (#comms=4)
-> [  1.500000] (1:worker@Tremblay) wait_all_for: Timeout reached
-> [  1.500000] (1:worker@Tremblay) wait_all_for: 1 comms finished (#comms=4)
-> [  2.000000] (1:worker@Tremblay) wait_all_for: Timeout reached
-> [  2.000000] (1:worker@Tremblay) wait_all_for: 0 comms finished (#comms=3)
-> [  2.070331] (1:worker@Tremblay) wait_all_for: 3 comms finished (#comms=3)
-> [  2.070331] (1:worker@Tremblay) All comms have finished
-> [  2.070331] (1:worker@Tremblay) Got 42 and 51
diff --git a/teshsuite/s4u/wait-any-for/wait-any-for.cpp b/teshsuite/s4u/wait-any-for/wait-any-for.cpp
deleted file mode 100644 (file)
index c7b689b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (c) 2019-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include <cstdlib>
-#include <iostream>
-#include <string>
-#include <simgrid/s4u.hpp>
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(meh, "meh");
-
-static void worker()
-{
-  auto mbox = simgrid::s4u::Mailbox::by_name("meh");
-  int input1 = 42;
-  int input2 = 51;
-
-  XBT_INFO("Sending and receiving %d and %d asynchronously", input1, input2);
-
-  auto put1 = mbox->put_async(&input1, 1000 * 1000 * 500);
-  auto put2 = mbox->put_async(&input2, 1000 * 1000 * 1000);
-
-  int* out1;
-  auto get1 = mbox->get_async<int>(&out1);
-
-  int* out2;
-  auto get2 = mbox->get_async<int>(&out2);
-
-  XBT_INFO("All comms have started");
-  std::vector<simgrid::s4u::CommPtr> comms = {put1, put2, get1, get2};
-
-  while (not comms.empty()) {
-    ssize_t index = simgrid::s4u::Comm::wait_any_for(comms, 0.5);
-    if (index < 0)
-      XBT_INFO("wait_any_for: Timeout reached");
-    else {
-      XBT_INFO("wait_any_for: A comm finished (index=%zd, #comms=%zu)", index, comms.size());
-      comms.erase(comms.begin() + index);
-    }
-  }
-
-  XBT_INFO("All comms have finished");
-  XBT_INFO("Got %d and %d", *out1, *out2);
-}
-
-int main(int argc, char* argv[])
-
-{
-  simgrid::s4u::Engine e(&argc, argv);
-  e.load_platform(argv[1]);
-  simgrid::s4u::Actor::create("worker", e.host_by_name("Tremblay"), worker);
-  e.run();
-  return 0;
-}
diff --git a/teshsuite/s4u/wait-any-for/wait-any-for.tesh b/teshsuite/s4u/wait-any-for/wait-any-for.tesh
deleted file mode 100644 (file)
index 87ae347..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env tesh
-
-p Testing the wait_any_for feature of S4U
-
-! output sort 19
-$ ${bindir:=.}/wait-any-for ${platfdir:=.}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
-> [  0.000000] (1:worker@Tremblay) Sending and receiving 42 and 51 asynchronously
-> [  0.000000] (1:worker@Tremblay) All comms have started
-> [  0.500000] (1:worker@Tremblay) wait_any_for: Timeout reached
-> [  1.000000] (1:worker@Tremblay) wait_any_for: Timeout reached
-> [  1.035263] (1:worker@Tremblay) wait_any_for: A comm finished (index=0, #comms=4)
-> [  1.035263] (1:worker@Tremblay) wait_any_for: A comm finished (index=1, #comms=3)
-> [  1.535263] (1:worker@Tremblay) wait_any_for: Timeout reached
-> [  2.035263] (1:worker@Tremblay) wait_any_for: Timeout reached
-> [  2.070331] (1:worker@Tremblay) wait_any_for: A comm finished (index=0, #comms=2)
-> [  2.070331] (1:worker@Tremblay) wait_any_for: A comm finished (index=0, #comms=1)
-> [  2.070331] (1:worker@Tremblay) All comms have finished
-> [  2.070331] (1:worker@Tremblay) Got 42 and 51
index be77453..25b8ce3 100644 (file)
@@ -57,6 +57,8 @@ set(bin_files       ${bin_files}    ${CMAKE_CURRENT_SOURCE_DIR}/hostfile
 
 
 if(enable_smpi)
+  ADD_TEST(test-smpi-help-coll ${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -wrapper "${VALGRIND_WRAPPER_NO_LEAK_CHECK}" --help-coll)
+
   ADD_TESH_FACTORIES(tesh-smpi-macro-shared "*" --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/smpi/macro-shared --cd ${CMAKE_BINARY_DIR}/teshsuite/smpi/macro-shared ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/macro-shared/macro-shared.tesh)
   ADD_TESH_FACTORIES(tesh-smpi-auto-shared "*" --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/smpi/auto-shared --cd ${CMAKE_BINARY_DIR}/teshsuite/smpi/auto-shared ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/auto-shared/auto-shared.tesh)
   ADD_TESH_FACTORIES(tesh-smpi-macro-partial-shared "*" --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/smpi/macro-partial-shared --cd ${CMAKE_BINARY_DIR}/teshsuite/smpi/macro-partial-shared ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/macro-partial-shared/macro-partial-shared.tesh)
@@ -141,7 +143,7 @@ if(enable_smpi)
   if (NOT HAVE_SANITIZER_ADDRESS)
     ADD_TESH(tesh-smpi-coll-allreduce-with-leaks --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/smpi/coll-allreduce-with-leaks --cd ${CMAKE_BINARY_DIR}/teshsuite/smpi/coll-allreduce-with-leaks ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/coll-allreduce-with-leaks/coll-allreduce-with-leaks.tesh)
     set_target_properties(coll-allreduce-with-leaks PROPERTIES COMPILE_FLAGS "-trace-call-location")
-    if(enable_model-checking)
+    if(SIMGRID_HAVE_MC)
       add_dependencies(tests-mc coll-allreduce-with-leaks)
       ADD_TESH(tesh-mc-smpi-coll-allreduce-with-leaks --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/smpi/coll-allreduce-with-leaks --cd ${CMAKE_BINARY_DIR}/teshsuite/smpi/coll-allreduce-with-leaks ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/coll-allreduce-with-leaks/mc-coll-allreduce-with-leaks.tesh)
     endif()
index a07c97c..9ea75ba 100644 (file)
@@ -7,12 +7,12 @@
 
 file(GLOB generator_scripts *Generator.py)
 
-if (enable_smpi_MBI_testsuite)
+if (enable_testsuite_smpi_MBI)
   if (NOT enable_smpi)
-    message(FATAL_ERROR "MBI test suite cannot be enabled without SMPI. Please change either setting.")
+    message(FATAL_ERROR "The MBI test suite cannot be enabled without SMPI. Please change either setting.")
   endif()
-  if (NOT enable_model-checking)
-    message(FATAL_ERROR "MBI test suite cannot be enabled without the Mc SimGrid model-checker. Please change either setting.")
+  if (NOT SIMGRID_HAVE_MC)
+    message(FATAL_ERROR "The MBI test suite cannot be enabled without the model-checker. Please change either setting.")
   endif()
 
   message(STATUS "Generating the MBI test cases")
@@ -38,7 +38,7 @@ if (enable_smpi_MBI_testsuite)
   add_dependencies(tests tests-mbi)
   add_dependencies(tests-mbi simgrid-mc smpimain)
 
-  # Remove Concurrency tests that are out of reach because simgrid does not intercept local modifications yet
+  # Remove Concurrency tests that are out of reach because SimGrid does not intercept local modifications yet
   # An idea could be to use ASan on the verified application, along with https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning
   # But currently, ASan is not usable at all, since the Checker dislikes this trick when it tries to read the memory of the app.
   # We should change the checker to not read the app when verifying safty properties
@@ -64,6 +64,7 @@ if (enable_smpi_MBI_testsuite)
     add_executable(mbi_${basefile} EXCLUDE_FROM_ALL ${CMAKE_BINARY_DIR}/MBI/${cfile})
     target_link_libraries(mbi_${basefile} simgrid)
     target_compile_options(mbi_${basefile} PRIVATE "-Wno-unused-variable")
+    target_compile_options(mbi_${basefile} PRIVATE "-Wno-unused-but-set-variable")
     set_target_properties(mbi_${basefile} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/MBI)
     add_dependencies(tests-mbi mbi_${basefile})
 
index 899e810..d9f8a51 100755 (executable)
@@ -26,11 +26,11 @@ END_MPI_FEATURES
 
 BEGIN_MBI_TESTS
   $ mpirun -np 2 ${EXE} 1
-  | @{outcome}@
-  | @{errormsg}@
+  | @{outcome1}@
+  | @{errormsg1}@
   $ mpirun -np 2 ${EXE} 2
-  | @{outcome}@
-  | @{errormsg}@
+  | @{outcome2}@
+  | @{errormsg2}@
 END_MBI_TESTS
 //////////////////////       End of MBI headers        /////////////////// */
 
@@ -127,16 +127,20 @@ for s in gen.send + gen.isend:
         replace = patterns.copy()
         replace['shortdesc'] = 'Correct call ordering.'
         replace['longdesc'] = 'Correct call ordering.'
-        replace['outcome'] = 'OK'
-        replace['errormsg'] = 'OK'
+        replace['outcome1'] = 'OK'
+        replace['errormsg1'] = 'OK'
+        replace['outcome2'] = 'OK'
+        replace['errormsg2'] = 'OK'
         gen.make_file(template, f'InputHazardCallOrdering_{r}_{s}_ok.c', replace)
 
         # Generate the incorrect matching
         replace = patterns.copy()
         replace['shortdesc'] = 'Missing Send function.'
         replace['longdesc'] = 'Missing Send function call for a path depending to input, a deadlock is created.'
-        replace['outcome'] = 'ERROR: IHCallMatching'
-        replace['errormsg'] = 'P2P mistmatch. Missing @{r}@ at @{filename}@:@{line:MBIERROR}@.'
+        replace['outcome1'] = 'OK'
+        replace['errormsg1'] = 'OK'
+        replace['outcome2'] = 'ERROR: IHCallMatching'
+        replace['errormsg2'] = 'P2P mistmatch. Missing @{r}@ at @{filename}@:@{line:MBIERROR}@.'
         replace['errorcond'] = '/* MBIERROR */'
         replace['operation1b'] = ''
         replace['fini1b'] = ''
@@ -172,16 +176,20 @@ for c in gen.coll:
     replace = patterns.copy()
     replace['shortdesc'] = 'Correct call ordering.'
     replace['longdesc'] = 'Correct call ordering.'
-    replace['outcome'] = 'OK'
-    replace['errormsg'] = 'OK'
+    replace['outcome1'] = 'OK'
+    replace['errormsg1'] = 'OK'
+    replace['outcome2'] = 'OK'
+    replace['errormsg2'] = 'OK'
     gen.make_file(template, f'InputHazardCallOrdering_{c}_ok.c', replace)
 
     # Generate the incorrect matching
     replace = patterns.copy()
     replace['shortdesc'] = 'Missing collective function call.'
     replace['longdesc'] = 'Missing collective function call for a path depending to input, a deadlock is created.'
-    replace['outcome'] = 'ERROR: IHCallMatching'
-    replace['errormsg'] = 'P2P mistmatch. Missing @{c}@ at @{filename}@:@{line:MBIERROR}@.'
+    replace['outcome1'] = 'OK'
+    replace['errormsg1'] = 'OK'
+    replace['outcome2'] = 'ERROR: IHCallMatching'
+    replace['errormsg2'] = 'P2P mistmatch. Missing @{c}@ at @{filename}@:@{line:MBIERROR}@.'
     replace['errorcond'] = '/* MBIERROR */'
     replace['operation1b'] = ''
     replace['fini1b'] = ''
index 6bd48c6..6484a0b 100755 (executable)
@@ -30,7 +30,7 @@ simgrid = sg.Tool()
 
 (name, path, binary, filename) = sys.argv
 for test in mbi.parse_one_code(filename):
-    execcmd = test['cmd'].replace("mpirun", f"{path}/smpi_script/bin/smpirun -wrapper '{path}/bin/simgrid-mc --log=mc_safety.t:info' -platform ./cluster.xml -analyze --cfg=smpi/barrier-finalization:on --cfg=smpi/list-leaks:10 --cfg=model-check/max-depth:10000")
+    execcmd = test['cmd'].replace("mpirun", f"{path}/smpi_script/bin/smpirun -wrapper '{path}/bin/simgrid-mc --cfg=model-check/reduction:odpor --log=mc_safety.t:info' -platform ./cluster.xml -analyze --cfg=smpi/barrier-finalization:on --cfg=smpi/list-leaks:10 --cfg=model-check/max-depth:10000")
     execcmd = execcmd.replace('${EXE}', binary)
     execcmd = execcmd.replace('$zero_buffer', "--cfg=smpi/buffering:zero")
     execcmd = execcmd.replace('$infty_buffer', "--cfg=smpi/buffering:infty")
index c422cca..9a7d837 100644 (file)
@@ -67,6 +67,9 @@ possible_details = {
     'GlobalConcurrency':'DGlobalConcurrency',
     # larger scope
     'BufferingHazard':'EBufferingHazard',
+    # Input Hazard
+    'IHCallMatching':'InputHazard',
+    
     'OK':'FOK'}
 
 error_scope = {
index 05253b8..663a548 100755 (executable)
@@ -25,11 +25,11 @@ END_MPI_FEATURES
 
 BEGIN_MBI_TESTS
   $ mpirun -np 4 $zero_buffer ${EXE}
-  | @{outcome1}@
-  | @{errormsg1}@
+  | @{outcome_zerob}@
+  | @{errormsg_zerob}@
   $ mpirun -np 4 $infty_buffer ${EXE}
-  | @{outcome1}@
-  | @{errormsg1}@
+  | @{outcome_infty}@
+  | @{errormsg_infty}@
 END_MBI_TESTS
 //////////////////////       End of MBI headers        /////////////////// */
 
@@ -123,8 +123,10 @@ for s in gen.send + gen.isend:
         replace = patterns.copy()
         replace['shortdesc'] = 'Point to point @{s}@ and @{r}@ may not be matched'
         replace['longdesc'] = 'Processes 0 and 1 both call @{s}@ and @{r}@. This results in a deadlock depending on the buffering mode'
-        replace['outcome1'] = 'ERROR: BufferingHazard'
-        replace['errormsg1'] = f'Buffering Hazard. Possible deadlock depending the buffer size of MPI implementation and system environment cause by two processes call {s} before {r}.'
+        replace['outcome_zerob'] = 'ERROR: BufferingHazard'
+        replace['errormsg_zerob'] = f'Buffering Hazard. Possible deadlock depending the buffer size of MPI implementation and system environment cause by two processes call {s} before {r}.'
+        replace['outcome_infty'] = 'OK'
+        replace['errormsg_infty'] = 'OK'
         gen.make_file(template, f'P2PBuffering_{s}_{r}_{s}_{r}_nok.c', replace)
 
         # Generate the incorrect matching with send message to the same process depending on the buffering mode (send + recv)
@@ -136,8 +138,10 @@ for s in gen.send + gen.isend:
         replace['dest2'] = '1'
         replace['shortdesc'] = 'Point to point @{s}@ and @{r}@ may not be matched'
         replace['longdesc'] = 'Processes 0 and 1 both call @{s}@ and @{r}@. This results in a deadlock depending on the buffering mode'
-        replace['outcome1'] = 'ERROR: BufferingHazard'
-        replace['errormsg1'] = f'Buffering Hazard. Possible deadlock depending the buffer size of MPI implementation and system environment cause Send message to the same process.'
+        replace['outcome_zerob'] = 'ERROR: BufferingHazard'
+        replace['errormsg_zerob'] = f'Buffering Hazard. Possible deadlock depending the buffer size of MPI implementation and system environment cause Send message to the same process.'
+        replace['outcome_infty'] = 'OK'
+        replace['errormsg_infty'] = 'OK'
         gen.make_file(template, f'P2PBuffering_SameProcess_{s}_{r}_nok.c', replace)
 
         # Generate the incorrect matching with circular send message depending on the buffering mode (send + recv)
@@ -155,16 +159,20 @@ for s in gen.send + gen.isend:
         replace['operation2c'] = gen.operation[r]("2")
         replace['shortdesc'] = 'Point to point @{s}@ and @{r}@ may not be matched'
         replace['longdesc'] = 'Processes 0 and 1 both call @{s}@ and @{r}@. This results in a deadlock depending on the buffering mode'
-        replace['outcome1'] = 'ERROR: BufferingHazard'
-        replace['errormsg1'] = f'Buffering Hazard. Possible deadlock depending the buffer size of MPI implementation and system environment cause circular send message.'
+        replace['outcome_zerob'] = 'ERROR: BufferingHazard'
+        replace['errormsg_zerob'] = f'Buffering Hazard. Possible deadlock depending the buffer size of MPI implementation and system environment cause circular send message.'
+        replace['outcome_infty'] = 'OK'
+        replace['errormsg_infty'] = 'OK'
         gen.make_file(template, f'P2PBuffering_Circular_{s}_{r}_nok.c', replace)
 
         # Generate the incorrect matching depending on the buffering mode (recv + send)
         replace = patterns.copy()
         replace['shortdesc'] = 'Point to point @{s}@ and @{r}@ are not matched'
         replace['longdesc'] = 'Processes 0 and 1 both call @{r}@ and @{s}@. This results in a deadlock'
-        replace['outcome1'] = 'ERROR: CallMatching'
-        replace['errormsg1'] = 'ERROR: CallMatching'
+        replace['outcome_zerob'] = 'ERROR: CallMatching'
+        replace['errormsg_zerob'] = 'ERROR: CallMatching'
+        replace['outcome_infty'] = 'ERROR: CallMatching'
+        replace['errormsg_infty'] = 'ERROR: CallMatching'
         replace['operation1a'] = gen.operation[r]("2")
         replace['fini1a'] = gen.fini[r]("2")
         replace['operation2a'] = gen.operation[s]("1")
@@ -179,10 +187,19 @@ for s in gen.send + gen.isend:
         replace = patterns.copy()
         replace['shortdesc'] = 'Point to point @{s}@ and @{r}@ are correctly  matched'
         replace['longdesc'] = 'Process 0 calls @{s}@ and process 1 calls @{r}@.'
-        replace['outcome1'] = 'OK'
-        replace['errormsg1'] = 'OK'
-        replace['fini1a'] = gen.fini[s]("1")
-        replace['fini2a'] = gen.fini[r]("2")
+        replace['outcome_zerob'] = 'OK'
+        replace['errormsg_zerob'] = 'OK'
+        replace['outcome_infty'] = 'OK'
+        replace['errormsg_infty'] = 'OK'
+        patterns['init1'] = gen.init[s]("1")
         replace['operation1a'] = gen.operation[s]("1")
-        replace['operation2a'] = gen.operation[r]("2")
+        replace['fini1a'] = gen.fini[s]("1")
+        replace['operation2a'] = ''
+        replace['fini2a'] = ''
+        
+        patterns['init2'] = gen.init[r]("2")
+        replace['operation1b'] = gen.operation[r]("2")
+        replace['fini1b'] = gen.fini[r]("2")
+        replace['operation2b'] = ''
+        replace['fini2b'] = ''
         gen.make_file(template, f'P2PCallMatching_{s}_{r}_{r}_{s}_ok.c', replace)
index 8ed991f..ef6fb16 100644 (file)
@@ -126,7 +126,7 @@ for s in gen.send:
             # Generate a code with non distinct buffer
             replace = patterns.copy()
             replace['shortdesc'] = 'Invalid buffer on Sendrecv function.'
-            replace['longdesc'] = 'Invalid buffer on Sendrecv, the tow buffers must be distinct.'
+            replace['longdesc'] = 'Invalid buffer on Sendrecv, the two buffers must be distinct.'
             replace['outcome'] = 'ERROR: InvalidBuffer'
             replace['errormsg'] = '@{sr}@ at @{filename}@:@{line:MBIERROR}@ send buffer and recv buffer must be distinct.'
             replace['change_arg'] = gen.write[sr]("2")
index 3801ae2..af5750b 100644 (file)
@@ -358,7 +358,7 @@ start['MPI_Sendrecv'] = lambda n: ""
 operation['MPI_Sendrecv'] = lambda n: f'MPI_Sendrecv(psbuf{n}, buff_size, type, dest, stag, prbuf{n}, buff_size, type, src, rtag, newcom, &sta{n});'
 fini['MPI_Sendrecv'] = lambda n: ""
 free['MPI_Sendrecv'] = lambda n: ""
-write['MPI_Sendrecv'] = lambda n: f"prbuf{n} = &sbuf{n}[2];"
+write['MPI_Sendrecv'] = lambda n: f"prbuf{n} = &sbuf{n}[0];"
 
 
 ### P2P:nonblocking
index 3c1ca88..907abc8 100644 (file)
@@ -55,7 +55,7 @@ class Tool(mbi.AbstractTool):
         execcmd = execcmd.replace('$infty_buffer', "--cfg=smpi/buffering:infty")
 
         mbi.run_cmd(
-            buildcmd=f"smpicc {filename} -trace-call-location -g -Wl,-znorelro -Wl,-znoseparate-code -o {binary}",
+            buildcmd=f"smpicc {filename} -trace-call-location -g -o {binary}",
             execcmd=execcmd,
             cachefile=cachefile,
             filename=filename,
index 002689b..ecdacc4 100644 (file)
@@ -1,7 +1,7 @@
 # Smpi Allreduce collectives tests
 
 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 --cfg=model-check/sleep-set:true -np 4 --log=xbt_cfg.thres:critical ${bindir:=.}/coll-allreduce-with-leaks --log=smpi_config.thres:warning --cfg=smpi/display-allocs:yes --cfg=smpi/simulate-computation:no --log=smpi_coll.thres:error --log=smpi_mpi.thres:error --cfg=smpi/list-leaks:10 --log=no_loc
+$ $VALGRIND_NO_LEAK_CHECK ${bindir:=.}/../../../smpi_script/bin/smpirun -wrapper "${bindir:=.}/../../../bin/simgrid-mc" -map -hostfile ../hostfile_coll -platform  ${platfdir:=.}/small_platform.xml -np 4 --log=xbt_cfg.thres:critical ${bindir:=.}/coll-allreduce-with-leaks --log=smpi_config.thres:warning --cfg=smpi/display-allocs:yes --cfg=smpi/simulate-computation:no --log=smpi_coll.thres:error --log=smpi_mpi.thres:error --cfg=smpi/list-leaks:10 --log=no_loc
 > [0.000000] [smpi/INFO] [rank 0] -> Tremblay
 > [0.000000] [smpi/INFO] [rank 1] -> Tremblay
 > [0.000000] [smpi/INFO] [rank 2] -> Tremblay
@@ -73,334 +73,4 @@ $ $VALGRIND_NO_LEAK_CHECK ${bindir:=.}/../../../smpi_script/bin/smpirun -wrapper
 > If this is too much, consider sharing allocations for computation buffers.
 > This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
 > 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed MPI handles:
-> [0.000000] [smpi_utils/WARNING] To get more information (location of allocations), compile your code with -trace-call-location flag of smpicc/f90
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Comm
-> [0.000000] [smpi_utils/INFO] 4 leaked handles of type MPI_Group
-> [0.000000] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 8 unfreed buffers:
-> [0.000000] [smpi_utils/INFO] leaked allocations of total size 152, called 8 times, with minimum size 16 and maximum size 28
-> [0.000000] [smpi_utils/INFO] Memory Usage: Simulated application allocated 152 bytes during its lifetime through malloc/calloc calls.
-> Largest allocation at once from a single process was 28 bytes, at coll-allreduce-with-leaks.c:28. It was called 1 times during the whole simulation.
-> If this is too much, consider sharing allocations for computation buffers.
-> This can be done automatically by setting --cfg=smpi/auto-shared-malloc-thresh to the minimum size wanted size (this can alter execution if data content is necessary)
-> 
-> [0.000000] [mc_dfs/INFO] DFS exploration ended. 616 unique states visited; 167 backtracks (3773 transition replays, 2991 states visited overall)
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 211 unique states visited; 50 backtracks (837 transition replays, 1098 states visited overall)
index d47dba9..0992475 100644 (file)
@@ -1,7 +1,7 @@
 # Smpi Allreduce collectives tests
 ! output sort
 
-p Test allreduce with papi events activated - needs papi installed, simgrid compiled with it, and sudo or sudo sh -c "echo 0 > /proc/sys/kernel/perf_event_paranoid"
+p Test allreduce with papi events activated - needs papi installed, SimGrid compiled with it, and sudo or sudo sh -c "echo 0 > /proc/sys/kernel/perf_event_paranoid"
 $ ${bindir:=.}/../../../smpi_script/bin/smpirun -map -hostfile ../hostfile_coll -platform ${platfdir:=.}/small_platform.xml -np 16 -trace --log=xbt_cfg.thres:critical ${bindir:=.}/coll-allreduce --log=smpi_config.thres:warning --log=smpi_coll.thres:error --log=smpi_mpi.thres:error --log=smpi_pmpi.thres:error --cfg=smpi/papi-events:default:PAPI_L1_TCM:PAPI_TOT_CYC
 > [0.000000] [smpi/INFO] [rank 0] -> Tremblay
 > [0.000000] [smpi/INFO] [rank 1] -> Tremblay
index f355696..8d021ea 100644 (file)
@@ -38,7 +38,7 @@ set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
 include_directories("${CMAKE_HOME_DIRECTORY}/include/smpi")
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/")
 
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   if(HAVE_PRIVATIZATION)
     add_library(mtest_c STATIC util/dtypes.c util/mtest.c  util/mtestcheck.c  util/mtest_datatype.c util/mtest_datatype_gen.c)
   else()
@@ -46,7 +46,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endif()
 endif()
 
-IF(enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+IF(enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   ADD_TEST(test-smpi-mpich3-thread-f77     ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/f77/ ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/f77/ -tests=testlist -privatization=${HAVE_PRIVATIZATION} -execarg=--cfg=contexts/stack-size:8000 -execarg=--cfg=contexts/factory:thread -execarg=--cfg=smpi/privatization:${HAVE_PRIVATIZATION})
   SET_TESTS_PROPERTIES(test-smpi-mpich3-thread-f77 PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
   ADD_TEST(test-smpi-mpich3-thread-f90     ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/f90/ ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/f90/ -tests=testlist -privatization=${HAVE_PRIVATIZATION} -execarg=--cfg=smpi/privatization:${HAVE_PRIVATIZATION} -execarg=--cfg=contexts/factory:thread)
index acdfd5d..c8b178d 100644 (file)
@@ -1,11 +1,11 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
   include_directories(BEFORE "${CMAKE_HOME_DIRECTORY}/include/smpi")
   include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include/")
 
-  foreach(file attr2type attrdeleteget attrend2 attrend attrerr attrerrcomm attrerrtype attrorder attrordercomm attrordertype attrt
+  foreach(file attr2type attrdelete attrdeleteget attrend2 attrend attrerr attrerrcomm attrerrtype attrorder attrordercomm attrordertype attrt
           baseattr2 baseattrcomm fkeyval fkeyvalcomm fkeyvaltype keyval_double_free) #attric
     add_executable(${file} EXCLUDE_FROM_ALL ${file}.c)
     add_dependencies(tests ${file})
@@ -13,12 +13,12 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endforeach()
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-attr-raw       ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/attr ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/attr -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-attr-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
 
-foreach(file attr2type attrdeleteget attrend2 attrend attrerr attrerrcomm attrerrtype attrorder attrordercomm attrordertype attrt
+foreach(file attr2type attrdelete attrdeleteget attrend2 attrend attrerr attrerrcomm attrerrtype attrorder attrordercomm attrordertype attrt
         baseattr2 baseattrcomm fkeyval attric fkeyvalcomm fkeyvaltype keyval_double_free keyval_double_free_comm keyval_double_free_type keyval_double_free_win)
   set(examples_src  ${examples_src} ${CMAKE_CURRENT_SOURCE_DIR}/${file}.c)
 endforeach()
diff --git a/teshsuite/smpi/mpich3-test/attr/attrdelete.c b/teshsuite/smpi/mpich3-test/attr/attrdelete.c
new file mode 100644 (file)
index 0000000..05f03e9
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) by Argonne National Laboratory
+ *     See COPYRIGHT in top-level directory
+ */
+
+/*
+  Having attr delete function to delete another attribute.
+ */
+#include "mpi.h"
+#include "mpitest.h"
+#include <stdio.h>
+
+int key1, key2, key3;
+
+int test_communicator(MPI_Comm comm);
+
+int main(int argc, char **argv)
+{
+    int errs;
+    MTest_Init(&argc, &argv);
+    errs = test_communicator(MPI_COMM_WORLD);
+    MTest_Finalize(errs);
+    return MTestReturnValue(errs);
+}
+
+static int key2_delete_fn(MPI_Comm comm, int keyval, void *attribute_val, void *extra_state)
+{
+    MPI_Comm_delete_attr(comm, key1);
+    MPI_Comm_delete_attr(comm, key3);
+    return MPI_SUCCESS;
+}
+
+int test_communicator(MPI_Comm comm)
+{
+    int errs = 0;
+    int rank, size;
+
+    MPI_Comm_rank(comm, &rank);
+    MPI_Comm_size(comm, &size);
+
+    MPI_Comm_create_keyval(MPI_NULL_COPY_FN, MPI_NULL_DELETE_FN, &key1, NULL);
+    MPI_Comm_create_keyval(MPI_NULL_COPY_FN, key2_delete_fn, &key2, NULL);
+    MPI_Comm_create_keyval(MPI_NULL_COPY_FN, MPI_NULL_DELETE_FN, &key3, NULL);
+
+    MPI_Comm_set_attr(comm, key1, (void *) (MPI_Aint) rank);
+    MPI_Comm_set_attr(comm, key2, (void *) (MPI_Aint) (rank + 100));
+    MPI_Comm_set_attr(comm, key3, (void *) (MPI_Aint) (rank + 200));
+
+    MPI_Comm_delete_attr(comm, key2);
+
+    MPI_Comm_free_keyval(&key1);
+    MPI_Comm_free_keyval(&key2);
+    MPI_Comm_free_keyval(&key3);
+
+    return errs;
+}
index 56fb8c5..e8577c6 100644 (file)
@@ -13,6 +13,7 @@ attrerr 1
 #attrend2 5
 attrerrcomm 1
 attrerrtype 1
+attrdelete 1
 attrdeleteget 1
 attr2type 1
 attrorder 1
index 6c4a1a7..6b23c01 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
   # There are too many warnings with these programs
@@ -8,10 +8,10 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include/")
 
   foreach(test allgather2 allgather3 allgather_struct allgatherv2 allgatherv3
-          allred2 allred3 allred4 allred5 allred6 allredmany alltoall1
+          allred2 allred3 allred4 allred5 allred6 allredmany allred_derived allred_float alltoall1
           alltoallv0 alltoallv alltoallw1 alltoallw2 alltoallw_zeros
           bcasttest bcastzerotype coll2 coll3 coll4 coll5 coll6 coll7 coll8
-          coll9 coll10 coll11 coll12 coll13 exscan exscan2 gather gather2
+          coll9 coll10 coll11 coll12 coll13 exscan exscan2 gather gather2 gatherv
           gather_big ibarrier longuser nonblocking nonblocking2 nonblocking3 iallred
         # icallgather icallgatherv icallreduce
         # icalltoall icalltoallv icalltoallw icbarrier icbcast
@@ -94,6 +94,8 @@ set(examples_src  ${examples_src}
  ${CMAKE_CURRENT_SOURCE_DIR}/allred6.c
  ${CMAKE_CURRENT_SOURCE_DIR}/allred.c
  ${CMAKE_CURRENT_SOURCE_DIR}/allredmany.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/allred_derived.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/allred_float.c
  ${CMAKE_CURRENT_SOURCE_DIR}/alltoall1.c
  ${CMAKE_CURRENT_SOURCE_DIR}/alltoallv0.c
  ${CMAKE_CURRENT_SOURCE_DIR}/alltoallv.c
@@ -120,6 +122,7 @@ set(examples_src  ${examples_src}
  ${CMAKE_CURRENT_SOURCE_DIR}/gather2.c
  ${CMAKE_CURRENT_SOURCE_DIR}/gather_big.c
  ${CMAKE_CURRENT_SOURCE_DIR}/gather.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/gatherv.c
  ${CMAKE_CURRENT_SOURCE_DIR}/iallred.c
  ${CMAKE_CURRENT_SOURCE_DIR}/ibarrier.c
  ${CMAKE_CURRENT_SOURCE_DIR}/icallgather.c
diff --git a/teshsuite/smpi/mpich3-test/coll/allred_derived.c b/teshsuite/smpi/mpich3-test/coll/allred_derived.c
new file mode 100644 (file)
index 0000000..1b40edd
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) by Argonne National Laboratory
+ *     See COPYRIGHT in top-level directory
+ */
+
+#include "mpi.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpitest.h"
+#include <assert.h>
+
+/*
+static char MTEST_Descrip[] = "Test MPI_Allreduce with commutative user-defined operations";
+*/
+
+#define MAX_BLOCKLEN 10000
+#define IS_COMMUTATIVE 1
+
+/* We make the error count global so that we can easily control the output
+   of error information (in particular, limiting it after the first 10
+   errors */
+int errs = 0;
+
+/* parameter for a vector type of MPI_INT */
+int g_blocklen = 1;
+int g_stride = 1;
+
+void uop(void *, void *, int *, MPI_Datatype *);
+void uop(void *cinPtr, void *coutPtr, int *count, MPI_Datatype * dtype)
+{
+    const int *cin = (const int *) cinPtr;
+    int *cout = (int *) coutPtr;
+
+    int k = 0;
+    for (int i = 0; i < *count; i++) {
+        for (int j = 0; j < g_blocklen; j++) {
+            cout[k] += cin[k];
+            k += g_stride;
+        }
+    }
+}
+
+static void init_buf(void *buf, int count, int rank)
+{
+    int *p = buf;
+
+    int k = 0;
+    for (int i = 0; i < count; i++) {
+        for (int j = 0; j < g_blocklen; j++) {
+            p[k] = rank + i + j;
+            k += g_stride;
+        }
+    }
+}
+
+static int check_result(void *buf, int count, int size)
+{
+    int lerrs = 0;
+    int *p = buf;
+
+    int k = 0;
+    for (int i = 0; i < count; i++) {
+        for (int j = 0; j < g_blocklen; j++) {
+            int exp = size * (size - 1) / 2 + (i + j) * size;
+            if (p[k] != exp) {
+                lerrs++;
+                if (errs + lerrs < 10) {
+                    printf("[%d - %d] expected %d, got %d, %s\n",
+                           i, j, exp, p[k], MTestGetIntracommName());
+                }
+            }
+            k += g_stride;
+        }
+    }
+    return lerrs;
+}
+
+int main(int argc, char *argv[])
+{
+    MPI_Comm comm;
+    void *buf, *bufout;
+    MPI_Op op;
+    MPI_Datatype datatype;
+
+    MTest_Init(&argc, &argv);
+
+    MPI_Op_create(uop, IS_COMMUTATIVE, &op);
+
+    while (MTestGetIntracommGeneral(&comm, 2, 1)) {
+        if (comm == MPI_COMM_NULL) {
+            continue;
+        }
+
+        int rank, size;
+        MPI_Comm_rank(comm, &rank);
+        MPI_Comm_size(comm, &size);
+
+        int count = 10;
+        for (int n = 1; n < MAX_BLOCKLEN; n *= 2) {
+            g_blocklen = n;
+            int extent = g_blocklen * g_stride * sizeof(int);
+            MPI_Type_vector(g_blocklen, 1, g_stride, MPI_INT, &datatype);
+            MPI_Type_commit(&datatype);
+
+            buf = (int *) malloc(extent * count);
+            if (!buf) {
+                MPI_Abort(MPI_COMM_WORLD, 1);
+            }
+            bufout = (int *) malloc(extent * count);
+            if (!bufout) {
+                MPI_Abort(MPI_COMM_WORLD, 1);
+            }
+
+            init_buf(buf, count, rank);
+            MPI_Allreduce(buf, bufout, count, datatype, op, comm);
+            errs += check_result(bufout, count, size);
+
+            /* do it again using MPI_IN_PLACE */
+            init_buf(bufout, count, rank);
+            MPI_Allreduce(MPI_IN_PLACE, bufout, count, datatype, op, comm);
+            errs += check_result(bufout, count, size);
+
+            free(buf);
+            free(bufout);
+            MPI_Type_free(&datatype);
+        }
+
+        MTestFreeComm(&comm);
+    }
+
+    MPI_Op_free(&op);
+
+    MTest_Finalize(errs);
+    return MTestReturnValue(errs);
+}
diff --git a/teshsuite/smpi/mpich3-test/coll/allred_float.c b/teshsuite/smpi/mpich3-test/coll/allred_float.c
new file mode 100644 (file)
index 0000000..6b6ebc6
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) by Argonne National Laboratory
+ *     See COPYRIGHT in top-level directory
+ */
+#include "mpi.h"
+#include "mpitest.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/* MPI_Allreduce need produce identical results on all ranks. This is
+ * particular challenging for floating point datatypes since computer
+ * floating point arithmetic do not follow associative law. This means
+ * certain algorithms that works for integers need to be excluded for
+ * floating point.
+ *
+ * This test checks when an inapproprate algorithms is used for floating
+ * point reduction.
+ */
+
+/* single-precision float has roughly a precision of 7 decimal digits */
+#define BIG 1e6
+#define TINY 1e-2
+
+#define N 8
+
+float buf[N];
+
+static void init_buf(int rank, int pos1, int pos2)
+{
+    /* Mix a pair of (BIG, -BIG) and TINY, the sum of array will be the sum of
+     * all TINYs if we add (BIG, -BIG) first, but different results following
+     * different associativity. A valid algorithm need to produce consistent
+     * results on all ranks.
+     */
+    for (int i = 0; i < N; i++) {
+        if (rank == pos1) {
+            buf[i] = BIG;
+        } else if (rank == pos2) {
+            buf[i] = -BIG;
+        } else {
+            buf[i] = TINY;
+        }
+    }
+}
+
+int main(int argc, char **argv)
+{
+    int errs = 0;
+
+    MTest_Init(&argc, &argv);
+
+    int rank, size;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    if (size < 3) {
+        printf("At least 3 processes required. More (e.g. 10) is recommended.\n");
+        MPI_Abort(MPI_COMM_WORLD, 1);
+    }
+
+    for (int pos1 = 0; pos1 < size; pos1++) {
+        for (int pos2 = pos1 + 1; pos2 < size; pos2++) {
+            init_buf(rank, pos1, pos2);
+
+            MPI_Allreduce(MPI_IN_PLACE, buf, N, MPI_FLOAT, MPI_SUM, MPI_COMM_WORLD);
+
+            float *check_buf=NULL;
+            if (rank == 0) {
+                check_buf = malloc(N * size * sizeof(float));
+            }
+            MPI_Gather(buf, N, MPI_FLOAT, check_buf, N, MPI_FLOAT, 0, MPI_COMM_WORLD);
+
+            if (rank == 0) {
+                MTestPrintfMsg(1, "BIG positions = (%d, %d), result = [", pos1, pos2);
+                for (int j = 0; j < N; j++) {
+                    MTestPrintfMsg(1, "%f ", buf[j]);
+                }
+                MTestPrintfMsg(1, "]\n");
+
+                for (int i = 0; i < size; i++) {
+                    for (int j = 0; j < N; j++) {
+                        if (memcmp(&check_buf[i * N + j], &buf[j], sizeof(float)) != 0) {
+                            if (errs < 10) {
+                                printf("(%d - %d) Result [%d] from rank %d mismatch: %f != %f\n",
+                                       pos1, pos2, j, i, check_buf[i * N + j], buf[j]);
+                            }
+                            errs++;
+                        }
+                    }
+                }
+                free(check_buf);
+            }
+        }
+    }
+
+    MTest_Finalize(errs);
+    return MTestReturnValue(errs);
+}
diff --git a/teshsuite/smpi/mpich3-test/coll/gatherv.c b/teshsuite/smpi/mpich3-test/coll/gatherv.c
new file mode 100644 (file)
index 0000000..6423f35
--- /dev/null
@@ -0,0 +1,90 @@
+/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
+/*
+ *  (C) 2001 by Argonne National Laboratory.
+ *      See COPYRIGHT in top-level directory.
+ */
+#include "mpi.h"
+#include <stdio.h>
+#include "mpitest.h"
+
+#define MAX_PROCESSES 10
+
+int main(int argc, char **argv)
+{
+    int rank, size, i, j;
+    int table[MAX_PROCESSES][MAX_PROCESSES];
+    int errors = 0;
+    int participants;
+    int displs[MAX_PROCESSES];
+    int recv_counts[MAX_PROCESSES];
+
+    MTest_Init(&argc, &argv);
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    /* A maximum of MAX_PROCESSES processes can participate */
+    if (size > MAX_PROCESSES)
+        participants = MAX_PROCESSES;
+    else
+        participants = size;
+    /* while (MAX_PROCESSES % participants) participants--; */
+    if (MAX_PROCESSES % participants) {
+        fprintf(stderr, "Number of processors must divide %d\n", MAX_PROCESSES);
+        MPI_Abort(MPI_COMM_WORLD, 1);
+    }
+    if ((rank < participants)) {
+
+        /* Determine what rows are my responsibility */
+        int block_size = MAX_PROCESSES / participants;
+        int begin_row = rank * block_size;
+        int end_row = (rank + 1) * block_size;
+        int send_count = block_size * MAX_PROCESSES;
+
+        /* Fill in the displacements and recv_counts */
+        for (i = 0; i < participants; i++) {
+            displs[i] = i * block_size * MAX_PROCESSES;
+            recv_counts[i] = send_count;
+        }
+
+        /* Paint my rows my color */
+        for (i = begin_row; i < end_row; i++)
+            for (j = 0; j < MAX_PROCESSES; j++)
+                table[i][j] = rank + 10;
+
+        /* Gather everybody's result together - sort of like an */
+        /* inefficient allgather */
+        for (i = 0; i < participants; i++) {
+            void *sendbuf = (i == rank ? MPI_IN_PLACE : &table[begin_row][0]);
+            MPI_Gatherv(sendbuf, send_count, MPI_INT,
+                        &table[0][0], recv_counts, displs, MPI_INT, i, MPI_COMM_WORLD);
+        }
+
+
+        /* Everybody should have the same table now.
+         *
+         * The entries are:
+         * Table[i][j] = (i/block_size) + 10;
+         */
+        for (i = 0; i < MAX_PROCESSES; i++)
+            if ((table[i][0] - table[i][MAX_PROCESSES - 1] != 0))
+                errors++;
+        for (i = 0; i < MAX_PROCESSES; i++) {
+            for (j = 0; j < MAX_PROCESSES; j++) {
+                if (table[i][j] != (i / block_size) + 10)
+                    errors++;
+            }
+        }
+        if (errors) {
+            /* Print out table if there are any errors */
+            for (i = 0; i < MAX_PROCESSES; i++) {
+                printf("\n");
+                for (j = 0; j < MAX_PROCESSES; j++)
+                    printf("  %d", table[i][j]);
+            }
+            printf("\n");
+        }
+    }
+
+    MTest_Finalize(errors);
+    return MTestReturnValue(errors);
+}
index 3b17eb2..31dae94 100644 (file)
@@ -9,6 +9,8 @@ allred5 5
 allred5 10
 allred6 4
 allred6 7
+allred_derived 4
+allred_float 10
 reduce_mpich 5
 reduce_mpich 10
 reduce_local 2 mpiversion=2.2
@@ -80,6 +82,7 @@ exscan 10
 exscan2 5
 gather 4
 gather2 4
+gatherv 5
 scattern 4
 scatter2 4
 scatter3 4
index 4bed718..350a207 100644 (file)
@@ -1,12 +1,12 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
   include_directories(BEFORE "${CMAKE_HOME_DIRECTORY}/include/smpi")
   include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include/")
 
-  foreach(file cmfree cmsplit2 cmsplit cmsplit_type commcreate1 comm_create_group comm_group_half comm_group_rand
-          comm_info ctxalloc ctxsplit dup dup_with_info commname)
+  foreach(file cmfree cmfree2 cmsplit2 cmsplit cmsplit_type commcreate1 comm_create_group comm_group_half comm_group_rand
+          comm_info comm_info2 ctxalloc ctxsplit dup dup_with_info commname)
     # not compiled files
     # comm_idup comm_idup_mul comm_idup_overlap  dupic ic1 ic2 iccreate icgroup icm icsplit probe-intercomm
     add_executable(${file} EXCLUDE_FROM_ALL ${file}.c)
@@ -15,13 +15,13 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endforeach()
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-comm-raw       ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/comm ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/comm -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-comm-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
 
-foreach(file cmfree cmsplit2 cmsplit cmsplit_type commcreate1 comm_create_group comm_group_half comm_group_rand
-        comm_info commname ctxalloc ctxsplit dup dupic dup_with_info ic1 ic2
+foreach(file cmfree cmfree2 cmsplit2 cmsplit cmsplit_type commcreate1 comm_create_group comm_group_half comm_group_rand
+        comm_info comm_info2 commname ctxalloc ctxsplit dup dupic dup_with_info ic1 ic2
         iccreate icgroup icm icsplit probe-intercomm comm_create_group_idup comm_idup_comm comm_idup_mul comm_idup comm_idup_iallreduce comm_idup_nb comm_idup_comm2 comm_idup_isend comm_idup_overlap
 )
   set(examples_src ${examples_src}  ${CMAKE_CURRENT_SOURCE_DIR}/${file}.c)
diff --git a/teshsuite/smpi/mpich3-test/comm/cmfree2.c b/teshsuite/smpi/mpich3-test/comm/cmfree2.c
new file mode 100644 (file)
index 0000000..fc94efb
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) by Argonne National Laboratory
+ *     See COPYRIGHT in top-level directory
+ */
+
+#include "mpi.h"
+#include <stdlib.h>
+#include "mpitest.h"
+
+/*
+static char MTEST_Descrip[] = "Test that communicators have reference count semantics";
+*/
+
+int main(int argc, char *argv[])
+{
+    int errs = 0;
+    int rank, size;
+    MPI_Comm comm;
+
+    MTest_Init(&argc, &argv);
+
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+    if (size < 2) {
+        fprintf(stderr, "This test requires at least two processes.");
+        MPI_Abort(MPI_COMM_WORLD, 1);
+    }
+
+    MPI_Comm_dup(MPI_COMM_WORLD, &comm);
+
+    if (rank == 0) {
+        MPI_Barrier(MPI_COMM_WORLD);
+        MPI_Ssend(NULL, 0, MPI_INT, 1, 0, comm);
+        MPI_Comm_free(&comm);
+    } else if (rank == 1) {
+        MPI_Request req;
+        /* recv an ssend after the user frees the comm */
+        MPI_Irecv(NULL, 0, MPI_INT, 0, 0, comm, &req);
+        MPI_Comm_free(&comm);
+        MPI_Barrier(MPI_COMM_WORLD);
+        MPI_Wait(&req, MPI_STATUS_IGNORE);
+    } else {
+        MPI_Comm_free(&comm);
+        MPI_Barrier(MPI_COMM_WORLD);
+    }
+
+    MTest_Finalize(errs);
+    return MTestReturnValue(errs);
+}
diff --git a/teshsuite/smpi/mpich3-test/comm/comm_info2.c b/teshsuite/smpi/mpich3-test/comm/comm_info2.c
new file mode 100644 (file)
index 0000000..eb4de40
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) by Argonne National Laboratory
+ *     See COPYRIGHT in top-level directory
+ */
+
+#include <stdio.h>
+#include <mpi.h>
+#include "mpitest.h"
+
+
+/*
+  This program provides tests cases for the functional evaluation
+  of the MPI communicator info hints infrastructure.
+ */
+
+int main(int argc, char **argv)
+{
+    int rank;
+    MPI_Info info_in, info_out;
+    int errs = 0;
+    MPI_Comm comm;
+    char query_key[MPI_MAX_INFO_KEY];
+    char val[MPI_MAX_INFO_VAL];
+    char new_key[MPI_MAX_INFO_KEY];
+    MPI_Comm comm_dup2;
+    MPI_Comm comm_dup3;
+    MPI_Comm comm_dup4;
+    MPI_Comm comm_split1;
+    MPI_Info info_out2;
+    MPI_Info info_out3;
+    MPI_Info info_out5;
+    MPI_Info info_in3;
+
+
+    /* Read arguments: info key and value */
+    snprintf(query_key, MPI_MAX_INFO_KEY, "arbitrary_key");
+    snprintf(val, MPI_MAX_INFO_VAL, "arbitrary_val");
+
+    MTest_Init(&argc, &argv);
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+    /* Goal of the test is only to make sure that MPI does not break */
+    /* No expectation is made on if the hints are actually set */
+
+    /* Test 1: comm_dup */
+    if (rank == 0)
+        MTestPrintfMsg(1,
+                       "Testing MPI_Comm_dup with a source comm that has default comm infohints");
+    MPI_Comm_dup(MPI_COMM_WORLD, &comm);
+
+    /* Test 2: comm_set_info and comm_get_info */
+    if (rank == 0)
+        MTestPrintfMsg(1, "Testing MPI_Comm_set_info and MPI_Comm_get_info");
+    MPI_Info_create(&info_in);
+    MPI_Info_set(info_in, query_key, val);
+    MPI_Comm_set_info(comm, info_in);
+    MPI_Comm_get_info(comm, &info_out);
+    MPI_Info_free(&info_out);
+
+    /* Test 3: com_dup after info is set in source comm */
+    if (rank == 0)
+        MTestPrintfMsg(1, "Testing MPI_Comm_dup: source comm has user provided comm infohint");
+    MPI_Comm_dup(comm, &comm_dup2);
+    MPI_Comm_get_info(comm_dup2, &info_out2);
+    MPI_Comm_free(&comm_dup2);
+    MPI_Info_free(&info_out2);
+
+    /* Test 4: Comm_dup_with_info */
+    if (rank == 0)
+        MTestPrintfMsg(1, "Testing MPI_Comm_dup_with_info");
+
+    /* Add 2 hints and create comm dup with info */
+    MPI_Info_create(&info_in3);
+    MPI_Info_set(info_in3, query_key, val);
+    snprintf(new_key, MPI_MAX_INFO_KEY, "arbitrary_key_2");
+    MPI_Info_set(info_in3, new_key, "arbitrary_value_2");
+    MPI_Comm_dup_with_info(comm, info_in3, &comm_dup3);
+    MPI_Comm_get_info(comm_dup3, &info_out3);
+    MPI_Info_free(&info_in3);
+    MPI_Info_free(&info_out3);
+    MPI_Comm_free(&comm_dup3);
+
+    /* Test 5: MPI_Comm_split_type */
+    MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, 0, info_in, &comm_split1);
+    MPI_Comm_get_info(comm_split1, &info_out5);
+    MPI_Info_free(&info_out5);
+    MPI_Comm_free(&comm_split1);
+
+    /* Test 6: comm_dup_with_info with info=MPI_INFO_NULL */
+    if (rank == 0)
+        MTestPrintfMsg(1, "Testing MPI_Comm_dup_with_info with MPI_INFO_NULL");
+    MPI_Comm_dup_with_info(comm, MPI_INFO_NULL, &comm_dup4);
+    MPI_Comm_free(&comm_dup4);
+
+    /* TODO - Test: MPI_Dist_graph_create_adjacent */
+
+    /* Release remaining resources */
+    MPI_Info_free(&info_in);
+    MPI_Comm_free(&comm);
+
+    MTest_Finalize(errs);
+    return MTestReturnValue(errs);
+}
index 4f2dc40..74577b3 100644 (file)
@@ -14,6 +14,7 @@ commname 4
 ctxalloc 2 timeLimit=300
 ctxsplit 4 timeLimit=300
 cmfree 4
+cmfree2 2
 cmsplit 4
 cmsplit2 12
 #probe-intercomm 2
@@ -35,3 +36,4 @@ dup_with_info 2 mpiversion=3.0
 dup_with_info 4 mpiversion=3.0
 dup_with_info 9 mpiversion=3.0
 comm_info 6 mpiversion=3.0
+comm_info2 1
index b9d31e5..2e4d7bf 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -31,7 +31,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
 
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-datatype-raw   ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/datatype ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/datatype -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-datatype-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
index e941496..f16e19c 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -12,7 +12,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endforeach()
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-errhan-raw       ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/errhan ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/errhan -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-errhan-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
index fee3ec3..2b8909c 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index 30bbd89..de624ed 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index d28313a..f864421 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index 4c55031..615b08a 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index 9ac4ac9..9c4e626 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index 4aac50d..0bdc36c 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index 2a3e74f..6e6b127 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index f6f088d..44e53d7 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index 1daf583..7b0ea93 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index f8964a5..d713eb7 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index e88db7e..b8e9ebb 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
index 1dc21fe..22be2e5 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpif90")
 
index e80c514..a8a45ce 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpif90")
 
index b4fb632..3ee04a0 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpif90")
 
index 3ce5a7c..18906d1 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpif90")
 
index 4ad7bd8..0004e52 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpif90")
 
index 48f19fc..4bea7c0 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpif90")
 
index e2f0a9b..68fab4d 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite AND SMPI_FORTRAN)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3 AND SMPI_FORTRAN)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpif90")
 
index 2f3cb24..c1364f8 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -12,7 +12,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endforeach()
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-group-raw      ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/group ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/group -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-group-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
index 4d6d572..068e157 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -12,7 +12,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endforeach()
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-info-raw       ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/info ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/info -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-info-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
index 4a8a6e8..951fa6c 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -12,7 +12,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endforeach()
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-init-raw       ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/init ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/init -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-init-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
index 643b4ab..4856c24 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -13,7 +13,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endforeach()
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-io-raw      ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/io ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -platformfile=../../../../examples/platforms/hosts_with_disks.xml -hostfile=../../hostfile_io -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/io -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-io-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
index c57bc7b..f0ec2a0 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -13,7 +13,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   endforeach()
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-perf-raw       ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/perf ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -tests=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/perf/testlist -execarg=-platform\ ${CMAKE_HOME_DIRECTORY}/examples/platforms/cluster_backbone.xml -execarg=--log=root.thr:critical -execarg=--cfg=smpi/async-small-thresh:65536 -execarg=--cfg=contexts/factory:raw -execarg=--cfg=smpi/simulate-computation:0)
 endif()
 
index 8a8431a..3844964 100644 (file)
@@ -1,12 +1,12 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
   include_directories(BEFORE "${CMAKE_HOME_DIRECTORY}/include/smpi")
   include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include/")
 
-  foreach(file anyall bottom eagerdt huge_anysrc huge_underflow inactivereq isendself isendirecv isendselfprobe issendselfcancel cancelanysrc pingping probenull
-          dtype_send greq1 probe-unexp rqstatus sendall sendflood sendrecv1 sendrecv2 sendrecv3 waitany-null waittestnull many_isend manylmt recv_any sendself scancel scancel2 rcancel bsend1 bsend2 bsend3 bsend4 bsend5 bsendalign bsendfrag bsendpending rqfreeb)
+  foreach(file anyall bottom eagerdt huge_anysrc huge_dupcomm huge_ssend huge_underflow inactivereq isendself isendrecv isendrecv_replace isendirecv isendselfprobe issendselfcancel large_tag multi_psend_derived cancelanysrc pingping probenull
+          dtype_send greq1 probe-unexp rqstatus sendall sendflood sendrecv1 sendrecv2 sendrecv3 waitany-null waittestnull many_isend manylmt recv_any sendself scancel scancel2 rcancel bsend1 bsend2 bsend3 bsend4 bsend5 bsendalign bsendfrag bsendpending rqfreeb pssend)
     # not compiled files: big_count_status mprobe
     # cancelrecv  icsend large_message pscancel     scancel_unmatch
     add_executable(${file} EXCLUDE_FROM_ALL ${file}.c)
@@ -27,10 +27,12 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
   unset(name)
 endif()
 
-foreach(file anyall bottom eagerdt huge_anysrc huge_underflow inactivereq isendself isendirecv isendselfprobe issendselfcancel pingping probenull
+foreach(file anyall bottom eagerdt huge_anysrc huge_dupcomm huge_ssend huge_underflow inactivereq isendrecv isendrecv_replace
+         isendself isendirecv isendselfprobe issendselfcancel large_tag multi_psend_derived pingping probenull
           probe-unexp sendall sendflood sendrecv1 sendrecv2 sendrecv3 waitany-null waittestnull
           big_count_status bsend1 bsend2 bsend3 bsend4 bsend5 bsendalign bsendfrag bsendpending
-          cancelrecv cancelanysrc dtype_send greq1 icsend large_message pscancel rcancel rqfreeb rqstatus scancel2 scancel sendself many_isend manylmt mprobe recv_any scancel_unmatch
+          cancelrecv cancelanysrc dtype_send greq1 icsend large_message pscancel pssend
+         rcancel rqfreeb rqstatus scancel2 scancel sendself many_isend manylmt mprobe recv_any scancel_unmatch
 )
   set(examples_src  ${examples_src} ${CMAKE_CURRENT_SOURCE_DIR}/${file}.c)
 endforeach()
diff --git a/teshsuite/smpi/mpich3-test/pt2pt/huge_dupcomm.c b/teshsuite/smpi/mpich3-test/pt2pt/huge_dupcomm.c
new file mode 100644 (file)
index 0000000..a22c429
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  (C) 2018 by Argonne National Laboratory.
+ *      See COPYRIGHT in top-level directory.
+ *
+ *  Portions of this code were written by Intel Corporation.
+ *  Copyright (C) 2011-2018 Intel Corporation.  Intel provides this material
+ *  to Argonne National Laboratory subject to Software Grant and Corporate
+ *  Contributor License Agreement dated February 8, 2012.
+ *
+ *  This program checks if MPICH can correctly handle huge message sends
+ *  over multiple different communicators simultaneously
+ *
+ */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mpitest.h"
+
+#define COUNT (4*1024*1024)
+#define NCOMMS 4
+
+int main(int argc, char *argv[])
+{
+    int *buff;
+    int size, rank;
+    int i;
+    MPI_Comm comms[NCOMMS];
+    MPI_Request reqs[NCOMMS];
+
+    MTest_Init(&argc, &argv);
+
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    if (size != 2) {
+        fprintf(stderr, "Launch with two processes\n");
+        MPI_Abort(MPI_COMM_WORLD, 1);
+    }
+
+    buff = malloc(COUNT * NCOMMS * sizeof(int));
+
+    for (i = 0; i < NCOMMS; i++)
+        MPI_Comm_dup(MPI_COMM_WORLD, &comms[i]);
+
+    for (i = 0; i < NCOMMS; i++) {
+        if (rank == 0)
+            MPI_Isend(buff + COUNT * i, COUNT, MPI_INT, 1 /* dest */ , 0 /* tag */ , comms[i],
+                      &reqs[i]);
+        else
+            MPI_Irecv(buff + COUNT * i, COUNT, MPI_INT, 0 /* src */ , 0 /* tag */ , comms[i],
+                      &reqs[i]);
+    }
+    MPI_Waitall(NCOMMS, reqs, MPI_STATUSES_IGNORE);
+
+    for (i = 0; i < NCOMMS; i++)
+        MPI_Comm_free(&comms[i]);
+
+    free(buff);
+
+    MTest_Finalize(0);
+
+    return 0;
+}
diff --git a/teshsuite/smpi/mpich3-test/pt2pt/huge_ssend.c b/teshsuite/smpi/mpich3-test/pt2pt/huge_ssend.c
new file mode 100644 (file)
index 0000000..cdd7f2c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  (C) 2018 by Argonne National Laboratory.
+ *      See COPYRIGHT in top-level directory.
+ *
+ *  Portions of this code were written by Intel Corporation.
+ *  Copyright (C) 2011-2018 Intel Corporation.  Intel provides this material
+ *  to Argonne National Laboratory subject to Software Grant and Corporate
+ *  Contributor License Agreement dated February 8, 2012.
+ *
+ *  This program checks if MPICH can correctly handle huge synchronous sends
+ *
+ */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mpitest.h"
+
+#define COUNT (4*1024*1024)
+
+int main(int argc, char *argv[])
+{
+    int *buff;
+    int size, rank;
+
+    MTest_Init(&argc, &argv);
+
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    if (size != 2) {
+        fprintf(stderr, "Launch with two processes\n");
+        MPI_Abort(MPI_COMM_WORLD, 1);
+    }
+
+    buff = malloc(COUNT * sizeof(int));
+
+    if (rank == 0)
+        MPI_Ssend(buff, COUNT, MPI_INT, 1, 0, MPI_COMM_WORLD);
+    else
+        MPI_Recv(buff, COUNT, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+
+    free(buff);
+
+    MTest_Finalize(0);
+
+    return 0;
+}
index fd9e7d0..ea7099c 100644 (file)
@@ -40,13 +40,53 @@ int StatusEmpty(MPI_Status * s)
     return errs ? 0 : 1;
 }
 
-int main(int argc, char *argv[])
+int test_recv_init(int src_rank, const char *test_name);
+int test_recv_init(int src_rank, const char *test_name)
 {
     MPI_Request r;
     MPI_Status s;
     int errs = 0;
     int flag;
     int buf[10];
+    int tag = 27;
+
+    MPI_Recv_init(buf, 10, MPI_INT, src_rank, tag, MPI_COMM_WORLD, &r);
+
+    flag = 0;
+    s.MPI_TAG = 10;
+    s.MPI_SOURCE = 10;
+    MPI_Test(&r, &flag, &s);
+    if (!flag) {
+        errs++;
+        printf("Flag not true after MPI_Test (%s)\n", test_name);
+        printf("Aborting further tests to avoid hanging in MPI_Wait\n");
+        return errs;
+    }
+    if (!StatusEmpty(&s)) {
+        errs++;
+        printf("Status not empty after MPI_Test (%s)\n", test_name);
+    }
+
+    s.MPI_TAG = 10;
+    s.MPI_SOURCE = 10;
+    MPI_Wait(&r, &s);
+    if (!StatusEmpty(&s)) {
+        errs++;
+        printf("Status not empty after MPI_Wait (%s)\n", test_name);
+    }
+
+    MPI_Request_free(&r);
+
+    return errs;
+}
+
+int main(int argc, char *argv[])
+{
+    MPI_Request r;
+    MPI_Status s;
+    int errs = 0, e;
+    int flag;
+    int buf[10];
     int rbuf[10];
     int tag = 27;
     int dest = 0;
@@ -57,7 +97,9 @@ int main(int argc, char *argv[])
     MPI_Comm_size(MPI_COMM_WORLD, &size);
     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
 
-    /* Create a persistent send request */
+    if (rank == 0)
+        MTestPrintfMsg(1, "Create a persistent send request\n");
+
     MPI_Send_init(buf, 10, MPI_INT, dest, tag, MPI_COMM_WORLD, &r);
 
     flag = 0;
@@ -69,8 +111,7 @@ int main(int argc, char *argv[])
         printf("Flag not true after MPI_Test (send)\n");
         printf("Aborting further tests to avoid hanging in MPI_Wait\n");
         MTest_Finalize(errs);
-        MPI_Finalize();
-        return 0;
+        return MTestReturnValue(errs);
     }
     if (!StatusEmpty(&s)) {
         errs++;
@@ -96,8 +137,7 @@ int main(int argc, char *argv[])
         MPI_Wait(&r, &s);
         MPI_Waitall(size, rr, MPI_STATUSES_IGNORE);
         free(rr);
-    }
-    else {
+    } else {
         MPI_Start(&r);
         MPI_Wait(&r, &s);
     }
@@ -111,8 +151,7 @@ int main(int argc, char *argv[])
         printf("Flag not true after MPI_Test (send)\n");
         printf("Aborting further tests to avoid hanging in MPI_Wait\n");
         MTest_Finalize(errs);
-        MPI_Finalize();
-        return 0;
+        return MTestReturnValue(errs);
     }
     if (!StatusEmpty(&s)) {
         errs++;
@@ -131,37 +170,20 @@ int main(int argc, char *argv[])
 
     MPI_Request_free(&r);
 
-    /* Create a persistent receive request */
-    MPI_Recv_init(buf, 10, MPI_INT, dest, tag, MPI_COMM_WORLD, &r);
+    if (rank == 0)
+        MTestPrintfMsg(1, "Create a persistent receive request\n");
 
-    flag = 0;
-    s.MPI_TAG = 10;
-    s.MPI_SOURCE = 10;
-    MPI_Test(&r, &flag, &s);
-    if (!flag) {
-        errs++;
-        printf("Flag not true after MPI_Test (recv)\n");
-        printf("Aborting further tests to avoid hanging in MPI_Wait\n");
-        MTest_Finalize(errs);
-        MPI_Finalize();
-        return 0;
-    }
-    if (!StatusEmpty(&s)) {
-        errs++;
-        printf("Status not empty after MPI_Test (recv)\n");
-    }
+    e = test_recv_init(dest, "recv");
+    errs += e;
+    if (e)
+        goto fn_exit;
 
-    s.MPI_TAG = 10;
-    s.MPI_SOURCE = 10;
-    MPI_Wait(&r, &s);
-    if (!StatusEmpty(&s)) {
-        errs++;
-        printf("Status not empty after MPI_Wait (recv)\n");
-    }
+    if (rank == 0)
+        MTestPrintfMsg(1, "Create a persistent receive (ANY_SOURCE) request\n");
 
-    MPI_Request_free(&r);
+    errs += test_recv_init(MPI_ANY_SOURCE, "recv-anysource");
 
+  fn_exit:
     MTest_Finalize(errs);
-    MPI_Finalize();
-    return 0;
+    return MTestReturnValue(errs);
 }
diff --git a/teshsuite/smpi/mpich3-test/pt2pt/isendrecv.c b/teshsuite/smpi/mpich3-test/pt2pt/isendrecv.c
new file mode 100644 (file)
index 0000000..63512e6
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) by Argonne National Laboratory
+ *     See COPYRIGHT in top-level directory
+ */
+
+#include "mpi.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "mpitest.h"
+
+/* Similar test as isendirecv.c, but use MPI_Isendrecv */
+
+int errs = 0;
+int elems = 20;
+int rank, nproc, dest;
+MPI_Comm comm;
+float *in_buf, *out_buf;
+MPI_Request *reqs;
+
+/* sendrecv may use the same or different source and destination,
+ * offset defines the offset between them */
+static void test_sendrecv(int offset)
+{
+    for (int i = 0; i < nproc; i++) {
+        for (int j = 0; j < elems; j++) {
+            in_buf[i * elems + j] = -1.0;
+            out_buf[i * elems + j] = rank * 10000.0 + i * 100.0 + j;
+        }
+    }
+
+    for (int i = 0; i < nproc; i++) {
+        int j = (i + offset) % nproc;
+        MPI_Isendrecv(&out_buf[elems * i], elems, MPI_FLOAT, i, 0,
+                      &in_buf[elems * j], elems, MPI_FLOAT, j, 0, comm, &reqs[i]);
+    }
+
+    MPI_Waitall(nproc, reqs, MPI_STATUSES_IGNORE);
+
+    for (int i = 0; i < nproc; i++) {
+        for (int j = 0; j < elems; j++) {
+            if (in_buf[i * elems + j] != i * 10000.0 + rank * 100.0 + j) {
+                errs++;
+            }
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    MTest_Init(&argc, &argv);
+
+    comm = MPI_COMM_WORLD;
+    MPI_Comm_rank(comm, &rank);
+    MPI_Comm_size(comm, &nproc);
+
+    reqs = malloc(nproc * sizeof(MPI_Request));
+    in_buf = malloc(elems * nproc * sizeof(float));
+    out_buf = malloc(elems * nproc * sizeof(float));
+
+    for (int offset = 0; offset < nproc - 1; offset++) {
+        test_sendrecv(offset);
+    }
+
+    free(reqs);
+    free(in_buf);
+    free(out_buf);
+    MTest_Finalize(errs);
+    return MTestReturnValue(errs);
+}
diff --git a/teshsuite/smpi/mpich3-test/pt2pt/isendrecv_replace.c b/teshsuite/smpi/mpich3-test/pt2pt/isendrecv_replace.c
new file mode 100644 (file)
index 0000000..f0174c9
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) by Argonne National Laboratory
+ *     See COPYRIGHT in top-level directory
+ */
+
+#include "mpi.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "mpitest.h"
+
+/* Similar test as isendirecv.c, but use MPI_Isendrecv_replace */
+
+int errs = 0;
+int elems = 20;
+int rank, nproc, dest;
+float *buf;
+MPI_Comm comm;
+MPI_Request *reqs;
+
+static void test_sendrecv(int offset)
+{
+    for (int i = 0; i < nproc; i++) {
+        for (int j = 0; j < elems; j++) {
+            buf[i * elems + j] = rank * 100.0 + j;
+        }
+    }
+
+    for (int i = 0; i < nproc; i++) {
+        int j = (i + offset) % nproc;
+        MPI_Isendrecv_replace(&buf[elems * j], elems, MPI_FLOAT, i, 0, j, 0, comm, &reqs[i]);
+    }
+
+    MPI_Waitall(nproc, reqs, MPI_STATUSES_IGNORE);
+
+    for (int i = 0; i < nproc; i++) {
+        for (int j = 0; j < elems; j++) {
+            if (buf[i * elems + j] != i * 100.0 + j) {
+                if (errs < 10) {
+                    fprintf(stderr, "buf(%d, %d) mismatch, got %f, expect %f\n", i, j,
+                            buf[i * elems + j], (float) (i * 100.0 + j));
+                }
+                errs++;
+            }
+        }
+    }
+}
+
+/* sendrecv may use the same or different source and destination,
+ * offset defines the offset between them */
+
+int main(int argc, char *argv[])
+{
+    MTest_Init(&argc, &argv);
+
+    comm = MPI_COMM_WORLD;
+    MPI_Comm_rank(comm, &rank);
+    MPI_Comm_size(comm, &nproc);
+
+    reqs = malloc(nproc * sizeof(MPI_Request));
+    buf = malloc(elems * nproc * sizeof(float));
+
+    for (int offset = 0; offset < nproc - 1; offset++) {
+        test_sendrecv(offset);
+    }
+
+    free(reqs);
+    free(buf);
+    MTest_Finalize(errs);
+    return MTestReturnValue(errs);
+}
diff --git a/teshsuite/smpi/mpich3-test/pt2pt/large_tag.c b/teshsuite/smpi/mpich3-test/pt2pt/large_tag.c
new file mode 100644 (file)
index 0000000..10eeb1a
--- /dev/null
@@ -0,0 +1,75 @@
+/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
+/*
+ *  (C) 2010 by Argonne National Laboratory.
+ *      See COPYRIGHT in top-level directory.
+ */
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpitest.h"
+
+/* Tests send/receive with large tag values. It mimics the usage of tags in
+ * some MPI-based libraries (e.g., PETSc). */
+
+#define ITER 5
+#define BUF_COUNT (16)
+
+int recvbuf[BUF_COUNT], sendbuf[BUF_COUNT];
+
+int main(int argc, char *argv[])
+{
+    int x, size, rank, errs = 0;
+    void *tag_ub_val = NULL;
+    int tag = 0, flag = 0;
+
+    MTest_Init(&argc, &argv);
+
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+    /* perform test only with two or more processes */
+    if (size < 2)
+        goto exit;
+
+    /* query the upper bound of tag value */
+    MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB, &tag_ub_val, &flag);
+    tag = *(int *) tag_ub_val;
+    if (!flag || tag < 32767) {
+        fprintf(stdout, "%d -- Incorrect MPI_TAG_UB, found flag=%d, tag=%d\n", rank, flag, tag);
+        fflush(stdout);
+        errs++;
+        goto exit;
+    }
+
+    /* send/receive with large tags from the upper bound */
+    for (x = 0; x < ITER; x++) {
+        int i;
+
+        if (rank == 0) {
+            /* reset send buffer */
+            for (i = 0; i < BUF_COUNT; i++)
+                sendbuf[i] = x * BUF_COUNT + i;
+
+            MPI_Send(sendbuf, BUF_COUNT, MPI_INT, 1, tag, MPI_COMM_WORLD);
+        } else if (rank == 1) {
+            MPI_Recv(recvbuf, BUF_COUNT, MPI_INT, 0, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+
+            /* check correctness of received data */
+            for (i = 0; i < BUF_COUNT; i++) {
+                int expected_val = x * BUF_COUNT + i;
+                if (recvbuf[i] != expected_val) {
+                    errs++;
+                    fprintf(stdout, "%d -- Received %d at index %d with tag %d, expected %d\n",
+                            rank, recvbuf[i], i, tag, expected_val);
+                    fflush(stdout);
+                }
+            }
+        }
+        tag--;
+    }
+
+  exit:
+    MTest_Finalize(errs);
+
+    return MTestReturnValue(errs);
+}
diff --git a/teshsuite/smpi/mpich3-test/pt2pt/multi_psend_derived.c b/teshsuite/smpi/mpich3-test/pt2pt/multi_psend_derived.c
new file mode 100644 (file)
index 0000000..84f670e
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  (C) 2018 by Argonne National Laboratory.
+ *      See COPYRIGHT in top-level directory.
+ *
+ *  Portions of this code were written by Intel Corporation.
+ *  Copyright (C) 2011-2018 Intel Corporation.  Intel provides this material
+ *  to Argonne National Laboratory subject to Software Grant and Corporate
+ *  Contributor License Agreement dated February 8, 2012.
+ *
+ *  This program checks if MPICH can correctly handle multiple persistent
+ *  communication calls with a derived datatype
+ *
+ */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpitest.h"
+
+#define ITER 16
+
+int main(int argc, char *argv[])
+{
+    int size, rank;
+    int i;
+    MPI_Request req;
+    MPI_Datatype int_dup;
+    int v = 1, errs = 0;
+
+    MTest_Init(&argc, &argv);
+
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    if (size != 2) {
+        fprintf(stderr, "Launch with two processes\n");
+        MPI_Abort(MPI_COMM_WORLD, 1);
+    }
+
+    if (rank == 0)
+        MTestPrintfMsg(1, "Test 1: Persistent send - Recv\n");
+
+    if (rank == 0) {
+        MPI_Type_dup(MPI_INT, &int_dup);
+        v = 42;
+        MPI_Send_init(&v, 1, int_dup, 1, 0, MPI_COMM_WORLD, &req);
+        MPI_Type_free(&int_dup);
+        for (i = 0; i < ITER; i++) {
+            MPI_Status s;
+            MPI_Start(&req);
+            MPI_Wait(&req, &s);
+        }
+        MPI_Request_free(&req);
+    } else {
+        for (i = 0; i < ITER; i++) {
+            v = -1;
+            MPI_Recv(&v, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+            if (v != 42) {
+                errs++;
+                fprintf(stderr, "Psend-recv iteration %d: Expected 42 but got %d\n", i, v);
+            }
+        }
+    }
+
+    if (rank == 0)
+        MTestPrintfMsg(1, "Test 2: Send - Persistent recv (with ANY_SOURCE)\n");
+
+    if (rank == 0) {
+        for (i = 0; i < ITER; i++) {
+            v = i;
+            MPI_Send(&v, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
+        }
+    } else {
+        MPI_Type_dup(MPI_INT, &int_dup);
+        MPI_Recv_init(&v, 1, int_dup, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &req);
+        MPI_Type_free(&int_dup);
+        for (i = 0; i < ITER; i++) {
+            MPI_Status s;
+            v = -1;
+            MPI_Start(&req);
+            MPI_Wait(&req, &s);
+            if (v != i) {
+                errs++;
+                fprintf(stderr, "Send-precv(anysrc) iteration %d: Expected %d but got %d\n",
+                        i, i, v);
+            }
+        }
+        MPI_Request_free(&req);
+    }
+
+    MTest_Finalize(errs);
+    MPI_Finalize();
+    return MTestReturnValue(errs);
+}
diff --git a/teshsuite/smpi/mpich3-test/pt2pt/pssend.c b/teshsuite/smpi/mpich3-test/pt2pt/pssend.c
new file mode 100644 (file)
index 0000000..c936224
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) by Argonne National Laboratory
+ *     See COPYRIGHT in top-level directory
+ */
+
+/*
+ * This program checks the semantics of persistent synchronous send
+ */
+#include "mpi.h"
+#include "mpitest.h"
+
+int main(int argc, char *argv[])
+{
+    int errs = 0;
+    int size, rank;
+    MPI_Request req;
+    int flag;
+
+    MTest_Init(&argc, &argv);
+
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+    if (size < 2) {
+        fprintf(stderr, "Launch with two processes\n");
+        MPI_Abort(MPI_COMM_WORLD, 1);
+    }
+
+    if (rank == 0) {
+        MPI_Ssend_init(NULL, 0, MPI_INT, 1, 0, MPI_COMM_WORLD, &req);
+        MPI_Start(&req);
+
+        /* ssend cannot be complete at this point */
+        MPI_Test(&req, &flag, MPI_STATUS_IGNORE);
+        if (flag != 0) {
+            errs++;
+            fprintf(stderr, "ERROR: synchronous send completed before matching recv was posted\n");
+        }
+    }
+
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    if (rank == 0) {
+        MPI_Wait(&req, MPI_STATUS_IGNORE);
+        MPI_Request_free(&req);
+    } else if (rank == 1) {
+        MPI_Recv(NULL, 0, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+    }
+
+    MTest_Finalize(errs);
+
+    return 0;
+}
index 6af72a2..b9f8d4f 100644 (file)
@@ -17,6 +17,8 @@ bsend4 1
 bsendalign 2
 bsendpending 2
 isendself 1
+isendrecv 4
+isendrecv_replace 4
 #issendselfcancel 1
 isendirecv 10
 bsendfrag 2
@@ -33,6 +35,7 @@ scancel 2 xfail=ticket287
 scancel2 2
 #Needs MPI_Buffer_attach
 #pscancel 2 xfail=ticket287
+pssend 2
 rcancel 2
 #cancelrecv 2 xfail=ticket287
 isendselfprobe 1
@@ -43,11 +46,15 @@ waitany-null 1
 # this should be run only on machines with large amount of memory (>=8GB)
 # perhaps disable in the release tarball
 #large_message 3
+large_tag 2
 #mprobe 2 mpiversion=3.0
 #big_count_status 1 mpiversion=3.0
 many_isend 3
 manylmt 2
+multi_psend_derived 2
 huge_anysrc 2
+huge_dupcomm 2
+huge_ssend 2
 huge_underflow 2
 dtype_send 2
 recv_any 2
index 9115003..be6d1db 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -37,7 +37,7 @@ if(enable_smpi AND enable_smpi_MPICH3_testsuite)
     set_target_properties(transpose3_shm PROPERTIES COMPILE_FLAGS "${MPICH_FLAGS} -DUSE_WIN_ALLOCATE")
 endif()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-rma-raw       ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/rma ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/rma -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-rma-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
   if (enable_thread_sanitizer OR enable_coverage)
index 671fbcd..7c032fc 100644 (file)
@@ -1,4 +1,4 @@
-if(enable_smpi AND enable_smpi_MPICH3_testsuite)
+if(enable_smpi AND enable_testsuite_smpi_MPICH3)
   set(CMAKE_C_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpicc")
   set(CMAKE_Fortran_COMPILER "${CMAKE_BINARY_DIR}/smpi_script/bin/smpiff")
 
@@ -19,7 +19,7 @@ foreach(file cartcreates cartshift1 cartsuball cartzero cartmap1 dgraph_unwgt di
   set(examples_src  ${examples_src} ${CMAKE_CURRENT_SOURCE_DIR}/${file}.c)
 endforeach()
 
-if (enable_smpi_MPICH3_testsuite AND HAVE_RAW_CONTEXTS)
+if (enable_testsuite_smpi_MPICH3 AND HAVE_RAW_CONTEXTS)
   ADD_TEST(test-smpi-mpich3-topo-raw       ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/teshsuite/smpi/mpich3-test/topo ${PERL_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/runtests "-wrapper=${VALGRIND_WRAPPER}" -mpiexec=${CMAKE_BINARY_DIR}/smpi_script/bin/smpirun -srcdir=${CMAKE_HOME_DIRECTORY}/teshsuite/smpi/mpich3-test/topo -tests=testlist -execarg=--cfg=contexts/factory:raw)
   SET_TESTS_PROPERTIES(test-smpi-mpich3-topo-raw PROPERTIES PASS_REGULAR_EXPRESSION "tests passed!")
 endif()
index fb10524..d3c59bb 100644 (file)
@@ -19,18 +19,8 @@ foreach(x parallel_log_crashtest parmap_bench parmap_test signals)
   set(teshsuite_src ${teshsuite_src} ${CMAKE_CURRENT_SOURCE_DIR}/${x}/${x}.cpp)
 endforeach()
 
-if(HAVE_MMALLOC)
-  add_executable       (mmalloc_test EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/mmalloc/mmalloc_test.cpp)
-  target_link_libraries(mmalloc_test simgrid sgmalloc)
-  set_target_properties(mmalloc_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mmalloc)
-  set_property(TARGET mmalloc_test APPEND PROPERTY INCLUDE_DIRECTORIES "${INTERNAL_INCLUDES}")
-  add_dependencies(tests mmalloc_test)
-endif()
-
-set(tesh_files    ${tesh_files}     ${CMAKE_CURRENT_SOURCE_DIR}/log_usage/log_usage_ndebug.tesh
-                                    ${CMAKE_CURRENT_SOURCE_DIR}/mmalloc/mmalloc_64.tesh
-                                    ${CMAKE_CURRENT_SOURCE_DIR}/mmalloc/mmalloc_32.tesh          PARENT_SCOPE)
-set(teshsuite_src ${teshsuite_src}  ${CMAKE_CURRENT_SOURCE_DIR}/mmalloc/mmalloc_test.cpp           PARENT_SCOPE)
+set(tesh_files    ${tesh_files}     ${CMAKE_CURRENT_SOURCE_DIR}/log_usage/log_usage_ndebug.tesh    PARENT_SCOPE)
+set(teshsuite_src ${teshsuite_src}                                                                 PARENT_SCOPE)
 
 foreach(x cmdline log_large parallel_log_crashtest parmap_test)
   ADD_TESH(tesh-xbt-${x} --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/xbt/${x} --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/xbt/${x} ${x}.tesh)
@@ -46,11 +36,3 @@ if(enable_debug)
 else()
   ADD_TESH(tesh-xbt-log --cd ${CMAKE_BINARY_DIR}/teshsuite/xbt/log_usage ${CMAKE_HOME_DIRECTORY}/teshsuite/xbt/log_usage/log_usage_ndebug.tesh)
 endif()
-
-if(HAVE_MMALLOC)
-  if(CMAKE_SIZEOF_VOID_P EQUAL 4) # 32 bits
-    ADD_TESH(tesh-xbt-mmalloc-32 --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/xbt/mmalloc --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/xbt/mmalloc mmalloc_32.tesh)
-  else()
-    ADD_TESH(tesh-xbt-mmalloc-64 --setenv bindir=${CMAKE_BINARY_DIR}/teshsuite/xbt/mmalloc --cd ${CMAKE_HOME_DIRECTORY}/teshsuite/xbt/mmalloc mmalloc_64.tesh)
-  endif()
-endif()
index 52c7828..01e9880 100644 (file)
@@ -6,9 +6,6 @@
 #include "simgrid/engine.h"
 #include <xbt.h>
 
-#define SIMIX_H_NO_DEPRECATED_WARNING // avoid deprecation warning on include (remove with XBT_ATTRIB_DEPRECATED_v335)
-#include "simgrid/simix.h" // we don't need it, but someone must check that this file is actually usable in plain C
-
 XBT_LOG_NEW_DEFAULT_CATEGORY(test, "Logging specific to this test");
 
 int main(int argc, char** argv)
diff --git a/teshsuite/xbt/mmalloc/mmalloc_32.tesh b/teshsuite/xbt/mmalloc/mmalloc_32.tesh
deleted file mode 100644 (file)
index 8bb9bac..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-$ ${bindir:=.}/mmalloc_test --log=root.fmt:%m%n
-> Allocating a new heap
-> HeapA allocated
-> 100 bytes allocated with offset 45000
-> 200 bytes allocated with offset 46000
-> 300 bytes allocated with offset 47000
-> 400 bytes allocated with offset 47200
-> 500 bytes allocated with offset 47400
-> 600 bytes allocated with offset 48000
-> 700 bytes allocated with offset 48400
-> 800 bytes allocated with offset 48800
-> 900 bytes allocated with offset 48c00
-> 1000 bytes allocated with offset 49000
-> 1100 bytes allocated with offset 4a000
-> 1200 bytes allocated with offset 4a800
-> 1300 bytes allocated with offset 4b000
-> 1400 bytes allocated with offset 4b800
-> 1500 bytes allocated with offset 4c000
-> 1600 bytes allocated with offset 4c800
-> 1700 bytes allocated with offset 4d000
-> 1800 bytes allocated with offset 4d800
-> 1900 bytes allocated with offset 4e000
-> 2000 bytes allocated with offset 4e800
-> 2100 bytes allocated with offset 4f000
-> 2200 bytes allocated with offset 50000
-> 2300 bytes allocated with offset 51000
-> 2400 bytes allocated with offset 52000
-> 2500 bytes allocated with offset 53000
-> 2600 bytes allocated with offset 54000
-> 2700 bytes allocated with offset 55000
-> 2800 bytes allocated with offset 56000
-> 2900 bytes allocated with offset 57000
-> 3000 bytes allocated with offset 58000
-> 3100 bytes allocated with offset 59000
-> 3200 bytes allocated with offset 5a000
-> 3300 bytes allocated with offset 5b000
-> 3400 bytes allocated with offset 5c000
-> 3500 bytes allocated with offset 5d000
-> 3600 bytes allocated with offset 5e000
-> 3700 bytes allocated with offset 5f000
-> 3800 bytes allocated with offset 60000
-> 3900 bytes allocated with offset 61000
-> 4000 bytes allocated with offset 62000
-> 4100 bytes allocated with offset 63000
-> 4200 bytes allocated with offset 65000
-> 4300 bytes allocated with offset 67000
-> 4400 bytes allocated with offset 69000
-> 4500 bytes allocated with offset 6b000
-> 4600 bytes allocated with offset 6d000
-> 4700 bytes allocated with offset 6f000
-> 4800 bytes allocated with offset 71000
-> 4900 bytes allocated with offset 73000
-> 5000 bytes allocated with offset 75000
-> 100 bytes allocated with offset 45080
-> 200 bytes allocated with offset 46100
-> 300 bytes allocated with offset 47600
-> 400 bytes allocated with offset 47800
-> 500 bytes allocated with offset 47a00
-> 600 bytes allocated with offset 49400
-> 700 bytes allocated with offset 49800
-> 800 bytes allocated with offset 49c00
-> 900 bytes allocated with offset 77000
-> 1000 bytes allocated with offset 77400
-> 1100 bytes allocated with offset 78000
-> 1200 bytes allocated with offset 78800
-> 1300 bytes allocated with offset 79000
-> 1400 bytes allocated with offset 79800
-> 1500 bytes allocated with offset 7a000
-> 1600 bytes allocated with offset 7a800
-> 1700 bytes allocated with offset 7b000
-> 1800 bytes allocated with offset 7b800
-> 1900 bytes allocated with offset 7c000
-> 2000 bytes allocated with offset 7c800
-> 2100 bytes allocated with offset 7d000
-> 2200 bytes allocated with offset 7e000
-> 2300 bytes allocated with offset 7f000
-> 2400 bytes allocated with offset 80000
-> 2500 bytes allocated with offset 81000
-> 2600 bytes allocated with offset 82000
-> 2700 bytes allocated with offset 83000
-> 2800 bytes allocated with offset 84000
-> 2900 bytes allocated with offset 85000
-> 3000 bytes allocated with offset 86000
-> 3100 bytes allocated with offset 87000
-> 3200 bytes allocated with offset 88000
-> 3300 bytes allocated with offset 89000
-> 3400 bytes allocated with offset 8a000
-> 3500 bytes allocated with offset 8b000
-> 3600 bytes allocated with offset 8c000
-> 3700 bytes allocated with offset 8d000
-> 3800 bytes allocated with offset 8e000
-> 3900 bytes allocated with offset 8f000
-> 4000 bytes allocated with offset 90000
-> 4100 bytes allocated with offset 91000
-> 4200 bytes allocated with offset 93000
-> 4300 bytes allocated with offset 95000
-> 4400 bytes allocated with offset 97000
-> 4500 bytes allocated with offset 99000
-> 4600 bytes allocated with offset 9b000
-> 4700 bytes allocated with offset 9d000
-> 4800 bytes allocated with offset 9f000
-> 4900 bytes allocated with offset a1000
-> 5000 bytes allocated with offset a3000
-> All blocks were correctly allocated. Free every second block
-> Memset every second block to zero (yeah, they are not currently allocated :)
-> Re-allocate every second block
-> free all blocks
-> Let's try different codepaths for mrealloc
-> Damnit, I cannot break mmalloc this time. That's SO disappointing.
diff --git a/teshsuite/xbt/mmalloc/mmalloc_64.tesh b/teshsuite/xbt/mmalloc/mmalloc_64.tesh
deleted file mode 100644 (file)
index ec276c3..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-$ ${bindir:=.}/mmalloc_test --log=root.fmt:%m%n
-> Allocating a new heap
-> HeapA allocated
-> 100 bytes allocated with offset 39000
-> 200 bytes allocated with offset 39100
-> 300 bytes allocated with offset 3a000
-> 400 bytes allocated with offset 3a200
-> 500 bytes allocated with offset 3a400
-> 600 bytes allocated with offset 3b000
-> 700 bytes allocated with offset 3b400
-> 800 bytes allocated with offset 3b800
-> 900 bytes allocated with offset 3bc00
-> 1000 bytes allocated with offset 3c000
-> 1100 bytes allocated with offset 3d000
-> 1200 bytes allocated with offset 3d800
-> 1300 bytes allocated with offset 3e000
-> 1400 bytes allocated with offset 3e800
-> 1500 bytes allocated with offset 3f000
-> 1600 bytes allocated with offset 3f800
-> 1700 bytes allocated with offset 40000
-> 1800 bytes allocated with offset 40800
-> 1900 bytes allocated with offset 41000
-> 2000 bytes allocated with offset 41800
-> 2100 bytes allocated with offset 42000
-> 2200 bytes allocated with offset 43000
-> 2300 bytes allocated with offset 44000
-> 2400 bytes allocated with offset 45000
-> 2500 bytes allocated with offset 46000
-> 2600 bytes allocated with offset 47000
-> 2700 bytes allocated with offset 48000
-> 2800 bytes allocated with offset 49000
-> 2900 bytes allocated with offset 4a000
-> 3000 bytes allocated with offset 4b000
-> 3100 bytes allocated with offset 4c000
-> 3200 bytes allocated with offset 4d000
-> 3300 bytes allocated with offset 4e000
-> 3400 bytes allocated with offset 4f000
-> 3500 bytes allocated with offset 50000
-> 3600 bytes allocated with offset 51000
-> 3700 bytes allocated with offset 52000
-> 3800 bytes allocated with offset 53000
-> 3900 bytes allocated with offset 54000
-> 4000 bytes allocated with offset 55000
-> 4100 bytes allocated with offset 56000
-> 4200 bytes allocated with offset 58000
-> 4300 bytes allocated with offset 5a000
-> 4400 bytes allocated with offset 5c000
-> 4500 bytes allocated with offset 5e000
-> 4600 bytes allocated with offset 60000
-> 4700 bytes allocated with offset 62000
-> 4800 bytes allocated with offset 64000
-> 4900 bytes allocated with offset 66000
-> 5000 bytes allocated with offset 68000
-> 100 bytes allocated with offset 39200
-> 200 bytes allocated with offset 39300
-> 300 bytes allocated with offset 3a600
-> 400 bytes allocated with offset 3a800
-> 500 bytes allocated with offset 3aa00
-> 600 bytes allocated with offset 3c400
-> 700 bytes allocated with offset 3c800
-> 800 bytes allocated with offset 3cc00
-> 900 bytes allocated with offset 6a000
-> 1000 bytes allocated with offset 6a400
-> 1100 bytes allocated with offset 6b000
-> 1200 bytes allocated with offset 6b800
-> 1300 bytes allocated with offset 6c000
-> 1400 bytes allocated with offset 6c800
-> 1500 bytes allocated with offset 6d000
-> 1600 bytes allocated with offset 6d800
-> 1700 bytes allocated with offset 6e000
-> 1800 bytes allocated with offset 6e800
-> 1900 bytes allocated with offset 6f000
-> 2000 bytes allocated with offset 6f800
-> 2100 bytes allocated with offset 70000
-> 2200 bytes allocated with offset 71000
-> 2300 bytes allocated with offset 72000
-> 2400 bytes allocated with offset 73000
-> 2500 bytes allocated with offset 74000
-> 2600 bytes allocated with offset 75000
-> 2700 bytes allocated with offset 76000
-> 2800 bytes allocated with offset 77000
-> 2900 bytes allocated with offset 78000
-> 3000 bytes allocated with offset 79000
-> 3100 bytes allocated with offset 7a000
-> 3200 bytes allocated with offset 7b000
-> 3300 bytes allocated with offset 7c000
-> 3400 bytes allocated with offset 7d000
-> 3500 bytes allocated with offset 7e000
-> 3600 bytes allocated with offset 7f000
-> 3700 bytes allocated with offset 80000
-> 3800 bytes allocated with offset 81000
-> 3900 bytes allocated with offset 82000
-> 4000 bytes allocated with offset 83000
-> 4100 bytes allocated with offset 84000
-> 4200 bytes allocated with offset 86000
-> 4300 bytes allocated with offset 88000
-> 4400 bytes allocated with offset 8a000
-> 4500 bytes allocated with offset 8c000
-> 4600 bytes allocated with offset 8e000
-> 4700 bytes allocated with offset 90000
-> 4800 bytes allocated with offset 92000
-> 4900 bytes allocated with offset 94000
-> 5000 bytes allocated with offset 96000
-> All blocks were correctly allocated. Free every second block
-> Memset every second block to zero (yeah, they are not currently allocated :)
-> Re-allocate every second block
-> free all blocks
-> Let's try different codepaths for mrealloc
-> Damnit, I cannot break mmalloc this time. That's SO disappointing.
diff --git a/teshsuite/xbt/mmalloc/mmalloc_test.cpp b/teshsuite/xbt/mmalloc/mmalloc_test.cpp
deleted file mode 100644 (file)
index c76ea46..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Copyright (c) 2012-2023. The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-#include "simgrid/Exception.hpp"
-#include "simgrid/engine.h"
-#include "src/xbt/mmalloc/mmalloc.h"
-#include "xbt.h"
-
-#include <array>
-#include <cassert>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <vector>
-
-XBT_LOG_NEW_DEFAULT_CATEGORY(test,"this test");
-
-constexpr int BUFFSIZE = 204800;
-constexpr int TESTSIZE = 100;
-
-#define size_of_block(i) ((((i) % 50) + 1) * 100)
-
-static void check_block(const unsigned char* p, unsigned char b, int n)
-{
-  for (int i = 0; i < n; i++)
-    xbt_assert(p[i] == b, "value mismatch: %p[%d] = %#hhx, expected %#hhx", p, i, p[i], b);
-}
-
-int main(int argc, char**argv)
-{
-  xbt_mheap_t heapA = nullptr;
-  std::array<void*, TESTSIZE> pointers;
-  simgrid_init(&argc, argv);
-
-  XBT_INFO("Allocating a new heap");
-  unsigned long mask = ~((unsigned long)xbt_pagesize - 1);
-  auto* addr         = reinterpret_cast<void*>(((unsigned long)sbrk(0) + BUFFSIZE) & mask);
-  heapA              = xbt_mheap_new(addr, 0);
-  if (heapA == nullptr) {
-    perror("attach 1 failed");
-    fprintf(stderr, "bye\n");
-    exit(1);
-  }
-
-  XBT_INFO("HeapA allocated");
-
-  int i;
-  int size;
-  for (i = 0; i < TESTSIZE; i++) {
-    size = size_of_block(i);
-    pointers[i] = mmalloc(heapA, size);
-    XBT_INFO("%d bytes allocated with offset %zx", size, (size_t)((char*)pointers[i] - (char*)heapA));
-  }
-  XBT_INFO("All blocks were correctly allocated. Free every second block");
-  for (i = 0; i < TESTSIZE; i+=2) {
-    mfree(heapA, pointers[i]);
-  }
-  XBT_INFO("Memset every second block to zero (yeah, they are not currently allocated :)");
-  for (i = 0; i < TESTSIZE; i+=2) {
-    size = size_of_block(i);
-    memset(pointers[i],0, size);
-  }
-  XBT_INFO("Re-allocate every second block");
-  for (i = 0; i < TESTSIZE; i+=2) {
-    size = size_of_block(i);
-    pointers[i] = mmalloc(heapA, size);
-  }
-
-  XBT_INFO("free all blocks");
-  for (i = 0; i < TESTSIZE; i++)
-    mfree(heapA, pointers[i]);
-
-  XBT_INFO("Let's try different codepaths for mrealloc");
-  for (i = 0; i < TESTSIZE; i++) {
-    const std::vector<std::pair<int, unsigned char>> requests = {
-        {size_of_block(i) / 2, 0x77}, {size_of_block(i) * 2, 0xaa}, {1, 0xc0}, {0, 0}};
-    pointers[i] = nullptr;
-    for (unsigned k = 0; k < requests.size(); ++k) {
-      size        = requests[k].first;
-      pointers[i] = mrealloc(heapA, pointers[i], size);
-      if (k > 0)
-        check_block(static_cast<unsigned char*>(pointers[i]), requests[k - 1].second,
-                    std::min(size, requests[k - 1].first));
-      if (size > 0)
-        memset(pointers[i], requests[k].second, size);
-    }
-  }
-
-  XBT_INFO("Damnit, I cannot break mmalloc this time. That's SO disappointing.");
-  return 0;
-}
index 02b1cdf..a0c1676 100644 (file)
@@ -11,29 +11,29 @@ static void worker()
 {
   simgrid::s4u::Host* other_host = simgrid::s4u::Host::by_name("Fafard");
   unsigned int first =
-      simgrid::s4u::Host::on_state_change.connect([](simgrid::s4u::Host const&) { XBT_INFO("First callback"); });
+      simgrid::s4u::Host::on_onoff.connect([](simgrid::s4u::Host const&) { XBT_INFO("First callback"); });
   unsigned int second =
-      simgrid::s4u::Host::on_state_change.connect([](simgrid::s4u::Host const&) { XBT_INFO("Second callback"); });
+      simgrid::s4u::Host::on_onoff.connect([](simgrid::s4u::Host const&) { XBT_INFO("Second callback"); });
   unsigned int third =
-      simgrid::s4u::Host::on_state_change.connect([](simgrid::s4u::Host const&) { XBT_INFO("Third callback"); });
+      simgrid::s4u::Host::on_onoff.connect([](simgrid::s4u::Host const&) { XBT_INFO("Third callback"); });
 
   XBT_INFO("Turning off: Three callbacks should be triggered");
   other_host->turn_off();
 
   XBT_INFO("Disconnect the second callback");
-  simgrid::s4u::Host::on_state_change.disconnect(second);
+  simgrid::s4u::Host::on_onoff.disconnect(second);
 
   XBT_INFO("Turning on: Two callbacks should be triggered");
   other_host->turn_on();
 
   XBT_INFO("Disconnect the first callback");
-  simgrid::s4u::Host::on_state_change.disconnect(first);
+  simgrid::s4u::Host::on_onoff.disconnect(first);
 
   XBT_INFO("Turning off: One callback should be triggered");
   other_host->turn_off();
 
   XBT_INFO("Disconnect the third callback");
-  simgrid::s4u::Host::on_state_change.disconnect(third);
+  simgrid::s4u::Host::on_onoff.disconnect(third);
   XBT_INFO("Turning on: No more callbacks");
   other_host->turn_on();
 }
index d07dcdd..591f664 100644 (file)
@@ -1,5 +1,4 @@
 set(bin_files ${bin_files}    ${CMAKE_CURRENT_SOURCE_DIR}/fix-paje-trace.sh
-                              ${CMAKE_CURRENT_SOURCE_DIR}/generate-dwarf-functions
                               ${CMAKE_CURRENT_SOURCE_DIR}/normalize-pointers.py
                               ${CMAKE_CURRENT_SOURCE_DIR}/sg_xml_unit_converter.py
                               ${CMAKE_CURRENT_SOURCE_DIR}/simgrid_update_xml.pl
index e7ca165..f478e89 100644 (file)
@@ -25,3 +25,16 @@ odr_violation:^stored_vtable$
 odr_violation:^cfg_bmf_max_iteration$
 # size=40 'cfg_bmf_precision' ../src/kernel/lmm/bmf.hpp:80:47
 odr_violation:^cfg_bmf_precision$
+
+# size=56 'on_completion' ../include/simgrid/s4u/Activity.hpp:235:55
+odr_violation:^on_completion$
+# size=56 'on_veto' ../include/simgrid/s4u/Activity.hpp:236:49
+odr_violation:^on_veto$
+# size=56 'on_suspend' ../include/simgrid/s4u/Activity.hpp:237:55
+odr_violation:^on_suspend$
+# size=56 'on_resume' ../include/simgrid/s4u/Activity.hpp:238:55
+odr_violation:^on_resume$
+
+# size=56 'on_start' ../include/simgrid/s4u/Comm.hpp:45:48
+# size=56 'on_start' ../include/simgrid/s4u/Exec.hpp:45:48
+odr_violation:^on_start$
index 53e2835..f1723c8 100644 (file)
@@ -17,10 +17,6 @@ if(enable_compile_warnings AND enable_compile_optimizations)
   SET(BUILDNAME "FULL_FLAGS" CACHE INTERNAL "Buildname" FORCE)
 endif()
 
-if(SIMGRID_HAVE_MC)
-  SET(BUILDNAME "MODEL-CHECKING" CACHE INTERNAL "Buildname" FORCE)
-endif()
-
 if(enable_memcheck)
   SET(BUILDNAME "MEMCHECK" CACHE INTERNAL "Buildname" FORCE)
 endif()
index 6cc2d4c..06c190e 100644 (file)
@@ -2,7 +2,6 @@
 
 set(EXTRA_DIST
   src/3rd-party/catch.hpp
-  src/3rd-party/xxhash.hpp
   src/bindings/python/simgrid_python.cpp
   src/dag/dax.dtd
   src/dag/dax_dtd.c
@@ -25,7 +24,7 @@ set(EXTRA_DIST
   src/kernel/resource/models/network_ns3.hpp
   src/kernel/resource/models/ns3/ns3_simulator.hpp
   src/kernel/resource/models/ptask_L07.hpp
-  
+
   src/mc/datatypes.h
   src/mc/mc.h
   src/mc/mc_mmu.hpp
@@ -46,29 +45,11 @@ set(EXTRA_DIST
   src/kernel/xml/simgrid_dtd.h
   src/kernel/xml/platf_sax_cb.cpp
 
-  src/xbt/automaton/automaton_lexer.yy.c
-  src/xbt/automaton/parserPromela.lex
-  src/xbt/automaton/parserPromela.tab.cacc
-  src/xbt/automaton/parserPromela.tab.hacc
-  src/xbt/automaton/parserPromela.yacc
   src/xbt/coverage.h
   src/xbt/dict_private.h
   src/xbt/log_private.hpp
   src/xbt/mallocator_private.h
   src/xbt/parmap.hpp
-  
-  src/xbt/mmalloc/mmalloc.h
-  src/xbt/mmalloc/mfree.c
-  src/xbt/mmalloc/mm_legacy.c
-  src/xbt/mmalloc/mm_module.c
-  src/xbt/mmalloc/mmalloc.c
-  src/xbt/mmalloc/mmalloc.info
-  src/xbt/mmalloc/mmalloc.texi
-  src/xbt/mmalloc/mmorecore.c
-  src/xbt/mmalloc/mmprivate.h
-  src/xbt/mmalloc/mrealloc.c
-  src/xbt/mmalloc/swag.c
-  src/xbt/mmalloc/swag.h
   )
 
 set(SMPI_SRC
@@ -257,8 +238,6 @@ set(STHREAD_SRC
 set(XBT_SRC
   src/xbt/OsSemaphore.hpp
   src/xbt/PropertyHolder.cpp
-  src/xbt/automaton/automaton.c
-  src/xbt/automaton/automatonparse_promela.c
   src/xbt/backtrace.cpp
   src/xbt/config.cpp
   src/xbt/dict.cpp
@@ -292,21 +271,12 @@ set(XBT_SRC
   src/xbt/utils/iter/LazyPowerset.hpp
   )
 
-if(HAVE_MMALLOC)
-  set(SGMALLOC_SRC src/xbt/mmalloc/mm.c)
-  set(XBT_SRC      ${XBT_SRC} src/xbt/mmalloc/mm.c)
-else()
-  set(EXTRA_DIST ${EXTRA_DIST} src/xbt/mmalloc/mm.c)
-endif()
-
 set(NS3_SRC
   src/kernel/resource/models/network_ns3.cpp
   src/kernel/resource/models/ns3/ns3_simulator.cpp
   )
 
 set(KERNEL_SRC
-  src/deprecated.cpp
-
   src/kernel/EngineImpl.cpp
   src/kernel/EngineImpl.hpp
 
@@ -324,6 +294,10 @@ set(KERNEL_SRC
   src/kernel/activity/IoImpl.hpp
   src/kernel/activity/MailboxImpl.cpp
   src/kernel/activity/MailboxImpl.hpp
+  src/kernel/activity/MessImpl.cpp
+  src/kernel/activity/MessImpl.hpp
+  src/kernel/activity/MessageQueueImpl.cpp
+  src/kernel/activity/MessageQueueImpl.hpp
   src/kernel/activity/MutexImpl.cpp
   src/kernel/activity/MutexImpl.hpp
   src/kernel/activity/SemaphoreImpl.cpp
@@ -342,7 +316,7 @@ set(KERNEL_SRC
   src/kernel/actor/SimcallObserver.hpp
   src/kernel/actor/SynchroObserver.cpp
   src/kernel/actor/SynchroObserver.hpp
-  
+
   src/kernel/context/Context.cpp
   src/kernel/context/Context.hpp
   src/kernel/context/ContextRaw.cpp
@@ -447,17 +421,22 @@ set(PLUGINS_SRC
   src/plugins/host_dvfs.cpp
   src/plugins/host_energy.cpp
   src/plugins/host_load.cpp
+  src/plugins/jbod.cpp
   src/plugins/link_energy.cpp
   src/plugins/link_energy_wifi.cpp
   src/plugins/link_load.cpp
   src/plugins/vm/VmLiveMigration.cpp
   src/plugins/vm/VmLiveMigration.hpp
   src/plugins/vm/dirty_page_tracking.cpp
+  src/plugins/battery.cpp
+  src/plugins/chiller.cpp
+  src/plugins/solar_panel.cpp
   )
 
 
 set(S4U_SRC
   src/s4u/s4u_Activity.cpp
+  src/s4u/s4u_ActivitySet.cpp
   src/s4u/s4u_Actor.cpp
   src/s4u/s4u_Barrier.cpp
   src/s4u/s4u_Comm.cpp
@@ -469,9 +448,12 @@ set(S4U_SRC
   src/s4u/s4u_Io.cpp
   src/s4u/s4u_Link.cpp
   src/s4u/s4u_Mailbox.cpp
+  src/s4u/s4u_Mess.cpp
+  src/s4u/s4u_MessageQueue.cpp
   src/s4u/s4u_Mutex.cpp
   src/s4u/s4u_Netzone.cpp
   src/s4u/s4u_Semaphore.cpp
+  src/s4u/s4u_Task.cpp
   src/s4u/s4u_VirtualMachine.cpp
 )
 
@@ -519,22 +501,31 @@ set(MC_SRC_BASE
   src/mc/transition/Transition.cpp
   )
 
-set(MC_SRC
-  src/mc/explo/CommunicationDeterminismChecker.cpp
+set(MC_SRC_STATELESS
+  src/mc/api/ActorState.hpp
+  src/mc/api/ClockVector.cpp
+  src/mc/api/ClockVector.hpp
+  src/mc/api/State.cpp
+  src/mc/api/State.hpp
+  src/mc/api/RemoteApp.cpp
+  src/mc/api/RemoteApp.hpp
+
   src/mc/explo/DFSExplorer.cpp
   src/mc/explo/DFSExplorer.hpp
   src/mc/explo/Exploration.cpp
   src/mc/explo/Exploration.hpp
-  src/mc/explo/LivenessChecker.cpp
-  src/mc/explo/LivenessChecker.hpp
+  src/mc/explo/CommunicationDeterminismChecker.cpp
+
   src/mc/explo/UdporChecker.cpp
   src/mc/explo/UdporChecker.hpp
-  
+
   src/mc/explo/udpor/Comb.hpp
   src/mc/explo/udpor/Configuration.hpp
   src/mc/explo/udpor/Configuration.cpp
   src/mc/explo/udpor/EventSet.cpp
   src/mc/explo/udpor/EventSet.hpp
+  src/mc/explo/udpor/ExtensionSetCalculator.cpp
+  src/mc/explo/udpor/ExtensionSetCalculator.hpp
   src/mc/explo/udpor/History.cpp
   src/mc/explo/udpor/History.hpp
   src/mc/explo/udpor/maximal_subsets_iterator.cpp
@@ -545,25 +536,15 @@ set(MC_SRC
   src/mc/explo/udpor/Unfolding.hpp
   src/mc/explo/udpor/udpor_forward.hpp
   src/mc/explo/udpor/udpor_tests_private.hpp
-  
-  src/mc/inspect/DwarfExpression.cpp
-  src/mc/inspect/DwarfExpression.hpp
-  src/mc/inspect/Frame.cpp
-  src/mc/inspect/Frame.hpp
-  src/mc/inspect/LocationList.cpp
-  src/mc/inspect/LocationList.hpp
-  src/mc/inspect/ObjectInformation.cpp
-  src/mc/inspect/ObjectInformation.hpp
-  src/mc/inspect/Type.hpp
-  src/mc/inspect/Variable.hpp
-  src/mc/inspect/mc_dwarf.cpp
-  src/mc/inspect/mc_dwarf.hpp
-  src/mc/inspect/mc_dwarf_attrnames.cpp
-  src/mc/inspect/mc_dwarf_tagnames.cpp
-  src/mc/inspect/mc_member.cpp
-  src/mc/inspect/mc_unw.cpp
-  src/mc/inspect/mc_unw.hpp
-  src/mc/inspect/mc_unw_vmread.cpp
+
+  src/mc/explo/odpor/Execution.cpp
+  src/mc/explo/odpor/Execution.hpp
+  src/mc/explo/odpor/WakeupTree.cpp
+  src/mc/explo/odpor/WakeupTree.hpp
+  src/mc/explo/odpor/WakeupTreeIterator.cpp
+  src/mc/explo/odpor/WakeupTreeIterator.hpp
+  src/mc/explo/odpor/odpor_forward.hpp
+  src/mc/explo/odpor/odpor_tests_private.hpp
 
   src/mc/remote/AppSide.cpp
   src/mc/remote/AppSide.hpp
@@ -573,21 +554,10 @@ set(MC_SRC
   src/mc/remote/CheckerSide.hpp
   src/mc/remote/RemotePtr.hpp
   src/mc/remote/mc_protocol.h
-  
-  src/mc/sosp/ChunkedData.cpp
-  src/mc/sosp/ChunkedData.hpp
-  src/mc/sosp/PageStore.cpp
-  src/mc/sosp/PageStore.hpp
-  src/mc/sosp/Region.cpp
-  src/mc/sosp/Region.hpp
-  src/mc/sosp/RemoteProcessMemory.cpp
-  src/mc/sosp/RemoteProcessMemory.hpp
-  src/mc/sosp/Snapshot.cpp
-  src/mc/sosp/Snapshot.hpp
 
   src/mc/transition/Transition.hpp
-  src/mc/transition/TransitionActorJoin.cpp
-  src/mc/transition/TransitionActorJoin.hpp
+  src/mc/transition/TransitionActor.cpp
+  src/mc/transition/TransitionActor.hpp
   src/mc/transition/TransitionAny.cpp
   src/mc/transition/TransitionAny.hpp
   src/mc/transition/TransitionComm.cpp
@@ -599,47 +569,44 @@ set(MC_SRC
   src/mc/transition/TransitionSynchro.cpp
   src/mc/transition/TransitionSynchro.hpp
 
-  src/mc/api/guide/BasicGuide.hpp
-  src/mc/api/guide/GuidedState.hpp
-  src/mc/api/ActorState.hpp
-  src/mc/api/State.cpp
-  src/mc/api/State.hpp
-  src/mc/api/RemoteApp.cpp
-  src/mc/api/RemoteApp.hpp
-
-  src/mc/AddressSpace.hpp
-  src/mc/VisitedState.cpp
-  src/mc/VisitedState.hpp
-  src/mc/compare.cpp
+  src/mc/mc_environ.h
   src/mc/mc_exit.hpp
   src/mc/mc_forward.hpp
   src/mc/mc_private.hpp
   src/mc/mc_record.cpp
 
-  src/xbt/mmalloc/mm_interface.c
+  src/mc/api/strategy/BasicStrategy.hpp
+  src/mc/api/strategy/MaxMatchComm.hpp
+  src/mc/api/strategy/MinMatchComm.hpp
+  src/mc/api/strategy/Strategy.hpp
+  src/mc/api/strategy/UniformStrategy.hpp
   )
 
 set(MC_SIMGRID_MC_SRC  src/mc/explo/simgrid_mc.cpp)
 
 set(headers_to_install
   include/simgrid/actor.h
+  include/simgrid/activity_set.h
   include/simgrid/barrier.h
   include/simgrid/comm.h
   include/simgrid/engine.h
   include/simgrid/exec.h
   include/simgrid/Exception.hpp
   include/simgrid/chrono.hpp
+  include/simgrid/plugins/battery.hpp
+  include/simgrid/plugins/chiller.hpp
   include/simgrid/plugins/dvfs.h
   include/simgrid/plugins/energy.h
   include/simgrid/plugins/file_system.h
+  include/simgrid/plugins/jbod.hpp
   include/simgrid/plugins/live_migration.h
   include/simgrid/plugins/load.h
+  include/simgrid/plugins/solar_panel.hpp
   include/simgrid/plugins/ProducerConsumer.hpp
   include/simgrid/instr.h
   include/simgrid/mailbox.h
   include/simgrid/modelchecker.h
   include/simgrid/forward.h
-  include/simgrid/simix.h
   include/simgrid/simix.hpp
   include/simgrid/kernel/ProfileBuilder.hpp
   include/simgrid/kernel/Timer.hpp
@@ -652,6 +619,7 @@ set(headers_to_install
   include/simgrid/vm.h
   include/simgrid/zone.h
   include/simgrid/s4u/Activity.hpp
+  include/simgrid/s4u/ActivitySet.hpp
   include/simgrid/s4u/Actor.hpp
   include/simgrid/s4u/Barrier.hpp
   include/simgrid/s4u/Comm.hpp
@@ -663,9 +631,12 @@ set(headers_to_install
   include/simgrid/s4u/Io.hpp
   include/simgrid/s4u/Link.hpp
   include/simgrid/s4u/Mailbox.hpp
+  include/simgrid/s4u/MessageQueue.hpp
+  include/simgrid/s4u/Mess.hpp
   include/simgrid/s4u/Mutex.hpp
   include/simgrid/s4u/NetZone.hpp
   include/simgrid/s4u/Semaphore.hpp
+  include/simgrid/s4u/Task.hpp
   include/simgrid/s4u/VirtualMachine.hpp
   include/simgrid/s4u.hpp
 
@@ -698,8 +669,6 @@ set(headers_to_install
   include/xbt.h
   include/xbt/asserts.h
   include/xbt/asserts.hpp
-  include/xbt/automaton.h
-  include/xbt/automaton.hpp
   include/xbt/backtrace.hpp
   include/xbt/base.h
   include/xbt/config.h
@@ -748,7 +717,7 @@ else() # NOT ucontext
                                 src/kernel/context/ContextUnix.cpp)
 endif()
 
-### Simgrid Lib sources
+### SimGrid Lib sources
 set(simgrid_sources
   ${S4U_SRC}
   ${SIMGRID_SRC}
@@ -765,8 +734,9 @@ if(enable_smpi)
 endif()
 
 if(SIMGRID_HAVE_MC)
-  set(simgrid_sources  ${simgrid_sources}  ${MC_SRC})
+  set(simgrid_sources  ${simgrid_sources}  ${MC_SRC_STATELESS})
 endif()
+set(EXTRA_DIST ${EXTRA_DIST} ${MC_SRC_STATELESS})
 
 if(SIMGRID_HAVE_NS3)
   set(headers_to_install ${headers_to_install} include/simgrid/plugins/ns3.hpp)
@@ -874,17 +844,10 @@ set(DOC_SOURCES
   docs/source/tuto_s4u/master-workers-lab4.cpp
 
   docs/source/Tutorial_DAG.rst
-  docs/source/tuto_dag/dag_lab1.cpp
-  docs/source/tuto_dag/dag_lab2-1.cpp
-  docs/source/tuto_dag/dag_lab2-2.cpp
-  docs/source/tuto_dag/dag_lab2-3.cpp
-  docs/source/tuto_dag/img/dag1.svg
-  docs/source/tuto_dag/img/dag2.svg
-  docs/source/tuto_dag/img/dag.svg
-  docs/source/tuto_dag/simple_dax.xml
-  docs/source/tuto_dag/simple_dot.dot
-  docs/source/tuto_dag/simple_json.json
-  docs/source/tuto_dag/small_platform.xml
+  docs/source/img/battery_degradation.svg
+  docs/source/img/dag1.svg
+  docs/source/img/dag2.svg
+  docs/source/img/dag.svg
 
   docs/source/Tutorial_MPI_Applications.rst
   docs/source/tuto_smpi/3hosts.png
@@ -1045,10 +1008,7 @@ set(CMAKE_SOURCE_FILES
   tools/cmake/MaintainerMode.cmake
   tools/cmake/MakeLib.cmake
   tools/cmake/Modules/FindGraphviz.cmake
-  tools/cmake/Modules/FindLibdw.cmake
-  tools/cmake/Modules/FindLibelf.cmake
   tools/cmake/Modules/FindLibevent.cmake
-  tools/cmake/Modules/FindLibunwind.cmake
   tools/cmake/Modules/FindNS3.cmake
   tools/cmake/Modules/FindPAPI.cmake
   tools/cmake/Modules/FindValgrind.cmake
@@ -1061,6 +1021,7 @@ set(CMAKE_SOURCE_FILES
   tools/cmake/scripts/update_tesh.pl
   tools/cmake/test_prog/prog_asan.cpp
   tools/cmake/test_prog/prog_makecontext.c
+  tools/cmake/test_prog/prog_ns3.cpp
   tools/cmake/test_prog/prog_stackgrowth.c
   tools/cmake/test_prog/prog_stacksetup.c
   tools/cmake/test_prog/prog_tsan.cpp
@@ -1157,13 +1118,3 @@ set(PLATFORMS_EXAMPLES
   examples/platforms/wifi_large_cell.xml
   examples/platforms/wifi_ns3.xml
   )
-
-set(generated_src_files
-  src/xbt/automaton/automaton_lexer.yy.c
-  src/xbt/automaton/parserPromela.tab.cacc
-  src/xbt/automaton/parserPromela.tab.hacc
-  )
-
-foreach(file ${generated_src_files})
-  set_source_files_properties(${file} PROPERTIES GENERATED true)
-endforeach(file ${generated_src_files})
index 10fddaf..5095296 100644 (file)
@@ -43,6 +43,9 @@ add_custom_target(simgrid_convert_TI_traces ALL
 
 # libraries
 install(TARGETS simgrid DESTINATION ${CMAKE_INSTALL_LIBDIR}/)
+if("${CMAKE_SYSTEM}" MATCHES "Linux")
+  install(TARGETS sthread DESTINATION ${CMAKE_INSTALL_LIBDIR}/)
+endif()
 
 # pkg-config files
 configure_file("${CMAKE_HOME_DIRECTORY}/tools/pkg-config/simgrid.pc.in"
@@ -211,10 +214,13 @@ add_dependencies(dist dist-dir)
 set(CMAKE_BINARY_TEST_DIR ${CMAKE_BINARY_DIR})
 
 # Allow to test the "make dist"
-add_custom_target(distcheck
+add_custom_target(distcheck-archive
   COMMAND ${CMAKE_COMMAND} -E echo "XXX Compare archive with git repository"
   COMMAND ${CMAKE_HOME_DIRECTORY}/tools/internal/check_dist_archive -batch ${CMAKE_BINARY_TEST_DIR}/${PROJECT_NAME}-${release_version}.tar.gz
+  )
+add_dependencies(distcheck-archive dist)
 
+add_custom_target(distcheck-configure
   COMMAND ${CMAKE_COMMAND} -E echo "XXX Remove old copy"
   COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_TEST_DIR}/${PROJECT_NAME}-${release_version}
 
@@ -231,7 +237,10 @@ add_custom_target(distcheck
 
   COMMAND ${CMAKE_COMMAND} -E echo "XXX Check generated files -- please copy new version if they are different"
   COMMAND ${CMAKE_COMMAND} -E compare_files ${CMAKE_HOME_DIRECTORY}/MANIFEST.in ${CMAKE_BINARY_TEST_DIR}/${PROJECT_NAME}-${release_version}/_build/MANIFEST.in
+  )
+add_dependencies(distcheck-configure distcheck-archive)
 
+add_custom_target(distcheck
   COMMAND ${CMAKE_COMMAND} -E echo "XXX Build"
   COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_TEST_DIR}/${PROJECT_NAME}-${release_version}/_build ${CMAKE_MAKE_PROGRAM} -j 4
 
@@ -247,7 +256,7 @@ add_custom_target(distcheck
   COMMAND ${CMAKE_COMMAND} -E echo "XXX Remove temp directories"
   COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_TEST_DIR}/${PROJECT_NAME}-${release_version}
   )
-add_dependencies(distcheck dist)
+add_dependencies(distcheck distcheck-configure)
 
 #######################################
 ### Fill in the "make check" target ###
index 60aeeca..21213be 100644 (file)
@@ -1,7 +1,7 @@
 ##
 ## This file is in charge of setting our paranoid flags with regard to warnings and optimization.
 ##
-##   It is only used for gcc and clang. MSVC builds don't load this file.
+##   It is only used for gcc, clang and Intel compilers.
 ##
 ##   These flags do break some classical CMake tests, so you don't
 ##   want to do so before the very end of the configuration.
@@ -41,6 +41,10 @@ if(enable_compile_warnings)
       # workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81767
       set(warnCXXFLAGS "${warnCXXFLAGS} -Wno-error=unused-variable")
     endif()
+    if (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "13.2.0")
+      # workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101361
+      set(warnCXXFLAGS "${warnCXXFLAGS} -Wno-error=stringop-overread -Wno-error=stringop-overflow")
+    endif()
   endif()
 
   if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
@@ -77,13 +81,12 @@ if(enable_compile_warnings AND enable_debug)
 endif()
 
 # Activate the warnings on #if FOOBAR when FOOBAR has no value
-# It breaks on FreeBSD within Boost headers, so activate this only in Pure Hardcore debug mode.
-if(enable_maintainer_mode)
+if("${CMAKE_SYSTEM}" MATCHES "Linux") # Breaks on FreeBSD within Boost headers :(
   set(warnCFLAGS "${warnCFLAGS} -Wundef")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wundef")
 endif()
 
-# Se the optimisation flags
+# Set the optimisation flags
 # NOTE, we should CMAKE_BUILD_TYPE for this
 if(enable_compile_optimizations)
   set(optCFLAGS "-O3 -funroll-loops -fno-strict-aliasing ")
@@ -91,13 +94,12 @@ else()
   set(optCFLAGS "-O0 ")
 endif()
 
-#ARM platforms have signed char by default, switch to unsigned for consistancy
+# ARM platforms have signed char by default, switch to unsigned for consistancy
 if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
   set(optCFLAGS "${optCFLAGS} -fsigned-char")
 endif()
 
-if(enable_compile_optimizations AND CMAKE_COMPILER_IS_GNUCC
-    AND (NOT enable_model-checking))
+if(enable_compile_optimizations AND CMAKE_COMPILER_IS_GNUCC)
   # This is redundant (already in -03):
   set(optCFLAGS "${optCFLAGS} -finline-functions ")
 endif()
@@ -120,8 +122,7 @@ endif()
 # Configure LTO
 if(enable_lto) # User wants LTO. Try if we can do that
   set(enable_lto OFF)
-  if(enable_compile_optimizations
-      AND (NOT enable_model-checking))
+  if(enable_compile_optimizations)
     include(CheckIPOSupported)
     check_ipo_supported(RESULT ipo LANGUAGES C CXX)
     if(ipo)
@@ -135,11 +136,7 @@ if(enable_lto) # User wants LTO. Try if we can do that
     if(NOT enable_compile_optimizations)
       message(STATUS "LTO disabled: Compile-time optimizations turned off.")
     else()
-      if(enable_model-checking)
-        message(STATUS "LTO disabled when compiling with model-checking.")
-      else()
-        message(STATUS "LTO does not seem usable -- try updating your build chain.")
-      endif()
+      message(STATUS "LTO does not seem usable -- try updating your build chain.")
     endif()
   endif()
 else()
@@ -172,25 +169,6 @@ if(enable_lto) # User wants LTO, and it seems usable. Go for it
   endif()
 endif()
 
-if(enable_model-checking AND enable_compile_optimizations)
-  # Forget it, do not optimize the code (because it confuses the MC):
-  set(optCFLAGS "-O0")
-  # But you can still optimize this:
-  set(src_list ${simgrid_sources})
-  # except...
-  list(FILTER src_list EXCLUDE REGEX "^src/kernel/activity/")
-  list(FILTER src_list EXCLUDE REGEX "^src/kernel/actor/")
-  list(FILTER src_list EXCLUDE REGEX "^src/kernel/context/")
-  list(FILTER src_list EXCLUDE REGEX "^src/s4u/")
-  foreach(src ${src_list})
-      set (mcCFLAGS "-O3 -funroll-loops -fno-strict-aliasing")
-      if(CMAKE_COMPILER_IS_GNUCC)
-        set (mcCFLAGS "${mcCFLAGS} -finline-functions")
-      endif()
-      set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS ${mcCFLAGS})
-  endforeach()
-endif()
-
 if (CMAKE_C_COMPILER_ID MATCHES "Intel")
   # honor parentheses when determining the order of expression evaluation.
   # disallow optimizations for floating-point arithmetic with Nans or +-Infs (breaks Eigen3)
index b31d336..42b4789 100644 (file)
@@ -11,6 +11,13 @@ set(FLEX_MIN_PATCH 39)
 # Let's generate header files required by SMPI when the call location tracing
 # has been activated.
 if(enable_maintainer_mode)
+  if (enable_ns3)
+    message(STATUS "Maintainer mode activated with ns-3, not enabling GLIBCXX_DEBUG (diable ns-3 to get it).")
+  else()
+    message(STATUS "Maintainer mode activated, enabling GLIBCXX_DEBUG.")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_DEBUG")
+  endif()
+
   add_custom_command(OUTPUT ${CMAKE_HOME_DIRECTORY}/include/smpi/smpi_extended_traces.h
                             ${CMAKE_HOME_DIRECTORY}/include/smpi/smpi_extended_traces_fortran.h
     DEPENDS
@@ -39,41 +46,10 @@ if(enable_maintainer_mode)
   find_program(FLEX_EXE NAMES flex)
   find_program(FLEXML_EXE NAMES flexml)
   find_program(SED_EXE NAMES sed)
-  find_program(BISON_EXE NAMES bison)
   find_program(LEX_EXE NAMES lex)
 
-  mark_as_advanced(BISON_EXE)
   mark_as_advanced(LEX_EXE)
 
-  if(BISON_EXE AND LEX_EXE)
-    add_custom_command(
-      OUTPUT
-      ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/automaton_lexer.yy.c
-      ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/parserPromela.tab.cacc
-      ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/parserPromela.tab.hacc
-
-      DEPENDS
-      ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/parserPromela.lex
-      ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/parserPromela.yacc
-
-      COMMENT "Generating automaton source files"
-      COMMAND ${BISON_EXE} --name-prefix=xbt_automaton_parser_ -d -t parserPromela.yacc
-      COMMAND ${LEX_EXE} --prefix=xbt_automaton_parser_ --outfile=automaton_lexer.yy.c parserPromela.lex
-      WORKING_DIRECTORY ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/
-      )
-
-    add_custom_target(automaton_generated_src
-      DEPENDS
-      ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/automaton_lexer.yy.c
-      ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/parserPromela.tab.cacc
-      ${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/parserPromela.tab.hacc
-      )
-
-    SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
-      "${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/parserPromela.tab.cacc;${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/parserPromela.tab.hacc;${CMAKE_HOME_DIRECTORY}/src/xbt/automaton/automaton_parse.yy.c"
-      )
-  endif()
-
   message(STATUS "Found flex: ${FLEX_EXE}")
   IF(FLEX_EXE)
     set(HAVE_FLEX 1)
@@ -204,9 +180,9 @@ if(enable_maintainer_mode)
 
 endif()
 
-    add_custom_target(maintainer_files
-      DEPENDS ${CMAKE_HOME_DIRECTORY}/src/kernel/xml/simgrid_dtd.h
-              ${CMAKE_HOME_DIRECTORY}/src/kernel/xml/simgrid_dtd.c
-              ${CMAKE_HOME_DIRECTORY}/src/dag/dax_dtd.h
-              ${CMAKE_HOME_DIRECTORY}/src/dag/dax_dtd.c
-      )
+add_custom_target(maintainer_files
+  DEPENDS ${CMAKE_HOME_DIRECTORY}/src/kernel/xml/simgrid_dtd.h
+          ${CMAKE_HOME_DIRECTORY}/src/kernel/xml/simgrid_dtd.c
+          ${CMAKE_HOME_DIRECTORY}/src/dag/dax_dtd.h
+          ${CMAKE_HOME_DIRECTORY}/src/dag/dax_dtd.c
+  )
index 11cf6b9..79f4e27 100644 (file)
@@ -29,6 +29,7 @@ add_dependencies(simgrid maintainer_files)
 
 if("${CMAKE_SYSTEM}" MATCHES "Linux")
   add_library(sthread SHARED ${STHREAD_SRC})
+  set_target_properties(sthread PROPERTIES VERSION ${libsimgrid_version})
   set_property(TARGET sthread
                 APPEND PROPERTY INCLUDE_DIRECTORIES "${INTERNAL_INCLUDES}")
   target_link_libraries(sthread simgrid)
@@ -36,19 +37,13 @@ else()
   set(EXTRA_DIST ${EXTRA_DIST} ${STHREAD_SRC})
 endif()
 
-if(HAVE_MMALLOC)
-  add_library(sgmalloc SHARED ${SGMALLOC_SRC})
-  set_property(TARGET sgmalloc
-                APPEND PROPERTY INCLUDE_DIRECTORIES "${INTERNAL_INCLUDES}")
-endif()
-
-if(enable_model-checking)
+if(SIMGRID_HAVE_MC)
   add_executable(simgrid-mc ${MC_SIMGRID_MC_SRC})
   target_link_libraries(simgrid-mc simgrid)
   set_target_properties(simgrid-mc
                         PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
   set_property(TARGET simgrid-mc
-               APPEND PROPERTY INCLUDE_DIRECTORIES "${INTERNAL_INCLUDES}")
+                APPEND PROPERTY INCLUDE_DIRECTORIES "${INTERNAL_INCLUDES}")
   install(TARGETS simgrid-mc # install that binary without breaking the rpath on Mac
     RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/)
   add_dependencies(tests-mc simgrid-mc)
@@ -178,10 +173,6 @@ if(CMAKE_COMPILER_IS_GNUCC AND GCCLIBATOMIC_LIBRARY)
 endif()
 mark_as_advanced(GCCLIBATOMIC_LIBRARY)
 
-if(enable_model-checking AND (NOT LINKER_VERSION VERSION_LESS "2.30"))
-    set(SIMGRID_DEP   "${SIMGRID_DEP}   -Wl,-znorelro -Wl,-znoseparate-code")
-endif()
-
 target_link_libraries(simgrid  ${SIMGRID_DEP})
 
 # Dependencies from maintainer mode
@@ -189,6 +180,3 @@ target_link_libraries(simgrid       ${SIMGRID_DEP})
 if(enable_maintainer_mode)
   add_dependencies(simgrid smpi_generated_headers_call_location_tracing)
 endif()
-if(enable_maintainer_mode AND BISON_EXE AND LEX_EXE)
-  add_dependencies(simgrid automaton_generated_src)
-endif()
index 57f6771..860a65e 100644 (file)
@@ -25,9 +25,9 @@ if(HAVE_CDT_LIB AND HAVE_CGRAPH_LIB AND HAVE_CGRAPH_H)
   include_directories(${file_graphviz_h} ${file_graphviz_h}/graphviz)
   link_directories(${lib_graphviz})
 
-  set(HAVE_GRAPHVIZ "1")
+  set(HAVE_GRAPHVIZ ON)
 else()
-  set(HAVE_GRAPHVIZ "0")
+  set(HAVE_GRAPHVIZ OFF)
 endif()
 
 mark_as_advanced(HAVE_GRAPHVIZ)
diff --git a/tools/cmake/Modules/FindLibdw.cmake b/tools/cmake/Modules/FindLibdw.cmake
deleted file mode 100644 (file)
index 62c52e9..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-find_path(LIBDW_INCLUDE_DIR "elfutils/libdw.h"
-  HINTS
-  $ENV{SIMGRID_LIBDW_LIBRARY_PATH}
-  $ENV{LD_LIBRARY_PATH}
-  $ENV{LIBDW_LIBRARY_PATH}
-  PATH_SUFFIXES include/
-  PATHS
-  /opt
-  /opt/local
-  /opt/csw
-  /sw
-  /usr)
-find_library(LIBDW_LIBRARY
-  NAMES dw
-  HINTS
-  $ENV{SIMGRID_LIBDW_LIBRARY_PATH}
-  $ENV{LD_LIBRARY_PATH}
-  $ENV{LIBDW_LIBRARY_PATH}
-  PATH_SUFFIXES lib/
-  PATHS
-  /opt
-  /opt/local
-  /opt/csw
-  /sw
-  /usr)
-set(LIBDW_LIBRARIES "${LIBDW_LIBRARY}")
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(
-  Libdw
-  DEFAULT_MSG
-  LIBDW_LIBRARIES
-  LIBDW_INCLUDE_DIR)
-mark_as_advanced(LIBDW_INCLUDE_DIR LIBDW_LIBRARIES)
diff --git a/tools/cmake/Modules/FindLibelf.cmake b/tools/cmake/Modules/FindLibelf.cmake
deleted file mode 100644 (file)
index 240be29..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-find_path(LIBELF_INCLUDE_DIR "libelf.h"
-  HINTS
-  $ENV{SIMGRID_LIBELF_LIBRARY_PATH}
-  $ENV{LD_LIBRARY_PATH}
-  $ENV{LIBELF_LIBRARY_PATH}
-  PATH_SUFFIXES include/
-  PATHS
-  /opt
-  /opt/local
-  /opt/csw
-  /sw
-  /usr)
-find_library(LIBELF_LIBRARY
-  NAMES elf
-  HINTS
-  $ENV{SIMGRID_LIBELF_LIBRARY_PATH}
-  $ENV{LD_LIBRARY_PATH}
-  $ENV{LIBELF_LIBRARY_PATH}
-  PATH_SUFFIXES lib/
-  PATHS
-  /opt
-  /opt/local
-  /opt/csw
-  /sw
-  /usr)
-set(LIBELF_LIBRARIES "${LIBELF_LIBRARY}")
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(
-  Libelf
-  DEFAULT_MSG
-  LIBELF_LIBRARIES
-  LIBELF_INCLUDE_DIR)
-mark_as_advanced(LIBELF_INCLUDE_DIR LIBELF_LIBRARIES)
diff --git a/tools/cmake/Modules/FindLibunwind.cmake b/tools/cmake/Modules/FindLibunwind.cmake
deleted file mode 100644 (file)
index 2066d48..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-# Search for libunwind and components, both includes and libraries
-#
-# Copyright (C) 2003-2023 The SimGrid Team.
-# This is distributed under the LGPL licence but please contact us for
-# relicensing if you need. This is merely free software, no matter the licence.
-#
-#
-# Input environment variables:
-#    LIBUNWIND_HINT: path to libunwind installation (e.g., /usr)
-#                    (only needed for non-standard installs)
-#
-# You can tune the needed components here.
-# TODO: we should take this as a parameter if I knew how to do so.
-
-# SimGrid needs unwind-ptrace on Linux and FreeBSD
-if("${CMAKE_SYSTEM}" MATCHES "Linux|FreeBSD")
-  set(LIBUNWIND_COMPONENTS ${LIBUNWIND_COMPONENTS} unwind-ptrace unwind-generic)
-endif()
-
-#
-#  Output variables:
-#     HAVE_LIBUNWIND     : if all components were found was found
-#     LIBUNWIND_LIBRARIES: List of all libraries to load (-lunwind -lunwind-x86_64 and such)
-#
-#  Other effects:
-#    - Calls include_directories() on where libunwind.h lives
-#    - Calls link_directories() on where the libs live
-
-# Of course also need the core lib
-set(LIBUNWIND_COMPONENTS ${LIBUNWIND_COMPONENTS} "unwind")
-
-message(STATUS "Looking for libunwind:")
-# Let's assume we have it, and invalidate if parts are missing
-SET(HAVE_LIBUNWIND 1)
-
-#
-# Search for the header file
-#
-
-find_path(PATH_LIBUNWIND_H "libunwind.h"
-  HINTS
-    $ENV{LIBUNWIND_HINT}
-    $ENV{LD_LIBRARY_PATH}
-  PATH_SUFFIXES include/
-  PATHS /opt /opt/local /opt/csw /sw /usr)
-if(PATH_LIBUNWIND_H)
-  string(REGEX REPLACE "/libunwind.h"               "" PATH_LIBUNWIND_H   "${PATH_LIBUNWIND_H}")
-  message("   Found libunwind.h in ${PATH_LIBUNWIND_H}")
-  include_directories(${PATH_LIBUNWIND_H})
-else()
-  message("   NOT FOUND libunwind.h")
-  SET(HAVE_LIBUNWIND 0)
-endif()
-mark_as_advanced(PATH_LIBUNWIND_H)
-
-#
-# Search for the library components
-#
-
-foreach(component ${LIBUNWIND_COMPONENTS})
-  find_library(PATH_LIBUNWIND_LIB_${component}
-    NAMES ${component}
-    HINTS
-      $ENV{LIBUNWIND_HINT}
-      $ENV{LD_LIBRARY_PATH}
-    PATH_SUFFIXES lib/ lib/system
-    PATHS /opt /opt/local /opt/csw /sw /usr /usr/lib/)
-  if(PATH_LIBUNWIND_LIB_${component})
-    # message("     ${component}  ${PATH_LIBUNWIND_LIB_${component}}")
-    string(REGEX REPLACE "/lib${component}.*[.]${LIB_EXE}$" "" PATH_LIBUNWIND_LIB_${component} "${PATH_LIBUNWIND_LIB_${component}}")
-    message("   Found lib${component}.${LIB_EXE} in ${PATH_LIBUNWIND_LIB_${component}}")
-    link_directories(${PATH_LIBUNWIND_LIB_${component}})
-
-    if(${component} STREQUAL "unwind" AND APPLE)
-        # Apple forbids to link directly against its libunwind implementation
-        # So let's comply to that stupid restriction and link against the System framework
-        SET(LIBUNWIND_LIBRARIES "${LIBUNWIND_LIBRARIES} -lSystem")
-    else()
-        SET(LIBUNWIND_LIBRARIES "${LIBUNWIND_LIBRARIES} -l${component}")
-    endif()
-
-  else()
-    message("   Looking for lib${component}.${LIB_EXE} - not found")
-    SET(HAVE_LIBUNWIND 0)
-  endif()
-  mark_as_advanced(PATH_LIBUNWIND_LIB_${component})
-endforeach()
-unset(component)
-unset(LIBUNWIND_COMPONENTS)
-
-#
-# Conclude and cleanup
-#
-if(HAVE_LIBUNWIND)
-  message(STATUS "Dependencies induced by libunwind: ${LIBUNWIND_LIBRARIES}")
-else()
-  message(STATUS "Some libunwind components are missing")
-  set(LIBUNWIND_LIBRARIES "")
-endif()
index 7154c2b..9975872 100644 (file)
@@ -126,8 +126,19 @@ else()
   endforeach()
 endif()
 
+set(SIMGRID_HAVE_NS3_GetNextEventTime FALSE)
 if(SIMGRID_HAVE_NS3)
-  message(STATUS "ns-3 found (v${NS3_VERSION}; minor:${NS3_MINOR_VERSION}; patch:${NS3_PATCH_VERSION}; libpath: ${NS3_LIBRARY_PATH}).")
+  try_compile(compile_ns3 ${CMAKE_BINARY_DIR} ${CMAKE_HOME_DIRECTORY}/tools/cmake/test_prog/prog_ns3.cpp
+              CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${NS3_INCLUDE_DIR}" "-DLINK_DIRECTORIES=${NS3_LIBRARY_PATH}"
+              LINK_LIBRARIES "${NS3_LIBRARIES}"
+              OUTPUT_VARIABLE compile_ns3_output)
+  if(NOT compile_ns3)
+    message(STATUS "ns-3 does not have the ns3::Simulator::GetNextEventTime patch. The ns-3 model will not be idempotent. Compilation output:\n ${compile_ns3_output}")
+  else()
+    set(SIMGRID_HAVE_NS3_GetNextEventTime TRUE)
+  endif()
+  file(REMOVE ${CMAKE_BINARY_DIR}/prog_ns3)
+  message(STATUS "ns-3 found (v${NS3_VERSION}; minor ver:${NS3_MINOR_VERSION}; patch ver:${NS3_PATCH_VERSION}; GetNextEventTime patch: ${SIMGRID_HAVE_NS3_GetNextEventTime}; libpath: ${NS3_LIBRARY_PATH}).")
   link_directories(${NS3_LIBRARY_PATH})
   include_directories(${NS3_INCLUDE_DIR})
 else()
index 8427cfe..28b2b35 100644 (file)
@@ -17,7 +17,7 @@
 #  PAPI_LIBRARY          The PAPI library
 #  PAPI_INCLUDE_DIRS       The location of PAPI headers
 
-set(HAVE_PAPI 0)
+set(HAVE_PAPI OFF)
 set(PAPI_HINT ${papi_path} CACHE PATH "Path to search for PAPI headers and library")
 
 find_path(PAPI_PREFIX
@@ -55,7 +55,7 @@ endif()
 
 if (PAPI_LIBRARY)
   if(PAPI_INCLUDE_DIRS)
-    set(HAVE_PAPI 1)
+    set(HAVE_PAPI ON)
     mark_as_advanced(HAVE_PAPI)
   endif()
 endif()
index 0ff2fcc..e35aa12 100644 (file)
@@ -38,8 +38,8 @@ endif()
 option(minimal-bindings      "Whether to compile the Python bindings libraries with the minimal dependency set" off)
 mark_as_advanced(minimal-bindings)
 
-option(enable_model-checking "Turn this on to experiment with our prototype of model-checker (hinders the simulation's performance even if turned off at runtime)" off)
-option(enable-model-checking "Please set 'enable_model-checking' instead" off)
+option(enable_model-checking "Turn this on to experiment with our prototype of model-checker" on)
+option(enable-model-checking "Please set 'enable_model-checking' instead" on)
 mark_as_advanced(enable-model-checking)
 if(enable-model-checking)
   SET(enable_model-checking ON CACHE BOOL "Whether to compile the model-checker" FORCE)
@@ -47,8 +47,22 @@ endif()
 
 option(enable_smpi "Whether SMPI is included in the library." on)
 option(enable_smpi_papi    "Whether SMPI supports PAPI bindings." off)
-option(enable_smpi_MPICH3_testsuite "Whether the test suite form MPICH 3 should be built" off)
-option(enable_smpi_MBI_testsuite "Whether the test suite from MBI should be built." off)
+
+option(enable_testsuite_smpi_MPICH3 "Whether the test suite form MPICH 3 should be built." off)
+option(enable_smpi_MPICH3_testsuite "Please use 'enable_testsuite_smpi_MPICH3' instead." off)
+mark_as_advanced(enable_smpi_MPICH3_testsuite)
+if(enable_smpi_MPICH3_testsuite)
+  SET(enable_testsuite_smpi_MPICH3 ON CACHE BOOL "Whether the test suite form MPICH 3 should be built." FORCE)
+endif()
+
+option(enable_testsuite_smpi_MBI "Whether the test suite from MBI should be built." off)
+option(enable_smpi_MBI_testsuite "Please use 'enable_testsuite_smpi_MBI' instead." off)
+mark_as_advanced(enable_smpi_MBI_testsuite)
+if(enable_smpi_MBI_testsuite)
+  SET(enable_testsuite_smpi_MBI ON CACHE BOOL "Whether the test suite from MBI should be built." FORCE)
+endif()
+
+option(enable_testsuite_McMini "Whether the test suite from McMini should be built." off)
 
 # Internal targets used by jenkins
 ###
index ce7d830..c5567a0 100644 (file)
@@ -19,6 +19,7 @@ IF(enable_memcheck)
       SET(VALGRIND_WRAPPER ${VALGRIND_WRAPPER}\ --xml=yes\ --xml-file=memcheck_test_%p.memcheck\ --child-silent-after-fork=yes\ )
     endif()
     set(TESH_OPTION ${TESH_OPTION} --setenv VALGRIND_NO_LEAK_CHECK=--leak-check=no\ --show-leak-kinds=none)
+    set(TESH_OPTION ${TESH_OPTION} --setenv VALGRIND_NO_TRACE_CHILDREN=--trace-children=no)
 
 #    message(STATUS "tesh wrapper: ${VALGRIND_WRAPPER}")
 
@@ -129,11 +130,14 @@ set(UNIT_TESTS  src/xbt/unit-tests_main.cpp
                 src/xbt/utils/iter/subsets_tests.cpp
                 src/kernel/lmm/maxmin_test.cpp)
 
-set(MC_UNIT_TESTS src/mc/sosp/Snapshot_test.cpp 
-                  src/mc/sosp/PageStore_test.cpp
-                  src/mc/explo/udpor/EventSet_test.cpp
+set(MC_UNIT_TESTS src/mc/explo/odpor/ClockVector_test.cpp
+                  src/mc/explo/odpor/Execution_test.cpp
+                  src/mc/explo/odpor/WakeupTree_test.cpp
+                  
                   src/mc/explo/udpor/Unfolding_test.cpp
                   src/mc/explo/udpor/UnfoldingEvent_test.cpp
+                  src/mc/explo/udpor/EventSet_test.cpp
+                  src/mc/explo/udpor/ExtensionSet_test.cpp
                   src/mc/explo/udpor/History_test.cpp
                   src/mc/explo/udpor/Configuration_test.cpp)
 if (SIMGRID_HAVE_MC)
index b13a4fc..d2ec57b 100755 (executable)
@@ -8,6 +8,7 @@
 use strict;
 use warnings;
 
+# Many other parameters (such as trace-children) are set in Tests.cmake
 my @argv = ("valgrind", "--quiet");
 my $count = 0;
 
diff --git a/tools/cmake/test_prog/prog_ns3.cpp b/tools/cmake/test_prog/prog_ns3.cpp
new file mode 100644 (file)
index 0000000..c763cbd
--- /dev/null
@@ -0,0 +1,7 @@
+#include "ns3/simulator.h"
+
+int main()
+{
+  ns3::Simulator::GetNextEventTime();
+  return 0;
+}
\ No newline at end of file
index 8fdaa14..7eb4d25 100644 (file)
@@ -1,5 +1,5 @@
-# Base image
-FROM debian:11
+# Base image: bookworm is Debian 12
+FROM debian:bookworm
 
 # Install the dependencies:
 #  - of the website
@@ -17,7 +17,7 @@ RUN apt-get --allow-releaseinfo-change update && \
        python3-pip \
        doxygen fig2dev \
        chrpath \
-       libdw-dev libevent-dev libunwind8-dev \
+       libevent-dev \
        python3-sphinx python3-breathe python3-sphinx-rtd-theme && \
     apt clean && apt autoclean
 
index b898611..011ae00 100644 (file)
@@ -17,6 +17,6 @@ RUN echo "DOWNLOAD_URL: ${DLURL}" && \
     make -j4 && \
     mkdir debian/ && touch debian/control && dpkg-shlibdeps --ignore-missing-info lib/*.so -llib/ -O/tmp/deps && \
     make install && make clean && \
-    apt remove -y  g++ gcc git valgrind gfortran libboost-dev libboost-all-dev libeigen3-dev cmake dpkg-dev wget python3-dev pybind11-dev && \
+    apt remove -y git valgrind libeigen3-dev cmake dpkg-dev wget python3-dev pybind11-dev && \
     apt install `sed -e 's/shlibs:Depends=//' -e 's/([^)]*)//g' -e 's/,//g' /tmp/deps` && \
     apt autoremove -y && apt autoclean && apt clean
index 1730440..f13861d 100644 (file)
@@ -13,7 +13,7 @@ RUN apt update && apt -y upgrade
 # - Get the tutorial files (with an empty makefile advising to run cmake before make, just in case)
 # - Remove everything that was installed, and re-install what's needed by the SimGrid libraries before the Gran Final Cleanup
 # - Keep g++ gcc gfortran as any MC user will use (some of) them
-RUN apt install -y g++ gcc git valgrind gfortran libboost-dev libeigen3-dev libboost-stacktrace-dev cmake dpkg-dev libunwind-dev libdw-dev libelf-dev libevent-dev python3-dev && \
+RUN apt install -y g++ gcc git valgrind gfortran libboost-dev libeigen3-dev libboost-stacktrace-dev cmake dpkg-dev libdw-dev libelf-dev libevent-dev python3-dev && \
     mkdir /source/ && cd /source && git clone --depth=1 https://framagit.org/simgrid/simgrid.git simgrid.git && \
     cd simgrid.git && \
     cmake -DCMAKE_INSTALL_PREFIX=/usr/ -Denable_model-checking=ON -Denable_documentation=OFF -Denable_smpi=ON -Denable_compile_optimizations=ON . && \
@@ -21,7 +21,7 @@ RUN apt install -y g++ gcc git valgrind gfortran libboost-dev libeigen3-dev libb
     git clone --depth=1 https://framagit.org/simgrid/tutorial-model-checking /source/tuto-mc.git && \
     printf "ndet-receive-s4u:\n\t@echo \"Please run the following command before make:\";echo \"    cmake .\"; exit 1" > /source/tuto-mc.git/Makefile &&\
     mkdir debian/ && touch debian/control && dpkg-shlibdeps --ignore-missing-info lib/*.so -llib/ -O/tmp/deps && \
-    apt remove -y dpkg-dev libunwind-dev libdw-dev libelf-dev libevent-dev && \
+    apt remove -y dpkg-dev libdw-dev libelf-dev libevent-dev && \
     apt install -y `sed -e 's/shlibs:Depends=//' -e 's/([^)]*)//g' -e 's/,//g' /tmp/deps` && rm /tmp/deps && \
     apt autoremove -y && apt autoclean && apt clean
 
index 6ef5e42..c3bf640 100644 (file)
@@ -12,6 +12,6 @@ RUN apt-get --allow-releaseinfo-change update && apt -y upgrade && \
     make -j4 install && \
     mkdir debian/ && touch debian/control && dpkg-shlibdeps --ignore-missing-info lib/*.so -llib/ -O/tmp/deps && \
     git reset --hard master && git clean -dfx && \
-    apt remove -y  g++ gcc git valgrind gfortran libboost-dev libboost-all-dev libeigen3-dev cmake dpkg-dev python3-dev pybind11-dev && \
+    apt remove -y git valgrind libeigen3-dev cmake dpkg-dev wget python3-dev pybind11-dev && \
     apt install `sed -e 's/shlibs:Depends=//' -e 's/([^)]*)//g' -e 's/,//g' /tmp/deps` && \
     apt autoremove -y && apt autoclean && apt clean
diff --git a/tools/generate-dwarf-functions b/tools/generate-dwarf-functions
deleted file mode 100755 (executable)
index 838d833..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env sh
-# Generate files from a given dwarf.h
-# Usage: tools/generate-dwarf-functions /usr/include/dwarf.h
-
-HEADER="\
-/* Copyright (c) 2014-$(date +%Y). The SimGrid Team. All rights reserved.          */
-
-/* This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package. */
-
-/* Warning: autogenerated, do not edit! */
-
-#include \"src/mc/inspect/mc_dwarf.hpp\"
-
-#include <string>
-#include <unordered_map>"
-
-cat - > src/mc/inspect/mc_dwarf_tagnames.cpp <<EOF
-$HEADER
-
-namespace {
-const std::unordered_map<int, const char*> tagname_map = {
-    {0x00, "DW_TAG_invalid"},
-$(sed -n 's/.*\(DW_TAG_[^ ]*\) = \(0x[0-9a-f]*\).*/    {\2, "\1"},/p' -- "$1")
-};
-}
-
-namespace simgrid::dwarf {
-
-/** @brief Get the name of a dwarf tag (DW_TAG_*) from its code
- *
- *  @param tag tag code (see the DWARF specification)
- *  @return name of the tag
- */
-XBT_PRIVATE
-const char* tagname(int tag)
-{
-  auto name = tagname_map.find(tag);
-  return name == tagname_map.end() ? "DW_TAG_unknown" : name->second;
-}
-
-} // namespace simgrid::dwarf
-EOF
-
-cat - > src/mc/inspect/mc_dwarf_attrnames.cpp << EOF
-$HEADER
-
-namespace {
-const std::unordered_map<int, const char*> attrname_map = {
-$(sed -n 's/.*\(DW_AT_[^ ]*\) = \(0x[0-9a-f]*\).*/    {\2, "\1"},/p' -- "$1")
-};
-}
-
-namespace simgrid::dwarf {
-
-/** @brief Get the name of an attribute (DW_AT_*) from its code
- *
- *  @param attr attribute code (see the DWARF specification)
- *  @return name of the attribute
- */
-XBT_PRIVATE
-const char* attrname(int attr)
-{
-  auto name = attrname_map.find(attr);
-  return name == attrname_map.end() ? "DW_AT_unknown" : name->second;
-}
-
-} // namespace simgrid::dwarf
-EOF
index dbcb6e0..368892b 100644 (file)
@@ -26,7 +26,7 @@ int main(int argc, char** argv)
     simgrid::instr::platform_graph_export_graphviz(outputfile);
   }
   else {
-    xbt_assert(false, "Unknown output file format, please use '.dot' or .csv' extension\n");
+    xbt_die("Unknown output file format, please use '.dot' or .csv' extension");
   }
   return 0;
 }
index 4a2012d..39fde22 100755 (executable)
@@ -65,9 +65,9 @@ cmake -Denable_documentation=OFF \
       -Denable_compile_optimizations=OFF -Denable_compile_warnings=ON \
       -Denable_mallocators=ON \
       -Denable_ns3=ON \
-      -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=ON -Denable_model-checking=ON \
+      -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=ON -Denable_model-checking=ON \
       -Denable_smpi_papi=ON \
-      -Denable_memcheck=OFF -Denable_memcheck_xml=OFF -Denable_smpi_MBI_testsuite=ON \
+      -Denable_memcheck=OFF -Denable_memcheck_xml=OFF -Denable_testsuite_smpi_MBI=ON -Denable_testsuite_McMini=ON \
       -Denable_coverage=ON -DLTO_EXTRA_FLAG="auto" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON "$WORKSPACE"
 
 #build with sonarqube scanner wrapper
@@ -87,7 +87,7 @@ if [ -f Testing/TAG ] ; then
   /usr/bin/python3-coverage xml -i -o ./python_coverage.xml
 
   #convert all gcov reports to xml cobertura reports
-  gcovr -r "$WORKSPACE" --xml-pretty -e "$WORKSPACE"/teshsuite -e MBI -e "$WORKSPACE"/examples/smpi/NAS -e "$WORKSPACE"/examples/smpi/mc -u -o xml_coverage.xml --gcov-ignore-parse-errors
+  gcovr -r "$WORKSPACE" --xml-pretty -e "$WORKSPACE"/teshsuite -e MBI -e "$WORKSPACE"/examples/smpi/NAS -e "$WORKSPACE"/examples/smpi/mc -u -o xml_coverage.xml --gcov-ignore-parse-errors all --gcov-ignore-errors all
 
   cd "$WORKSPACE"
   xsltproc "$WORKSPACE"/tools/jenkins/ctest2junit.xsl build/Testing/"$( head -n 1 < build/Testing/TAG )"/Test.xml > CTestResults_memcheck.xml
@@ -96,7 +96,7 @@ if [ -f Testing/TAG ] ; then
   sloccount --duplicates --wide --details "$WORKSPACE" | grep -v -e '.git' -e 'mpich3-test' -e 'sloccount.sc' -e 'build/' -e 'xml_coverage.xml' -e 'CTestResults_memcheck.xml' -e 'DynamicAnalysis.xml' > "$WORKSPACE"/sloccount.sc
 
   #generate PVS-studio report
-  EXCLUDEDPATH="-e $WORKSPACE/src/3rd-party/catch.hpp -e $WORKSPACE/src/3rd-party/xxhash.hpp -e $WORKSPACE/teshsuite/smpi/mpich3-test/ -e *_dtd.c -e *_dtd.h -e *.yy.c -e *.tab.cacc -e *.tab.hacc -e $WORKSPACE/src/smpi/colls/ -e $WORKSPACE/examples/smpi/NAS/ -e $WORKSPACE/examples/smpi/gemm/gemm.cq"
+  EXCLUDEDPATH="-e $WORKSPACE/src/3rd-party/catch.hpp -e $WORKSPACE/teshsuite/smpi/mpich3-test/ -e *_dtd.c -e *_dtd.h -e *.yy.c -e *.tab.cacc -e *.tab.hacc -e $WORKSPACE/src/smpi/colls/ -e $WORKSPACE/examples/smpi/NAS/ -e $WORKSPACE/examples/smpi/gemm/gemm.cq"
   pvs-studio-analyzer analyze -f "$BUILDFOLDER"/compile_commands.json -o "$WORKSPACE"/pvs.log $EXCLUDEDPATH -j$NUMPROC
   # Disable:
   # V521 Such expressions using the ',' operator are dangerous. (-> commas in catch.hpp),
index 41f0ba1..2f7d99f 100755 (executable)
@@ -61,7 +61,7 @@ ctest -D ExperimentalStart || true
 cmake -Denable_documentation=OFF -Denable_python=OFF \
       -Denable_compile_optimizations=OFF -Denable_compile_warnings=ON \
       -Denable_mallocators=OFF \
-      -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=OFF -Denable_model-checking=OFF \
+      -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=OFF -Denable_testsuite_McMini=OFF -Denable_model-checking=OFF \
       -Denable_ns3=ON \
       -Denable_memcheck_xml=ON -DLTO_EXTRA_FLAG="auto" "$WORKSPACE"
 
index e8f9198..1fe6b38 100755 (executable)
@@ -76,16 +76,25 @@ else
     runtests="OFF"
 fi
 
-cmake -Denable_documentation=OFF \
+GENERATOR="Unix Makefiles"
+BUILDER=make
+VERBOSE_BUILD="VERBOSE=1"
+if which ninja 2>/dev/null >/dev/null ; then
+  GENERATOR=Ninja
+  BUILDER=ninja
+  VERBOSE_BUILD="-v"
+fi
+
+cmake -G"$GENERATOR" -Denable_documentation=OFF \
       -Denable_compile_optimizations=${runtests} -Denable_compile_warnings=ON \
       -Denable_mallocators=ON -Denable_debug=${builddebug} \
-      -Denable_smpi=${buildsmpi} -Denable_smpi_MPICH3_testsuite=${buildsmpi} -Denable_model-checking=${buildmc} \
-      -Denable_memcheck=OFF -Denable_memcheck_xml=OFF -Denable_smpi_MBI_testsuite=OFF \
+      -Denable_smpi=${buildsmpi} -Denable_testsuite_smpi_MPICH3=${buildsmpi} -Denable_model-checking=${buildmc} \
+      -Denable_memcheck=OFF -Denable_memcheck_xml=OFF -Denable_testsuite_smpi_MBI=OFF -Denable_testsuite_McMini=OFF \
       -Denable_ns3=$(onoff test "$buildmc" != "ON") -DNS3_HINT=/builds/ns-3-dev/build/ \
       -Denable_coverage=OFF -DLTO_EXTRA_FLAG="auto" -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
       "$WORKSPACE"
 
-make -j$NUMPROC tests
+${BUILDER} -j$NUMPROC tests ${VERBOSE_BUILD}
 
 if [ "$runtests" = "ON" ]; then
     # exclude tests known to fail with _GLIBCXX_DEBUG
index 04b4737..ef5ae0e 100755 (executable)
@@ -77,9 +77,9 @@ ctest -D ExperimentalStart || true
 cmake -Denable_documentation=OFF \
       -Denable_compile_optimizations=ON -Denable_compile_warnings=ON \
       -Denable_mallocators=OFF \
-      -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=ON -Denable_model-checking=OFF \
+      -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=ON -Denable_model-checking=OFF \
       -Denable_ns3=ON \
-      -Denable_memcheck=OFF -Denable_memcheck_xml=OFF -Denable_smpi_MBI_testsuite=OFF -Denable_coverage=OFF\
+      -Denable_memcheck=OFF -Denable_memcheck_xml=OFF -Denable_testsuite_smpi_MBI=OFF -Denable_testsuite_McMini=OFF -Denable_coverage=OFF\
       -Denable_fortran=OFF -Denable_python=OFF -DLTO_EXTRA_FLAG="auto" -DCMAKE_CXX_COMPILER_LAUNCHER=ccache\
       ${SANITIZER_OPTIONS} "$WORKSPACE"
 
index a1a6b16..0438427 100755 (executable)
@@ -2,6 +2,13 @@
 
 # This script is used by various build projects on Jenkins
 
+case "$JENKINS_HOME" in
+*-qualif)
+  echo "Build skipped on $JENKINS_HOME."
+  exit 0
+  ;;
+esac
+
 # See https://ci.inria.fr/simgrid/job/SimGrid/configure
 # See https://ci.inria.fr/simgrid/job/Simgrid-Windows/configure
 
@@ -122,6 +129,13 @@ echo "Branch built is $branch_name"
 
 NUMBER_OF_PROCESSORS="$(nproc)" || NUMBER_OF_PROCESSORS=1
 GENERATOR="Unix Makefiles"
+BUILDER=make
+VERBOSE_BUILD="VERBOSE=1"
+if which ninja 2>/dev/null >/dev/null ; then
+  GENERATOR=Ninja
+  BUILDER=ninja
+  VERBOSE_BUILD="-v"
+fi
 
 ulimit -c 0 || true
 
@@ -162,7 +176,7 @@ echo "XX   pwd: $(pwd)"
 echo "XX"
 
 cmake -G"$GENERATOR" -Denable_documentation=OFF "$WORKSPACE"
-make dist -j $NUMBER_OF_PROCESSORS
+${BUILDER} dist -j $NUMBER_OF_PROCESSORS
 SIMGRID_VERSION=$(cat VERSION)
 
 echo "XX"
@@ -197,9 +211,9 @@ fi
 cmake -G"$GENERATOR" ${INSTALL:+-DCMAKE_INSTALL_PREFIX=$INSTALL} \
   -Denable_debug=ON -Denable_documentation=OFF -Denable_coverage=OFF \
   -Denable_model-checking=$(onoff test "$build_mode" = "ModelChecker") \
-  -Denable_smpi_MBI_testsuite=OFF \
+  -Denable_testsuite_smpi_MBI=OFF -Denable_testsuite_McMini=ON \
   -Denable_compile_optimizations=$(onoff test "$build_mode" != "DynamicAnalysis") \
-  -Denable_smpi_MPICH3_testsuite=$(onoff test "$build_mode" = "Debug") \
+  -Denable_testsuite_smpi_MPICH3=$(onoff test "$build_mode" = "Debug") \
   -Denable_mallocators=$(onoff test "$build_mode" != "DynamicAnalysis") \
   -Denable_memcheck=$(onoff test "$build_mode" = "DynamicAnalysis") \
   -Denable_compile_warnings=$(onoff test "$GENERATOR" != "MSYS Makefiles") -Denable_smpi=ON \
@@ -209,9 +223,8 @@ cmake -G"$GENERATOR" ${INSTALL:+-DCMAKE_INSTALL_PREFIX=$INSTALL} \
   -DLTO_EXTRA_FLAG="auto" \
   -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
   "$SRCFOLDER"
-set +x
 
-make -j $NUMBER_OF_PROCESSORS VERBOSE=1 tests
+${BUILDER} -j $NUMBER_OF_PROCESSORS ${VERBOSE_BUILD} tests
 
 echo "XX"
 echo "XX Run the tests"
@@ -227,7 +240,7 @@ if test -n "$INSTALL" && [ "${branch_name}" = "origin/master" ] ; then
 
   rm -rf "$INSTALL"
 
-  make install
+  ${BUILDER} install
 fi
 
 echo "XX"
index 29673a7..9391fa0 100755 (executable)
@@ -22,11 +22,17 @@ export PATH=$PWD/simgrid-dev/smpi_script/bin/:$PATH
 export LD_LIBRARY_PATH=$PWD/simgrid-dev/lib/:$LD_LIBRARY_PATH
 export JHBUILD_RUN_AS_ROOT=1
 
+#workaround issue with ntpoly 3.0.0
+sed -i 's|repository type="tarball" name="ntpoly" href="https://github.com/william-dawson/NTPoly/archive/"|repository type="git" name="ntpoly" href="https://github.com/william-dawson/"|' ../modulesets/hpc-upstream.modules
+sed -i 's|module="ntpoly-v3.0.0.tar.gz"|module="ntpoly"|' ../modulesets/hpc-upstream.modules
+
 ../Installer.py autogen -y
 
 ../Installer.py -f ../../tools/jenkins/gfortran-simgrid.rc -y build
 
 export OMP_NUM_THREADS=1
+#workaround issue with profiling optimization (for fugaku) which prevent f_free_ptr to use the simgrid version. Fix pending.
+export FUTILE_PROFILING_DEPTH=-1
 
 #cubic version
 cd ../bigdft/tests/DFT/cubic/C
index ece7a08..73864b4 100755 (executable)
@@ -12,17 +12,17 @@ echo "XXXXXXXXXXXXXXXX Install APT dependencies"
 $SUDO apt-get update
 $SUDO apt-get -y install build-essential libboost-all-dev wget git xsltproc
 
-for i in master 1.3 ; do
+for i in master starpu-1.3 ; do
   echo "XXXXXXXXXXXXXXXX Build and test StarPU $i"
   rm -rf starpu*
-  wget https://files.inria.fr/starpu/simgrid/starpu-simgrid-$i.tar.gz
-  md5sum starpu-simgrid-$i.tar.gz
-  tar xf starpu-simgrid-$i.tar.gz
+  wget https://files.inria.fr/starpu/testing/$i/starpu-nightly-latest.tar.gz
+  md5sum starpu-nightly-latest.tar.gz
+  tar xf starpu-nightly-latest.tar.gz
   cd starpu-1*
 
   # NOTE: Do *not* introduce parameters to "make it work" here.
   # Things should "just work" with default parameters!
-  # Users should not have to tinker to get starpu working on top of simgrid, that is precisely why we have this CI
+  # Users should not have to tinker to get starpu working on top of SimGrid, that is precisely why we have this CI
 
   if [ $i = master ]; then
     # On master, fail if we use deprecated functions, so that StarPU people know they have to stop using them, fix it, and thus make CI happy again
index 5d3eb0d..e8ec004 100644 (file)
@@ -6,7 +6,7 @@ def getcwd():
 prefix=getcwd()+"/install"
 #Add the condition testing to run tests and includes PyYaml
 conditions.add("testing")
-conditions.add("simulation") #to include simgrid compilation
+conditions.add("simulation") #to include SimGrid compilation
 #List the module the this rcfile will build
 modules = ['spred',]
 #example of the potentialities of the python syntax in this file
index 4a52a6f..8af5e8d 100755 (executable)
@@ -26,7 +26,7 @@ get_json(){
 }
 
 get_ns3(){
-  sed -n 's/.*-- ns-3 found (v\(3[-.0-9a-z]\+\); minor:.*/\1/p;T;q' ./consoleText
+  sed -n 's/.*-- ns-3 found (v\(3[-.0-9a-z]\+\).*/\1/p;T;q' ./consoleText
 }
 
 get_python(){
index 8a70894..c5699ea 100755 (executable)
@@ -1,6 +1,6 @@
 #! /usr/bin/env python3
 
-# The goal is to introduce random failures in a simulation, to test simgrid under extreme conditions.
+# The goal is to introduce random failures in a simulation, to test SimGrid under extreme conditions.
 # 
 # It is made of several components.
 # 
@@ -13,7 +13,7 @@
 #     Kill the link #0 after 42 seconds (using a kernel::Timer)
 # 
 # * a python script: tools/simgrid-monkey (this file)
-#   * It takes a regular simgrid simulation as a parameter, use the cmonkey plugin to get the information about it, 
+#   * It takes a regular SimGrid simulation as a parameter, use the cmonkey plugin to get the information about it, 
 #     and then restart many runs, with one resource being turn_off() + turn_on() in each run.
 #   * Each resource gets killed between each timestamps, and on each timestamp.
 #   * So the amount of simulations is: 1 + (host_c+link_c) * timestamps * 2
@@ -65,7 +65,7 @@ def get_info(cmd):
     #print(f"hosts:{host_count} links:{link_count} timestamps:{' '.join(([str(i) for i in timestamps]))}")
     return (host_count,  link_count,  timestamps)
 
-parser = argparse.ArgumentParser(description='Run a simgrid simulation, and turn off/on resources at random.')
+parser = argparse.ArgumentParser(description='Run a SimGrid simulation, and turn off/on resources at random.')
 parser.add_argument('--valgrind', help="Run the simulations in valgrind")
 parser.add_argument('command', nargs='*')
 args = parser.parse_args()
index 98a18e1..e1c3f28 100644 (file)
    fun:agconcat
 }
 
-# libunwind seems to be using msync poorly, thus triggering these
-# https://github.com/JuliaLang/julia/issues/4533
-{
-   msync unwind
-   Memcheck:Param
-   msync(start)
-   ...
-   obj:*/libpthread*.so
-   ...
-}
-
-{
-   ignore unwind cruft
-   Memcheck:Param
-   rt_sigprocmask(set)
-   ...
-   obj:/usr/lib/x86_64-linux-gnu/libunwind.so.*
-   ...
-}
-{
-   ignore unwind cruft
-   Memcheck:Param
-   msync(start)
-   ...
-   obj:/usr/lib/x86_64-linux-gnu/libunwind.so.*
-   ...
-}
-{
-   ignore unwind cruft
-   Memcheck:Param
-   write(buf)
-   ...
-   fun:_ULx86_64_step
-   obj:/usr/lib/x86_64-linux-gnu/libunwind.so.*
-}
-
-{
-   ignore unwind invalid reads
-   Memcheck:Addr8
-   fun:_Ux86_64_setcontext
-}
-
 # Ignore python cruft
 {
    ignore python cruft 1
index b31bdbc..8c9cd3e 100755 (executable)
@@ -7,7 +7,7 @@
 
 '''
 This script is intended to convert SMPI time independent traces (TIT) from the
-old format (simgrid version <= 3.19) to the new format.
+old format (SimGrid version <= 3.19) to the new format.
 
 On the previous format each MPI_wait calls were associated to the last ISend of
 IRecv call arbitrarily.
@@ -15,7 +15,7 @@ IRecv call arbitrarily.
 This new that includes tags field that links MPI_wait calls to the
 MPI_ISend or MPI_IRecv associated to this wait.
 
-This script reproduce the old behavior of simgrid because information are
+This script reproduce the old behavior of SimGrid because information are
 missing to add the tags properly. It also lower case all the mpi calls.
 
 It takes in input (as argument or in stdin) the trace list file that is only a
index defb1ec..e62d011 100755 (executable)
@@ -2,7 +2,7 @@
 eval 'exec perl -S $0 ${1+"$@"}'
     if $running_under_some_shell;
 
-# This script updates the simgrid XML file passed as argument (modification in place)
+# This script updates the SimGrid XML file passed as argument (modification in place)
 # It is built to do the conversion incrementally.
 
 # Copyright (c) 2006-2023. The SimGrid Team.
@@ -15,7 +15,7 @@ eval 'exec perl -S $0 ${1+"$@"}'
 
 =head1 NAME
 
-simgrid_update_xml - updates simgrid XML files to latest version
+simgrid_update_xml - updates SimGrid XML files to latest version
 
 =head1 SYNOPSIS
 
@@ -23,7 +23,7 @@ B<simgrid_update_xml> I<xml_file>
 
 =head1 DESCRIPTION
 
-simgrid_update_xml updates the simgrid XML file passed as argument.  The file
+simgrid_update_xml updates the SimGrid XML file passed as argument.  The file
 is modified in place, without any kind of backup. You may want to save a copy
 before running the script.
 
index c3e213f..34c366a 100755 (executable)
@@ -50,11 +50,11 @@ sub output_macro {
   # This is a GCC extension. The last statement is the value of the expression
   # in parentheses.
   if (defined $options{f}) {
-    print "#define ". lc($id) ." smpi_trace_set_call_location(__FILE__,__LINE__); call ". ucfirst $id ."\n";
-    print "#define ". uc($id) ." smpi_trace_set_call_location(__FILE__,__LINE__); call ". ucfirst $id ."\n";
+    print "#define ". lc($id) ." smpi_trace_set_call_location(__FILE__,__LINE__,\"". lc($id) ."\"); call ". ucfirst $id ."\n";
+    print "#define ". uc($id) ." smpi_trace_set_call_location(__FILE__,__LINE__,\"". uc($id) ."\"); call ". ucfirst $id ."\n";
   }
   else {
-    print "#define $id(...) (smpi_trace_set_call_location(__FILE__, __LINE__), $id(__VA_ARGS__))\n";
+    print "#define $id(...) (smpi_trace_set_call_location(__FILE__, __LINE__, \"$id\"), $id(__VA_ARGS__))\n";
   }
 }
 
index e2c0a25..c7bbc67 100644 (file)
@@ -7,6 +7,7 @@ p Order: in, out, cmd
 < $ cat
 > Test suite from stdin
 > [(stdin):3] cat
+> 
 > Test suite from stdin OK
 $ ${bindir:=.}/tesh
 
@@ -16,6 +17,7 @@ p Order: out, in, cmd
 < $ cat
 > Test suite from stdin
 > [(stdin):3] cat
+> 
 > Test suite from stdin OK
 $ ${bindir:=.}/tesh
 
@@ -25,6 +27,7 @@ p Order: out, cmd, in
 < < TOTO
 > Test suite from stdin
 > [(stdin):2] cat
+> 
 > Test suite from stdin OK
 $ ${bindir:=.}/tesh
 
@@ -34,6 +37,7 @@ p Order: in, cmd, out
 < > TOTO
 > Test suite from stdin
 > [(stdin):2] cat
+> 
 > Test suite from stdin OK
 $ ${bindir:=.}/tesh
 
@@ -43,6 +47,7 @@ p Order: cmd, out, in
 < < TOTO
 > Test suite from stdin
 > [(stdin):1] cat
+> 
 > Test suite from stdin OK
 $ ${bindir:=.}/tesh
 
@@ -52,5 +57,6 @@ p Order: cmd, in, out
 < > TOTO
 > Test suite from stdin
 > [(stdin):1] cat
+> 
 > Test suite from stdin OK
 $ ${bindir:=.}/tesh
index 2799b4f..42fede2 100644 (file)
@@ -19,7 +19,7 @@ $ perl segfault.pl
 p Check that we return the expected return value on SEGV
 ! expect return 11
 < $ perl segfault.pl
-$ ${bindir:=.}/tesh
+$ ${bindir:=.}/tesh --no-auto-valgrind
 > Test suite from stdin
 > [(stdin):1] perl segfault.pl
 > Test suite `(stdin)': NOK (<(stdin):1> got signal SIGSEGV)
index 227d93c..e308580 100644 (file)
@@ -14,6 +14,7 @@
 > @@ -0,0 +1 @@
 > +I crashed
 > Test suite `(stdin)': NOK (<(stdin):2> output mismatch)
+> In addition, <(stdin):2> got signal SIGTERM.
 $ ${bindir:=.}/tesh
 
 
index e560f56..92b3400 100644 (file)
@@ -75,19 +75,33 @@ $ ${bindir:=.}/tesh --ignore-jenkins
 > Test suite from stdin
 > [(stdin):1] Test sorting and filtering of output
 > [(stdin):3] true
+> 
 > [(stdin):6] true
+> 
 > [(stdin):8] printf 'profiling: foo\n'
+> 
 > [(stdin):10] printf 'profiling: foo'
+> 
 > [(stdin):13] printf 'profiling: foo\n'
+> 
 > [(stdin):16] printf 'profiling: foo'
+> 
 > [(stdin):18] printf 'a\nb\nc\nd\n'
+> 
 > [(stdin):24] printf 'a\nb\nc\nd'
+> 
 > [(stdin):31] printf 'c\nd\nb\na\n'
+> 
 > [(stdin):38] printf 'c\nd\nb\na'
+> 
 > [(stdin):44] printf 'a\nprofiling: foo\nprofiling: bar\nb\nc\nd\nprofiling: baz\n'
+> 
 > [(stdin):50] printf 'a\nprofiling: foo\nprofiling: bar\nb\nc\nd\nprofiling: baz'
+> 
 > [(stdin):57] printf 'c\nprofiling: foo\nprofiling: bar\nd\nb\na\nprofiling: baz\n'
+> 
 > [(stdin):64] printf 'c\nprofiling: foo\nprofiling: bar\nd\nb\na\nprofiling: baz'
+> 
 > Test suite from stdin OK
 
 p Check the Right Prefix Length (19) for "output sort"
index 2baa1b3..0db9022 100755 (executable)
@@ -79,14 +79,24 @@ def fatal_error(msg):
     print("[Tesh/CRITICAL] " + str(msg))
     tesh_exit(1)
 
+# retrocompatibility: support ${aaa:=.} variable format
+def replace_perl_variables(arg):
+    vname = arg.group(1)
+    vdefault = arg.group(2)
+    if vname in os.environ:
+        return "$" + vname
+    return vdefault
 
 def setenv(arg):
     """
     Set an environment variable.
     arg must be a string with the format "variable=value"
     """
-    print("[Tesh/INFO] setenv " + arg)
+    if '$' in arg:
+        arg = re.sub(r"\${(\w+):=([^}]*)}", replace_perl_variables, arg)
+        arg = expandvars2(arg)
     (var, val) = arg.split("=", 1)
+    print("[Tesh/INFO] setenv " + var + "=" + val)
     os.environ[var] = val
     # os.putenv(var, val) does not work
     # see http://stackoverflow.com/questions/17705419/python-os-environ-os-putenv-usr-bin-env
@@ -196,6 +206,7 @@ class TeshState(Singleton):
         self.args_suffix = ""
         self.ignore_regexps_common = []
         self.jenkins = False  # not a Jenkins run by default
+        self.auto_valgrind = True
         self.timeout = 10  # default value: 10 sec
         self.wrapper = None
         self.keep = False
@@ -237,6 +248,7 @@ class Cmd:
         self.output_display = False
 
         self.sort = -1
+        self.rerun_with_valgrind = False
 
         self.ignore_regexps = TeshState().ignore_regexps_common
 
@@ -302,20 +314,21 @@ class Cmd:
             _thread.start_new_thread(Cmd._run, (self, lock))
         else:
             self._run()
+            if self.rerun_with_valgrind and TeshState().auto_valgrind:
+                print('\n\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
+                print(      'XXXXXXXXX Rerunning this test with valgrind to help debugging it XXXXXXXXX')
+                print(      'XXXXXXXX (this will fail if valgrind is not installed, of course) XXXXXXXX')
+                print(      'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n\n')
+
+                self.args = "valgrind " + self.args
+                self._run()
         return True
 
+
     def _run(self, lock=None):
         # Python threads loose the cwd
         os.chdir(self.cwd)
 
-        # retrocompatibility: support ${aaa:=.} variable format
-        def replace_perl_variables(arg):
-            vname = arg.group(1)
-            vdefault = arg.group(2)
-            if vname in os.environ:
-                return "$" + vname
-            return vdefault
-
         self.args = re.sub(r"\${(\w+):=([^}]*)}", replace_perl_variables, self.args)
 
         # replace bash environment variables ($THINGS) to their values
@@ -344,8 +357,11 @@ class Cmd:
         self.args += TeshState().args_suffix
 
         logs = list()
-        logs.append("[{file}:{number}] {args}".format(file=FileReader().filename,
-                                                      number=self.linenumber, args=self.args))
+        msg = "[{file}:{number}] {args}".format(file=FileReader().filename, number=self.linenumber, args=self.args)
+        if self.background:
+            logs.append(msg)
+        else:
+            print(msg, flush=True)
 
         args = shlex.split(self.args)
 
@@ -411,13 +427,17 @@ class Cmd:
                 print('\n'.join(logs))
                 return
 
-        if self.output_display:
-            logs.append(str(stdout_data))
-
         # remove text colors
         ansi_escape = re.compile(r'\x1b[^m]*m')
         stdout_data = ansi_escape.sub('', stdout_data)
 
+        if self.output_display:
+            logs.append(str(stdout_data))
+
+        if self.rerun_with_valgrind:
+            print(str(stdout_data), file=sys.stderr)
+            return
+
         if self.ignore_output:
             logs.append("(ignoring the output of <{cmd}> as requested)".format(cmd=cmd_name))
         else:
@@ -461,6 +481,18 @@ class Cmd:
 
                 logs.append("Test suite `{file}': NOK (<{cmd}> output mismatch)".format(
                     file=FileReader().filename, cmd=cmd_name))
+
+                # Also report any failed return code and/or signal we got in case of output mismatch
+                if not proc.returncode in self.expect_return:
+                    if proc.returncode >= 0:
+                        logs.append("In addition, <{cmd}> returned code {code}.".format(
+                            cmd=cmd_name, code=proc.returncode))
+                    else:
+                        logs.append("In addition, <{cmd}> got signal {sig}.".format(cmd=cmd_name,
+                            sig=SIGNALS_TO_NAMES_DICT[-proc.returncode]))
+                    if proc.returncode == -signal.SIGSEGV:
+                        self.rerun_with_valgrind = True
+
                 if lock is not None:
                     lock.release()
                 if TeshState().keep:
@@ -495,6 +527,10 @@ class Cmd:
             logs.append("Test suite `{file}': NOK (<{cmd}> got signal {sig})".format(
                 file=FileReader().filename, cmd=cmd_name,
                 sig=SIGNALS_TO_NAMES_DICT[-proc.returncode]))
+
+            if proc.returncode == -signal.SIGSEGV:
+                self.rerun_with_valgrind = True
+
             if lock is not None:
                 lock.release()
             TeshState().set_return_code(max(-proc.returncode, 1))
@@ -535,6 +571,10 @@ def main():
         '--ignore-jenkins',
         action='store_true',
         help='ignore all cruft generated on SimGrid continuous integration servers')
+    group1.add_argument(
+        '--no-auto-valgrind',
+        action='store_true',
+        help='do not automaticall launch segfaulting commands in valgrind')
     group1.add_argument('--wrapper', metavar='arg', help='Run each command in the provided wrapper (eg valgrind)')
     group1.add_argument(
         '--keep',
@@ -560,6 +600,7 @@ def main():
             re.compile(r"For details see http://code\.google\.com/p/address-sanitizer/issues/detail\?id=189"),
             re.compile(r"For details see https://github\.com/google/sanitizers/issues/189"),
             re.compile(r"Python runtime initialized with LC_CTYPE=C .*"),
+            re.compile(r"sthread is intercepting the execution of \.*"),
             # Seen on CircleCI
             re.compile(r"cmake: /usr/local/lib/libcurl\.so\.4: no version information available \(required by cmake\)"),
             re.compile(
@@ -568,6 +609,9 @@ def main():
         ]
         TeshState().jenkins = True  # This is a Jenkins build
 
+    if options.no_auto_valgrind:
+        TeshState().auto_valgrind = False
+
     if options.teshfile is None:
         file = FileReader(None)
         print("Test suite from stdin")
@@ -642,7 +686,10 @@ def main():
             cmd.output_display = True
             cmd.ignore_output = True
         elif line[0:15] == "! expect return":
-            cmd.expect_return = [int(line[16:])]
+            try:
+                cmd.expect_return = [int(line[16:])]
+            except ValueError as err:
+                fatal_error("Invalid expect return value: \""+(line[16:])+"\"")
             #print("expect return "+str(int(line[16:])))
         elif line[0:15] == "! expect signal":
             cmd.expect_return = []
@@ -657,11 +704,17 @@ def main():
             if "no" in line[len("! timeout "):]:
                 cmd.timeout = None
             else:
-                cmd.timeout = int(line[len("! timeout "):])
+                try:
+                    cmd.timeout = int(line[len("! timeout "):])
+                except ValueError as err:
+                    fatal_error("Invalid timeout value: \""+(line[len("! timeout "):])+"\"")
 
         elif line[0:len("! output sort")] == "! output sort":
             if len(line) >= len("! output sort "):
-                sort = int(line[len("! output sort "):])
+                try:
+                    sort = int(line[len("! output sort "):])
+                except ValueError as err:
+                    fatal_error("Invalid sort value: \""+(line[len("! output sort "):])+"\"")
             else:
                 sort = 0
             cmd.sort = sort
@@ -672,7 +725,16 @@ def main():
             cmd.add_ignore(line[len("! ignore "):])
 
         else:
-            fatal_error(f"UNRECOGNIZED OPTION LINE: {line}")
+            fatal_error(f"UNRECOGNIZED OPTION LINE: {line}\n"
+            "Valid requests:\n"
+            "   ! output ignore\n"
+            "   ! output sort\n"
+            "   ! output display\n"
+            "   ! setenv XX=YY\n"
+            "   ! ignore XYZ\n"
+            "   ! expect return NN\n"
+            "   ! expect signal NN\n"
+            "   ! timeout NN\n")
 
         line = file.readfullline()