# Build the version number
set(SIMGRID_VERSION_MAJOR "3")
-set(SIMGRID_VERSION_MINOR "30")
+set(SIMGRID_VERSION_MINOR "31")
set(SIMGRID_VERSION_PATCH "1") # odd => git branch; even => stable release or released snapshot
if(${SIMGRID_VERSION_PATCH} EQUAL "0")
-SimGrid (3.30.1) NOT RELEASED YET (v3.31 expected March 20. 2022, 15:33 UTC)
+SimGrid (3.31.1) NOT RELEASED YET (v3.32 expected June 21. 2022, 09:13 UTC)
+
+----------------------------------------------------------------------------
+
+S4U:
+ - kill signal Comm::on_completion that was not working anyway.
+ - Expose signals Activity::on_suspend and Activity::on_resume
+
+SimGrid (3.31) March 22. 2022.
The ненасильство release. We stand against war.
- tracing: ensure that we dump the TI traces continuously during execution and
not just at the end, reducing memory cost and performance hit.
- Update OpenMPI collectives selection logic to match current one (4.1.2)
+ - Add a coherence check for collective operation order and root/MPI_Op
+ coherence. Potentially costly so not activated unless smpi:pendantic is set
+ or -analyze is given.
S4U:
- New signal: Engine::on_simulation_start_cb()
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
include teshsuite/smpi/MBI/CollMatchingGenerator.py
+include teshsuite/smpi/MBI/CollP2PMatchingGenerator.py
+include teshsuite/smpi/MBI/CollP2PMessageRaceGenerator.py
+include teshsuite/smpi/MBI/CollTopoGenerator.py
include teshsuite/smpi/MBI/MBI.py
include teshsuite/smpi/MBI/MBIutils.py
+include teshsuite/smpi/MBI/MissingWaitandStartGenerator.py
+include teshsuite/smpi/MBI/P2PArgGenerator.py
+include teshsuite/smpi/MBI/P2PComGenerator.py
+include teshsuite/smpi/MBI/P2PInvalidComGenerator.py
+include teshsuite/smpi/MBI/P2PLocalConcurrencyGenerator.py
+include teshsuite/smpi/MBI/P2PMatchingANYSRCGenerator.py
+include teshsuite/smpi/MBI/P2PMatchingGenerator.py
+include teshsuite/smpi/MBI/P2PProbeGenerator.py
+include teshsuite/smpi/MBI/RMAArgGenerator.py
+include teshsuite/smpi/MBI/RMAInvalidArgGenerator.py
+include teshsuite/smpi/MBI/RMALocalLocalConcurrencyGenerator.py
+include teshsuite/smpi/MBI/RMAP2PGlobalConcurrencyGenerator.py
+include teshsuite/smpi/MBI/RMARemoteLocalConcurrencyGenerator.py
+include teshsuite/smpi/MBI/RMARemoteRemoteConcurrencyGenerator.py
+include teshsuite/smpi/MBI/RMAReqLifecycleGenerator.py
+include teshsuite/smpi/MBI/RMAWinBufferGenerator.py
include teshsuite/smpi/MBI/ResleakGenerator.py
include teshsuite/smpi/MBI/generator_utils.py
include teshsuite/smpi/MBI/simgrid.py
+ _ _____ _________
+__ _____ _ __ ___(_) ___ _ __ |___ / |___ /___ \
+\ \ / / _ \ '__/ __| |/ _ \| '_ \ |_ \ |_ \ __) |
+ \ V / __/ | \__ \ | (_) | | | | ___) | ___) / __/
+ \_/ \___|_| |___/_|\___/|_| |_| |____(_)____/_____|
+ (unreleased)
+
_ _____ _____ _
__ _____ _ __ ___(_) ___ _ __ |___ / |___ // |
\ \ / / _ \ '__/ __| |/ _ \| '_ \ |_ \ |_ \| |
\ V / __/ | \__ \ | (_) | | | | ___) | ___) | |
\_/ \___|_| |___/_|\___/|_| |_| |____(_)____/|_|
- (unreleased)
+ March 22. 2022
The ненасильство release. We stand against war.
+ * Refactoring the model-checker, enabling synchronization objects and future improvements
+ * Introducing BMF sharing, enabling ptasks in regular models (experimental)
+ * Further complete Python bindings (Mutex, Semaphore and Barrier)
+ * (+ internal refactoring, many bug fixes and documentation improvement)
_ _____ _____ ___
__ _____ _ __ ___(_) ___ _ __ |___ / |___ / / _ \
\ \ / / _ \ '__/ __| |/ _ \| '_ \ |_ \ |_ \| | | |
Last, the main development of SimGrid is done on [Framagit](https://framagit.org/simgrid/simgrid/),
but we also maintain a [GitHub mirror](https://github.com/simgrid/simgrid/) and an [Inria GitLab mirror](https://gitlab.inria.fr/simgrid/simgrid),
-Thanks for using our software. Please do great things with it and tell
-the world about it. Tell us, too, because we love to have positive
-feedback. Welcome to our community.
+Thanks for using our software. Please do great things with it and tell the world about it.
+Tell us, too, because we love to have positive feedback. Welcome to our community.
Cheers,
Da SimGrid Team.
[license-badge]: https://img.shields.io/badge/License-LGPL%20v2.1-blue.svg
[release-badge]: https://img.shields.io/github/release/simgrid/simgrid.svg
-[release-link]: https://gforge.inria.fr/frs/?group_id=12
- Release notes in the documentation
- The content of the future mail is part of the documentation, since
we won't send mails once gforge is definitly turned off.
+ - The date of the release is marked in the title
- Tests
- The "make distcheck" target works (tested by jenkins)
- All tests pass on everything on ci + AppVeyor
@subsection inside_release_c_publishing Publishing the release if it's a stable one (3.XX not 3.XX.Y)
- Announce the release
- - Mail the simgrid-user mailing list
+ - Mail the https://sympa.inria.fr/sympa/review/simgrid-community mailing list
- the NEWS chunk in the mail;
- Hall of Fame in the mail
git shortlog -se v3.29..
- Kill the one for the current release and remove all code that were
mandated by the deprecated functions (both in source and headers).
- Do the possible cleanups now that these features are gone.
+- Regenerate the unstable docker with this new version
Release numbering semantic:
- 3.X is a named release.
option. For example, ``--cfg=plugin:help`` will give you the list
of plugins available in your installation of SimGrid.
+- **bmf/max-iterations:** :ref:`cfg=bmf/max-iterations`
+- **bmf/precision:** :ref:`cfg=bmf/precision`
+
- **contexts/factory:** :ref:`cfg=contexts/factory`
- **contexts/guard-size:** :ref:`cfg=contexts/guard-size`
- **contexts/nthreads:** :ref:`cfg=contexts/nthreads`
the dependency induced by the backbone), but through a complicated
and slow pattern that follows the actual dependencies.
+.. _cfg=bmf/precision:
.. _cfg=maxmin/precision:
.. _cfg=surf/precision:
Numerical Precision
...................
-**Option** ``maxmin/precision`` **Default:** 0.00001 (in flops or bytes) |br|
-**Option** ``surf/precision`` **Default:** 0.00001 (in seconds)
+**Option** ``maxmin/precision`` **Default:** 1e-5 (in flops or bytes) |br|
+**Option** ``surf/precision`` **Default:** 1e-9 (in seconds) |br|
+**Option** ``bmf/precision`` **Default:** 1e-12 (no unit)
The analytical models handle a lot of floating point values. It is
possible to change the epsilon used to update and compare them through
on highly constrained scenarios, but the simulation speed suffers of this
setting on regular (less constrained) scenarios so it is off by default.
+.. _cfg=bmf/max-iterations:
+
+BMF settings
+............
+
+**Option** ``bmf/max-iterations`` **Default:** 1000
+
+It may happen in some settings that the BMF solver fails to converge to
+a solution, so there is a hard limit on the amount of iteration count to
+avoid infinite loops.
+
.. _options_model_network:
Configuring the Network Model
XBT_ATTRIB_NORETURN= \
XBT_ATTRIB_UNUSED= \
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(cname,parent,desc)= \
- XBT_ATTRIB_DEPRECATED_v332(mesg)= \
XBT_ATTRIB_DEPRECATED_v333(mesg)= \
XBT_ATTRIB_DEPRECATED_v334(mesg)= \
- XBT_ATTRIB_DEPRECATED_v335(mesg)=
+ XBT_ATTRIB_DEPRECATED_v335(mesg)= \
+ XBT_ATTRIB_DEPRECATED_v336(mesg)=
Finally, on the SMPI front, we introduced a :ref:`new documentation section <models_calibration>` on calibrating the SMPI models from your
measurements and fixed some issues with the replay mechanism.
-Version 3.31 (not released yet)
--------------------------------
-
-Expected: spring 2022
+Version 3.31 (March 22. 2022)
+-----------------------------
**On the model checking front**, the long awaited big bang finally occurred, greatly simplifying future evolution.
it straightforward to model multithreaded computational kernels, and it comes with an illustrating example. It can be seen as a simplified ptask, but
since it does not mix bytes and flops and has a homogeneous consumption over a single CPU, it perfectly fits with the classical SimGrid model.
+This release also introduces steadily progress **on the bindings front**, introducing in particular the Mutex, Barrier and Semaphore to your python scripts.
.. |br| raw:: html
.. code-block:: console
[0.000000] [mc_ModelChecker/INFO] Counter-example execution trace:
- [0.000000] [mc_ModelChecker/INFO] [(1)Tremblay (server)] iRecv(dst=(1)Tremblay (server), buff=(verbose only), size=(verbose only))
- [0.000000] [mc_ModelChecker/INFO] [(2)Jupiter (client)] iSend(src=(2)Jupiter (client), buff=(verbose only), size=(verbose only))
- [0.000000] [mc_ModelChecker/INFO] [(1)Tremblay (server)] Wait(comm=(verbose only) [(2)Jupiter (client)-> (1)Tremblay (server)])
- [0.000000] [mc_ModelChecker/INFO] [(1)Tremblay (server)] iRecv(dst=(1)Tremblay (server), buff=(verbose only), size=(verbose only))
- [0.000000] [mc_ModelChecker/INFO] [(2)Jupiter (client)] Wait(comm=(verbose only) [(2)Jupiter (client)-> (1)Tremblay (server)])
- [0.000000] [mc_ModelChecker/INFO] [(4)Ginette (client)] iSend(src=(4)Ginette (client), buff=(verbose only), size=(verbose only))
- [0.000000] [mc_ModelChecker/INFO] [(1)Tremblay (server)] Wait(comm=(verbose only) [(4)Ginette (client)-> (1)Tremblay (server)])
- [0.000000] [mc_ModelChecker/INFO] [(1)Tremblay (server)] iRecv(dst=(1)Tremblay (server), buff=(verbose only), size=(verbose only))
- [0.000000] [mc_ModelChecker/INFO] [(3)Bourassa (client)] iSend(src=(3)Bourassa (client), buff=(verbose only), size=(verbose only))
- [0.000000] [mc_ModelChecker/INFO] [(1)Tremblay (server)] Wait(comm=(verbose only) [(3)Bourassa (client)-> (1)Tremblay (server)])
+ [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] 1: iRecv(mbox=0)
+ [0.000000] [mc_ModelChecker/INFO] 2: WaitComm(from 2 to 1, mbox=0, no timeout)
+ [0.000000] [mc_ModelChecker/INFO] 4: iSend(mbox=0)
+ [0.000000] [mc_ModelChecker/INFO] 1: WaitComm(from 4 to 1, mbox=0, no timeout)
+ [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)
- Then, the execution path is given.
.. code-block:: console
- [0.000000] [mc_safety/INFO] Expanded states = 22
- [0.000000] [mc_safety/INFO] Visited states = 56
- [0.000000] [mc_safety/INFO] Executed transitions = 52
+ [0.000000] [mc_dfs/INFO] DFS exploration ended. 22 unique states visited; 4 backtracks (56 transition replays, 30 states visited overall)
- Finally, the application stack trace is displayed as the model-checker sees it. It should be the same as the one displayed from the
application side, unless you found a bug our tools.
try:
import cPickle as pickle
-except:
+except ImportError:
import pickle
import hashlib
def encode_output(s):
if isinstance(s, str):
return s
- else:
- return s.encode('utf-8')
+ return s.encode('utf-8')
def find_source_files(input_path, excludes):
""" Get a list of filenames for all Java source files within the given
if see.startswith('<a href'):
# HTML link -- <a href="...">...</a>
return self.__html_to_rst(see)
- elif '"' in see:
+ if '"' in see:
# Plain text
return see
- else:
- # Type reference (default)
- return ':java:ref:`%s`' % (see.replace('#', '.').replace(' ', ''),)
+
+ # Type reference (default)
+ return ':java:ref:`%s`' % (see.replace('#', '.').replace(' ', ''),)
def compile_type(self, declaration):
signature = util.StringBuilder()
parts.append(nodes.Text(dim, dim))
return parts
- else:
- type_repr = formatter.output_type(typ).build()
- return [nodes.Text(type_repr, type_repr)]
+
+ type_repr = formatter.output_type(typ).build()
+ return [nodes.Text(type_repr, type_repr)]
def _build_type_node_list(self, types):
parts = self._build_type_node(types[0])
if handle:
return handle(sig, signode)
- else:
- raise NotImplementedError
+ raise NotImplementedError
- def get_index_text(self, package, type, name):
+ def get_index_text(self, package, typ, name):
raise NotImplementedError
def get_package(self):
def add_target_and_index(self, name, sig, signode):
package = self.get_package()
- type = self.get_type();
+ typ = self.get_type()
- fullname = '.'.join(filter(None, (package, type, name)))
+ fullname = '.'.join(filter(None, (package, typ, name)))
basename = fullname.partition('(')[0]
# note target
objects[fullname] = (self.env.docname, self.objtype, basename)
- indextext = self.get_index_text(package, type, name)
+ indextext = self.get_index_text(package, typ, name)
if indextext:
self.indexnode['entries'].append(_create_indexnode(indextext, fullname))
param_reprs = [formatter.output_type(param.type, with_generics=False).build() for param in member.parameters]
return member.name + '(' + ', '.join(param_reprs) + ')'
- def get_index_text(self, package, type, name):
+ def get_index_text(self, package, typ, name):
return _('%s (Java method)' % (name,))
class JavaConstructor(JavaObject):
param_reprs = [formatter.output_type(param.type, with_generics=False).build() for param in member.parameters]
return '%s(%s)' % (member.name, ', '.join(param_reprs))
- def get_index_text(self, package, type, name):
+ def get_index_text(self, package, typ, name):
return _('%s (Java constructor)' % (name,))
class JavaType(JavaObject):
return member.name
- def get_index_text(self, package, type, name):
+ def get_index_text(self, package, typ, name):
return _('%s (Java %s)' % (name, self.declaration_type))
class JavaField(JavaObject):
return declarator.name
- def get_index_text(self, package, type, name):
+ def get_index_text(self, package, typ, name):
return _('%s (Java field)' % (name,))
class JavaPackage(Directive):
for fullname, (_, _, basename) in objects.items():
if fullname.endswith(suffix):
return make_ref(fullname)
- elif basename.endswith(basename_suffix):
+ if basename.endswith(basename_suffix):
basename_match = fullname
if basename_match:
if ref:
ref.append(contnode)
return ref
- else:
- return None
+ return None
def get_objects(self):
- for refname, (docname, type, _) in self.data['objects'].items():
- yield (refname, refname, type, docname, refname, 1)
+ for refname, (docname, typ, _) in self.data['objects'].items():
+ yield (refname, refname, typ, docname, refname, 1)
def _create_indexnode(indextext, fullname):
# See https://github.com/sphinx-doc/sphinx/issues/2673
if version_info < (1, 4):
return ('single', indextext, fullname, '')
- else:
- return ('single', indextext, fullname, '', None)
+ return ('single', indextext, fullname, '', None)
output.append(' ')
@formatter
-def output_type(type, output, with_generics=True):
- if not type:
+def output_type(typ, output, with_generics=True):
+ if not typ:
output.append('void')
return
- if type.dimensions:
- dim = '[]' * len(type.dimensions)
+ if typ.dimensions:
+ dim = '[]' * len(typ.dimensions)
else:
dim = ''
- if isinstance(type, javalang.tree.BasicType):
- output.append(type.name)
+ if isinstance(typ, javalang.tree.BasicType):
+ output.append(typ.name)
else:
- while type:
- output.append(type.name)
+ while typ:
+ output.append(typ.name)
if with_generics:
- output_type_args(type.arguments, output)
+ output_type_args(typ.arguments, output)
- type = type.sub_type
+ typ = typ.sub_type
- if type:
+ if typ:
output.append('.')
output.append(dim)
def _unicode(self, s):
if isinstance(s, unicode):
return s
- else:
- return unicode(s, 'utf8')
+ return unicode(s, 'utf8')
def _separate(self, s):
return u'\n\n' + s + u'\n\n'
def _role(self, role, s, label=None):
if label:
return self._escape_inline(':%s:`%s <%s>`' % (role, label, s))
- else:
- return self._escape_inline(':%s:`%s`' % (role, s))
+ return self._escape_inline(':%s:`%s`' % (role, s))
def _directive(self, directive, body=None):
header = '\n\n.. %s::\n\n' % (directive,)
if body:
return header + self._left_justify(body, 3) + '\n\n'
- else:
- return header + '\n'
+ return header + '\n'
def _hyperlink(self, target, label):
return self._escape_inline('`%s <%s>`_' % (label, target))
if shift < 0:
return '\n'.join(l[-shift:] for l in lines)
- else:
- prefix = ' ' * shift
- return '\n'.join(prefix + l for l in lines)
+
+ prefix = ' ' * shift
+ return '\n'.join(prefix + l for l in lines)
def _compress_whitespace(self, s, replace=' ', newlines=True):
if newlines:
return self._whitespace_with_newline.sub(replace, s)
- else:
- return self._whitespace.sub(replace, s)
+ return self._whitespace.sub(replace, s)
# --------------------------------------------------------------------------
# ---- DOM Tree Processing ----
if node.name == 'a':
if 'name' in node.attrs:
return self._separate('.. _' + node['name'] + ':')
- elif 'href' in node.attrs:
+ if 'href' in node.attrs:
target = node['href']
label = self._compress_whitespace(self._process_text(node).strip('\n'))
if target.startswith('#'):
return self._role('ref', target[1:], label)
- elif target.startswith('@'):
+ if target.startswith('@'):
return self._role('java:ref', target[1:], label)
- else:
- return self._hyperlink(target, label)
+ return self._hyperlink(target, label)
if node.name == 'ul':
items = [self._process(n) for n in node.find_all('li', recursive=False)]
class Directive(object):
- def __init__(self, type, argument=''):
- self.type = type
+ def __init__(self, typ, argument=''):
+ self.type = typ
self.argument = argument
self.options = []
.. 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_suspend_cb
+ .. doxygenfunction:: simgrid::s4u::Activity::on_resume_cb
+
.. _API_s4u_Comm:
=============
the calls instead (MPI_Send will become smpi_mpi_send). Some functions
may have different signatures than their MPI counterpart, please check
the other algorithms or contact us using the `>SimGrid
-developers mailing list <http://lists.gforge.inria.fr/mailman/listinfo/simgrid-devel>`_.
+user mailing list <https://sympa.inria.fr/sympa/info/simgrid-community>`_,
+or on `>Mattermost <https://framateam.org/simgrid/channels/town-square>`_.
Example: adding a "pair" version of the Alltoall collective.
author = u'The SimGrid Team'
# The short X.Y version
-version = u'3.30.1'
+version = u'3.31.1'
# -- General configuration ---------------------------------------------------
> [ 3.000000] (C@Ginette) And now, induce a deadlock by waiting for a message that will never come
>
>
-> [ 3.000000] (maestro@) Oops! Deadlock or code not perfectly clean.
+> [ 3.000000] (maestro@) Oops! Deadlock detected, some activities are still around but will never complete. This usually happens when the user code is not perfectly clean.
> [ 3.000000] (maestro@) 1 actors are still running, waiting for something.
> [ 3.000000] (maestro@) Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
> [ 3.000000] (maestro@) Actor 3 (C@Ginette): waiting for communication activity 0xdeadbeef () in state WAITING to finish
> [ 3.000000] (C@Ginette) And now, induce a deadlock by waiting for a message that will never come
>
>
-> [ 3.000000] (maestro@) Oops! Deadlock or code not perfectly clean.
+> [ 3.000000] (maestro@) Oops! Deadlock detected, some activities are still around but will never complete. This usually happens when the user code is not perfectly clean.
> [ 3.000000] (maestro@) 1 actors are still running, waiting for something.
> [ 3.000000] (maestro@) Legend of the following listing: "Actor <pid> (<name>@<host>): <status>"
> [ 3.000000] (maestro@) Actor 3 (C@Ginette): waiting for communication activity 0xdeadbeef () in state WAITING to finish
> [Checker] Start a DFS exploration. Reduction is: dpor.
> [Checker] Execute 1: BARRIER_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] Execute 2: BARRIER_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves)
> [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 3, state: 3, 0 interleaves)
> [Checker] Execute 2: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 4, 0 interleaves)
+> [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] INDEPENDENT Transitions:
> [Checker] BARRIER_WAIT(barrier: 0) (state=3)
> [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 4, 0 interleaves)
> [Checker] Execute 2: BARRIER_WAIT(barrier: 0) (stack depth: 5, state: 5, 0 interleaves)
> [Checker] Execute 3: BARRIER_WAIT(barrier: 0) (stack depth: 6, state: 6, 0 interleaves)
+> [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] INDEPENDENT Transitions:
> [Checker] BARRIER_WAIT(barrier: 0) (state=5)
$ ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:1 --log=s4u_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
> [Checker] Start a DFS exploration. Reduction is: dpor.
> [App ] Configuration change: Set 'actors' to '1'
-> [Checker] Execute 2: MUTEX_LOCK(mutex: 0, owner:2) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner:2) (stack depth: 2, state: 2, 0 interleaves)
-> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 3, state: 3, 0 interleaves)
-> [Checker] Execute 3: MUTEX_LOCK(mutex: 0, owner:3) (stack depth: 4, state: 4, 0 interleaves)
-> [Checker] Execute 3: MUTEX_WAIT(mutex: 0, owner:3) (stack depth: 5, state: 5, 0 interleaves)
-> [Checker] Execute 3: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 6, state: 6, 0 interleaves)
-> [Checker] Backtracking from 2;2;2;3;3;3;0
+> [Checker] Execute 1: MUTEX_LOCK(mutex: 0, owner:1) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Execute 1: MUTEX_WAIT(mutex: 0, owner:1) (stack depth: 2, state: 2, 0 interleaves)
+> [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 3, state: 3, 0 interleaves)
+> [Checker] Execute 2: MUTEX_LOCK(mutex: 0, owner:2) (stack depth: 4, state: 4, 0 interleaves)
+> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner:2) (stack depth: 5, state: 5, 0 interleaves)
+> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 6, state: 6, 0 interleaves)
+> [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] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 0, owner:-1) (state=3)
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=4)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=4)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=2)
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=4)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:1) (state=2)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=4)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=1)
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=4)
-> [Checker] Execute 3: MUTEX_LOCK(mutex: 0, owner:3) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 2: MUTEX_LOCK(mutex: 0, owner:3) (stack depth: 2, state: 8, 0 interleaves)
-> [Checker] Execute 3: MUTEX_WAIT(mutex: 0, owner:3) (stack depth: 3, state: 9, 0 interleaves)
-> [Checker] Execute 3: MUTEX_UNLOCK(mutex: 0, owner:2) (stack depth: 4, state: 10, 0 interleaves)
-> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner:2) (stack depth: 5, state: 11, 0 interleaves)
-> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 6, state: 12, 0 interleaves)
-> [Checker] Backtracking from 3;2;3;3;2;2;0
+> [Checker] MUTEX_LOCK(mutex: 0, owner:1) (state=1)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=4)
+> [Checker] Execute 2: MUTEX_LOCK(mutex: 0, owner:2) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Execute 1: MUTEX_LOCK(mutex: 0, owner:2) (stack depth: 2, state: 8, 0 interleaves)
+> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner:2) (stack depth: 3, state: 9, 0 interleaves)
+> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner:1) (stack depth: 4, state: 10, 0 interleaves)
+> [Checker] Execute 1: MUTEX_WAIT(mutex: 0, owner:1) (stack depth: 5, state: 11, 0 interleaves)
+> [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 6, state: 12, 0 interleaves)
+> [Checker] Execution came to an end at 2;1;2;2;1;1;0 (state: 13, depth: 7)
+> [Checker] Backtracking from 2;1;2;2;1;1;0
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_UNLOCK(mutex: 0, owner:2) (state=10)
-> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=11)
-> [Checker] Backtracking from 3;2;3;3
+> [Checker] MUTEX_UNLOCK(mutex: 0, owner:1) (state=10)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:1) (state=11)
+> [Checker] Backtracking from 2;1;2;2
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=8)
-> [Checker] MUTEX_WAIT(mutex: 0, owner:3) (state=9)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=8)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=9)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=1)
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=8)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=1)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=8)
> [Checker] DFS exploration ended. 13 unique states visited; 3 backtracks (18 transition replays, 3 states visited overall)
$ ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:2 --log=s4u_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
> [Checker] Start a DFS exploration. Reduction is: dpor.
> [App ] Configuration change: Set 'actors' to '2'
-> [Checker] Execute 2: MUTEX_LOCK(mutex: 0, owner:2) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner:2) (stack depth: 2, state: 2, 0 interleaves)
-> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 3, state: 3, 0 interleaves)
-> [Checker] Execute 3: MUTEX_LOCK(mutex: 0, owner:3) (stack depth: 4, state: 4, 0 interleaves)
-> [Checker] Execute 3: MUTEX_WAIT(mutex: 0, owner:3) (stack depth: 5, state: 5, 0 interleaves)
-> [Checker] Execute 3: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 6, state: 6, 0 interleaves)
-> [Checker] Execute 4: MUTEX_LOCK(mutex: 1, owner:4) (stack depth: 7, state: 7, 0 interleaves)
-> [Checker] Execute 4: MUTEX_WAIT(mutex: 1, owner:4) (stack depth: 8, state: 8, 0 interleaves)
-> [Checker] Execute 4: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 9, state: 9, 0 interleaves)
-> [Checker] Execute 5: MUTEX_LOCK(mutex: 1, owner:5) (stack depth: 10, state: 10, 0 interleaves)
-> [Checker] Execute 5: MUTEX_WAIT(mutex: 1, owner:5) (stack depth: 11, state: 11, 0 interleaves)
-> [Checker] Execute 5: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 12, state: 12, 0 interleaves)
-> [Checker] Backtracking from 2;2;2;3;3;3;4;4;4;5;5;5;0
+> [Checker] Execute 1: MUTEX_LOCK(mutex: 0, owner:1) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Execute 1: MUTEX_WAIT(mutex: 0, owner:1) (stack depth: 2, state: 2, 0 interleaves)
+> [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 3, state: 3, 0 interleaves)
+> [Checker] Execute 2: MUTEX_LOCK(mutex: 0, owner:2) (stack depth: 4, state: 4, 0 interleaves)
+> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner:2) (stack depth: 5, state: 5, 0 interleaves)
+> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 6, state: 6, 0 interleaves)
+> [Checker] Execute 3: MUTEX_LOCK(mutex: 1, owner:3) (stack depth: 7, state: 7, 0 interleaves)
+> [Checker] Execute 3: MUTEX_WAIT(mutex: 1, owner:3) (stack depth: 8, state: 8, 0 interleaves)
+> [Checker] Execute 3: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 9, state: 9, 0 interleaves)
+> [Checker] Execute 4: MUTEX_LOCK(mutex: 1, owner:4) (stack depth: 10, state: 10, 0 interleaves)
+> [Checker] Execute 4: MUTEX_WAIT(mutex: 1, owner:4) (stack depth: 11, state: 11, 0 interleaves)
+> [Checker] Execute 4: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 12, state: 12, 0 interleaves)
+> [Checker] Execution came to an end at 1;1;1;2;2;2;3;3;3;4;4;4;0 (state: 13, depth: 13)
+> [Checker] Backtracking from 1;1;1;2;2;2;3;3;3;4;4;4;0
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 1, owner:-1) (state=9)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=10)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=10)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 1, owner:4) (state=8)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=10)
+> [Checker] MUTEX_WAIT(mutex: 1, owner:3) (state=8)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=10)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=10)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=10)
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 0, owner:-1) (state=6)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=7)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:3) (state=5)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=5)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=7)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=4)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=4)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=7)
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 0, owner:-1) (state=3)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=7)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=2)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:1) (state=2)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=7)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=1)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
-> [Checker] Execute 5: MUTEX_LOCK(mutex: 1, owner:5) (stack depth: 7, state: 7, 0 interleaves)
-> [Checker] Execute 4: MUTEX_LOCK(mutex: 1, owner:5) (stack depth: 8, state: 14, 0 interleaves)
-> [Checker] Execute 5: MUTEX_WAIT(mutex: 1, owner:5) (stack depth: 9, state: 15, 0 interleaves)
-> [Checker] Execute 5: MUTEX_UNLOCK(mutex: 1, owner:4) (stack depth: 10, state: 16, 0 interleaves)
-> [Checker] Execute 4: MUTEX_WAIT(mutex: 1, owner:4) (stack depth: 11, state: 17, 0 interleaves)
-> [Checker] Execute 4: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 12, state: 18, 0 interleaves)
-> [Checker] Backtracking from 2;2;2;3;3;3;5;4;5;5;4;4;0
+> [Checker] MUTEX_LOCK(mutex: 0, owner:1) (state=1)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=7)
+> [Checker] Execute 4: MUTEX_LOCK(mutex: 1, owner:4) (stack depth: 7, state: 7, 0 interleaves)
+> [Checker] Execute 3: MUTEX_LOCK(mutex: 1, owner:4) (stack depth: 8, state: 14, 0 interleaves)
+> [Checker] Execute 4: MUTEX_WAIT(mutex: 1, owner:4) (stack depth: 9, state: 15, 0 interleaves)
+> [Checker] Execute 4: MUTEX_UNLOCK(mutex: 1, owner:3) (stack depth: 10, state: 16, 0 interleaves)
+> [Checker] Execute 3: MUTEX_WAIT(mutex: 1, owner:3) (stack depth: 11, state: 17, 0 interleaves)
+> [Checker] Execute 3: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 12, state: 18, 0 interleaves)
+> [Checker] Execution came to an end at 1;1;1;2;2;2;4;3;4;4;3;3;0 (state: 19, depth: 13)
+> [Checker] Backtracking from 1;1;1;2;2;2;4;3;4;4;3;3;0
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_UNLOCK(mutex: 1, owner:4) (state=16)
-> [Checker] MUTEX_WAIT(mutex: 1, owner:4) (state=17)
-> [Checker] Backtracking from 2;2;2;3;3;3;5;4;5;5
+> [Checker] MUTEX_UNLOCK(mutex: 1, owner:3) (state=16)
+> [Checker] MUTEX_WAIT(mutex: 1, owner:3) (state=17)
+> [Checker] Backtracking from 1;1;1;2;2;2;4;3;4;4
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=14)
-> [Checker] MUTEX_WAIT(mutex: 1, owner:5) (state=15)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=14)
+> [Checker] MUTEX_WAIT(mutex: 1, owner:4) (state=15)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=7)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=14)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=14)
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 0, owner:-1) (state=6)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:3) (state=5)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=7)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=5)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=4)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=4)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 0, owner:-1) (state=3)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=2)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=7)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:1) (state=2)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=1)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=7)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:1) (state=1)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=7)
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 0, owner:-1) (state=3)
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=4)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=4)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=2)
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=4)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:1) (state=2)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=4)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=1)
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=4)
-> [Checker] Execute 3: MUTEX_LOCK(mutex: 0, owner:3) (stack depth: 1, state: 1, 0 interleaves)
-> [Checker] Execute 2: MUTEX_LOCK(mutex: 0, owner:3) (stack depth: 2, state: 20, 0 interleaves)
-> [Checker] Execute 3: MUTEX_WAIT(mutex: 0, owner:3) (stack depth: 3, state: 21, 0 interleaves)
-> [Checker] Execute 3: MUTEX_UNLOCK(mutex: 0, owner:2) (stack depth: 4, state: 22, 0 interleaves)
-> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner:2) (stack depth: 5, state: 23, 0 interleaves)
-> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 6, state: 24, 0 interleaves)
-> [Checker] Execute 4: MUTEX_LOCK(mutex: 1, owner:4) (stack depth: 7, state: 25, 0 interleaves)
-> [Checker] Execute 4: MUTEX_WAIT(mutex: 1, owner:4) (stack depth: 8, state: 26, 0 interleaves)
-> [Checker] Execute 4: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 9, state: 27, 0 interleaves)
-> [Checker] Execute 5: MUTEX_LOCK(mutex: 1, owner:5) (stack depth: 10, state: 28, 0 interleaves)
-> [Checker] Execute 5: MUTEX_WAIT(mutex: 1, owner:5) (stack depth: 11, state: 29, 0 interleaves)
-> [Checker] Execute 5: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 12, state: 30, 0 interleaves)
-> [Checker] Backtracking from 3;2;3;3;2;2;4;4;4;5;5;5;0
+> [Checker] MUTEX_LOCK(mutex: 0, owner:1) (state=1)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=4)
+> [Checker] Execute 2: MUTEX_LOCK(mutex: 0, owner:2) (stack depth: 1, state: 1, 0 interleaves)
+> [Checker] Execute 1: MUTEX_LOCK(mutex: 0, owner:2) (stack depth: 2, state: 20, 0 interleaves)
+> [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner:2) (stack depth: 3, state: 21, 0 interleaves)
+> [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner:1) (stack depth: 4, state: 22, 0 interleaves)
+> [Checker] Execute 1: MUTEX_WAIT(mutex: 0, owner:1) (stack depth: 5, state: 23, 0 interleaves)
+> [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 6, state: 24, 0 interleaves)
+> [Checker] Execute 3: MUTEX_LOCK(mutex: 1, owner:3) (stack depth: 7, state: 25, 0 interleaves)
+> [Checker] Execute 3: MUTEX_WAIT(mutex: 1, owner:3) (stack depth: 8, state: 26, 0 interleaves)
+> [Checker] Execute 3: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 9, state: 27, 0 interleaves)
+> [Checker] Execute 4: MUTEX_LOCK(mutex: 1, owner:4) (stack depth: 10, state: 28, 0 interleaves)
+> [Checker] Execute 4: MUTEX_WAIT(mutex: 1, owner:4) (stack depth: 11, state: 29, 0 interleaves)
+> [Checker] Execute 4: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 12, state: 30, 0 interleaves)
+> [Checker] Execution came to an end at 2;1;2;2;1;1;3;3;3;4;4;4;0 (state: 31, depth: 13)
+> [Checker] Backtracking from 2;1;2;2;1;1;3;3;3;4;4;4;0
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 1, owner:-1) (state=27)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=28)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=28)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 1, owner:4) (state=26)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=28)
+> [Checker] MUTEX_WAIT(mutex: 1, owner:3) (state=26)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=28)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=28)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=25)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=28)
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 0, owner:-1) (state=24)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=23)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:1) (state=23)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_UNLOCK(mutex: 0, owner:2) (state=22)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
+> [Checker] MUTEX_UNLOCK(mutex: 0, owner:1) (state=22)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:3) (state=21)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=21)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=20)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=20)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=1)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
-> [Checker] Execute 5: MUTEX_LOCK(mutex: 1, owner:5) (stack depth: 7, state: 25, 0 interleaves)
-> [Checker] Execute 4: MUTEX_LOCK(mutex: 1, owner:5) (stack depth: 8, state: 32, 0 interleaves)
-> [Checker] Execute 5: MUTEX_WAIT(mutex: 1, owner:5) (stack depth: 9, state: 33, 0 interleaves)
-> [Checker] Execute 5: MUTEX_UNLOCK(mutex: 1, owner:4) (stack depth: 10, state: 34, 0 interleaves)
-> [Checker] Execute 4: MUTEX_WAIT(mutex: 1, owner:4) (stack depth: 11, state: 35, 0 interleaves)
-> [Checker] Execute 4: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 12, state: 36, 0 interleaves)
-> [Checker] Backtracking from 3;2;3;3;2;2;5;4;5;5;4;4;0
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=1)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:3) (state=25)
+> [Checker] Execute 4: MUTEX_LOCK(mutex: 1, owner:4) (stack depth: 7, state: 25, 0 interleaves)
+> [Checker] Execute 3: MUTEX_LOCK(mutex: 1, owner:4) (stack depth: 8, state: 32, 0 interleaves)
+> [Checker] Execute 4: MUTEX_WAIT(mutex: 1, owner:4) (stack depth: 9, state: 33, 0 interleaves)
+> [Checker] Execute 4: MUTEX_UNLOCK(mutex: 1, owner:3) (stack depth: 10, state: 34, 0 interleaves)
+> [Checker] Execute 3: MUTEX_WAIT(mutex: 1, owner:3) (stack depth: 11, state: 35, 0 interleaves)
+> [Checker] Execute 3: MUTEX_UNLOCK(mutex: 1, owner:-1) (stack depth: 12, state: 36, 0 interleaves)
+> [Checker] Execution came to an end at 2;1;2;2;1;1;4;3;4;4;3;3;0 (state: 37, depth: 13)
+> [Checker] Backtracking from 2;1;2;2;1;1;4;3;4;4;3;3;0
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_UNLOCK(mutex: 1, owner:4) (state=34)
-> [Checker] MUTEX_WAIT(mutex: 1, owner:4) (state=35)
-> [Checker] Backtracking from 3;2;3;3;2;2;5;4;5;5
+> [Checker] MUTEX_UNLOCK(mutex: 1, owner:3) (state=34)
+> [Checker] MUTEX_WAIT(mutex: 1, owner:3) (state=35)
+> [Checker] Backtracking from 2;1;2;2;1;1;4;3;4;4
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=32)
-> [Checker] MUTEX_WAIT(mutex: 1, owner:5) (state=33)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=32)
+> [Checker] MUTEX_WAIT(mutex: 1, owner:4) (state=33)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=25)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=32)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=32)
> [Checker] INDEPENDENT Transitions:
> [Checker] MUTEX_UNLOCK(mutex: 0, owner:-1) (state=24)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=25)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=23)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=25)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:1) (state=23)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_UNLOCK(mutex: 0, owner:2) (state=22)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=25)
+> [Checker] MUTEX_UNLOCK(mutex: 0, owner:1) (state=22)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_WAIT(mutex: 0, owner:3) (state=21)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=25)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=21)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=20)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=25)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=20)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=1)
-> [Checker] MUTEX_LOCK(mutex: 1, owner:5) (state=25)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=1)
+> [Checker] MUTEX_LOCK(mutex: 1, owner:4) (state=25)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_UNLOCK(mutex: 0, owner:2) (state=22)
-> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=23)
-> [Checker] Backtracking from 3;2;3;3
+> [Checker] MUTEX_UNLOCK(mutex: 0, owner:1) (state=22)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:1) (state=23)
+> [Checker] Backtracking from 2;1;2;2
> [Checker] INDEPENDENT Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=20)
-> [Checker] MUTEX_WAIT(mutex: 0, owner:3) (state=21)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=20)
+> [Checker] MUTEX_WAIT(mutex: 0, owner:2) (state=21)
> [Checker] Dependent Transitions:
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=1)
-> [Checker] MUTEX_LOCK(mutex: 0, owner:3) (state=20)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=1)
+> [Checker] MUTEX_LOCK(mutex: 0, owner:2) (state=20)
> [Checker] DFS exploration ended. 37 unique states visited; 7 backtracks (76 transition replays, 33 states visited overall)
$ ${bindir:=.}/../../../bin/simgrid-mc -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:3 --log=s4u_test.thres:critical
// Nothing specific here: the unlock will be automatic
}
-static void master()
+int main(int argc, char** argv)
{
+ sg4::Engine e(&argc, argv);
+ e.load_platform("../../platforms/two_hosts.xml");
+
/* Create the requested amount of actors pairs. Each pair has a specific mutex and cell in `result`. */
std::vector<int> result(cfg_actor_count.get());
sg4::Actor::create("worker", sg4::Host::by_name("Tremblay"), worker, mutex, std::ref(result[i]));
}
- sg4::this_actor::sleep_for(10);
+ e.run();
+
for (int i = 0; i < cfg_actor_count; i++)
XBT_INFO("Result[%d] -> %d", i, result[i]);
-}
-
-int main(int argc, char **argv)
-{
- sg4::Engine e(&argc, argv);
- e.load_platform("../../platforms/two_hosts.xml");
- sg4::Actor::create("main", e.host_by_name("Tremblay"), master);
- e.run();
return 0;
}
#!/usr/bin/env tesh
$ ${bindir:=.}/s4u-synchro-mutex
-> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
-> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Tremblay:worker:(3) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
-> [Tremblay:worker:(3) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
-> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Tremblay:worker:(5) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
-> [Tremblay:worker:(5) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Jupiter:worker:(6) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
-> [Jupiter:worker:(6) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Tremblay:worker:(7) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
-> [Tremblay:worker:(7) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Jupiter:worker:(8) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
-> [Jupiter:worker:(8) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Tremblay:worker:(9) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
-> [Tremblay:worker:(9) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Jupiter:worker:(10) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
-> [Jupiter:worker:(10) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Tremblay:worker:(11) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
-> [Tremblay:worker:(11) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Jupiter:worker:(12) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
-> [Jupiter:worker:(12) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Tremblay:worker:(13) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
-> [Tremblay:worker:(13) 0.000000] [s4u_test/INFO] I'm done, good bye
-> [Tremblay:main:(1) 10.000000] [s4u_test/INFO] Result[0] -> 2
-> [Tremblay:main:(1) 10.000000] [s4u_test/INFO] Result[1] -> 2
-> [Tremblay:main:(1) 10.000000] [s4u_test/INFO] Result[2] -> 2
-> [Tremblay:main:(1) 10.000000] [s4u_test/INFO] Result[3] -> 2
-> [Tremblay:main:(1) 10.000000] [s4u_test/INFO] Result[4] -> 2
-> [Tremblay:main:(1) 10.000000] [s4u_test/INFO] Result[5] -> 2
+> [Jupiter:worker:(1) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
+> [Jupiter:worker:(1) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
+> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Jupiter:worker:(5) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
+> [Jupiter:worker:(5) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Jupiter:worker:(7) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
+> [Jupiter:worker:(7) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Jupiter:worker:(9) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
+> [Jupiter:worker:(9) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Jupiter:worker:(11) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a lock_guard
+> [Jupiter:worker:(11) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Tremblay:worker:(2) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
+> [Tremblay:worker:(2) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Tremblay:worker:(4) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
+> [Tremblay:worker:(4) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Tremblay:worker:(6) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
+> [Tremblay:worker:(6) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Tremblay:worker:(8) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
+> [Tremblay:worker:(8) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Tremblay:worker:(10) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
+> [Tremblay:worker:(10) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [Tremblay:worker:(12) 0.000000] [s4u_test/INFO] Hello s4u, I'm ready to compute after a regular lock
+> [Tremblay:worker:(12) 0.000000] [s4u_test/INFO] I'm done, good bye
+> [0.000000] [s4u_test/INFO] Result[0] -> 2
+> [0.000000] [s4u_test/INFO] Result[1] -> 2
+> [0.000000] [s4u_test/INFO] Result[2] -> 2
+> [0.000000] [s4u_test/INFO] Result[3] -> 2
+> [0.000000] [s4u_test/INFO] Result[4] -> 2
+> [0.000000] [s4u_test/INFO] Result[5] -> 2
> [Checker] Execute 2: SEM_LOCK(semaphore: 1) (stack depth: 22, state: 22, 0 interleaves)
> [Checker] Execute 2: SEM_WAIT(semaphore: 1, granted: yes) (stack depth: 23, state: 23, 0 interleaves)
> [Checker] Execute 2: SEM_UNLOCK(semaphore: 0) (stack depth: 24, state: 24, 0 interleaves)
+> [Checker] Execution came to an end at 1;1;1;1;2;2;2;1;1;1;2;2;2;1;1;1;2;2;2;1;1;2;2;2;0 (state: 25, depth: 25)
> [Checker] Backtracking from 1;1;1;1;2;2;2;1;1;1;2;2;2;1;1;1;2;2;2;1;1;2;2;2;0
> [Checker] INDEPENDENT Transitions:
> [Checker] SEM_UNLOCK(semaphore: 1) (state=21)
<?xml version='1.0'?>
-<!DOCTYPE platform SYSTEM "http://simgrid.gforge.inria.fr/simgrid/simgrid.dtd">
+<!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
<platform version="4.1">
<zone id="AS0" routing="Floyd">
def worker_context_manager(mutex: Mutex, result: ResultHolder):
+ # When using a context manager, the lock and the unlock are automatic. This is the easiest approach
with mutex:
this_actor.info(f"Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager")
result.value += 1
def worker(mutex: Mutex, result: ResultHolder):
+ # If you lock your mutex manually, you also have to unlock it.
+ # Beware of exceptions preventing your unlock() from being executed!
mutex.lock()
this_actor.info("Hello simgrid, I'm ready to compute after a regular lock")
result.value += 1
this_actor.info("I'm done, good bye")
-def master(settings):
+
+def main():
+ settings = create_parser().parse_known_args()[0]
+ e = Engine(sys.argv)
+ e.load_platform(settings.platform)
+
+ # Create the requested amount of actors pairs. Each pair has a specific mutex and cell in `result`
results = [ResultHolder(value=0) for _ in range(settings.actors)]
for i in range(settings.actors):
mutex = Mutex()
Actor.create(f"worker-{i}(mgr)", Host.by_name("Jupiter"), worker_context_manager, mutex, results[i])
Actor.create(f"worker-{i}", Host.by_name("Tremblay"), worker, mutex, results[i])
- this_actor.sleep_for(10)
- for i in range(settings.actors):
- this_actor.info(f"Result[{i}] -> {results[i].value}")
- this_actor.info("I'm done, good bye")
-
-def main():
- settings = create_parser().parse_known_args()[0]
- e = Engine(sys.argv)
- e.load_platform(settings.platform)
- Actor.create("master", Host.by_name("Tremblay"), master, settings)
e.run()
+ for i in range(settings.actors):
+ this_actor.info(f"Result[{i}] -> {results[i].value}")
+
if __name__ == "__main__":
main()
p Testing Mutex
-$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/synchro-mutex.py --platform ${platfdir}/two_hosts.xml --actors 0 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[ 10.000000] (1:master@Tremblay) I'm done, good bye
-
$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/synchro-mutex.py --platform ${platfdir}/two_hosts.xml --actors 1 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[ 0.000000] (2:worker-0(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
->[ 0.000000] (2:worker-0(mgr)@Jupiter) I'm done, good bye
->[ 0.000000] (3:worker-0@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
->[ 0.000000] (3:worker-0@Tremblay) I'm done, good bye
->[ 10.000000] (1:master@Tremblay) Result[0] -> 2
->[ 10.000000] (1:master@Tremblay) I'm done, good bye
+>[ 0.000000] (1:worker-0(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
+>[ 0.000000] (2:worker-0@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
+>[ 0.000000] (1:worker-0(mgr)@Jupiter) I'm done, good bye
+>[ 0.000000] (2:worker-0@Tremblay) I'm done, good bye
+>[ 0.000000] (0:maestro@) Result[0] -> 2
$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/synchro-mutex.py --platform ${platfdir}/two_hosts.xml --actors 5 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
->[ 0.000000] (2:worker-0(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
->[ 0.000000] (2:worker-0(mgr)@Jupiter) I'm done, good bye
->[ 0.000000] (3:worker-0@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
->[ 0.000000] (3:worker-0@Tremblay) I'm done, good bye
->[ 0.000000] (4:worker-1(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
->[ 0.000000] (4:worker-1(mgr)@Jupiter) I'm done, good bye
->[ 0.000000] (5:worker-1@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
->[ 0.000000] (5:worker-1@Tremblay) I'm done, good bye
->[ 0.000000] (6:worker-2(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
->[ 0.000000] (6:worker-2(mgr)@Jupiter) I'm done, good bye
->[ 0.000000] (7:worker-2@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
->[ 0.000000] (7:worker-2@Tremblay) I'm done, good bye
->[ 0.000000] (8:worker-3(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
->[ 0.000000] (8:worker-3(mgr)@Jupiter) I'm done, good bye
->[ 0.000000] (9:worker-3@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
->[ 0.000000] (9:worker-3@Tremblay) I'm done, good bye
->[ 0.000000] (10:worker-4(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
->[ 0.000000] (10:worker-4(mgr)@Jupiter) I'm done, good bye
->[ 0.000000] (11:worker-4@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
->[ 0.000000] (11:worker-4@Tremblay) I'm done, good bye
->[ 10.000000] (1:master@Tremblay) Result[0] -> 2
->[ 10.000000] (1:master@Tremblay) Result[1] -> 2
->[ 10.000000] (1:master@Tremblay) Result[2] -> 2
->[ 10.000000] (1:master@Tremblay) Result[3] -> 2
->[ 10.000000] (1:master@Tremblay) Result[4] -> 2
->[ 10.000000] (1:master@Tremblay) I'm done, good bye
+>[ 0.000000] (1:worker-0(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
+>[ 0.000000] (3:worker-1(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
+>[ 0.000000] (5:worker-2(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
+>[ 0.000000] (7:worker-3(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
+>[ 0.000000] (9:worker-4(mgr)@Jupiter) Hello simgrid, I'm ready to compute after acquiring the mutex from a context manager
+>[ 0.000000] (2:worker-0@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
+>[ 0.000000] (1:worker-0(mgr)@Jupiter) I'm done, good bye
+>[ 0.000000] (4:worker-1@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
+>[ 0.000000] (3:worker-1(mgr)@Jupiter) I'm done, good bye
+>[ 0.000000] (6:worker-2@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
+>[ 0.000000] (5:worker-2(mgr)@Jupiter) I'm done, good bye
+>[ 0.000000] (8:worker-3@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
+>[ 0.000000] (7:worker-3(mgr)@Jupiter) I'm done, good bye
+>[ 0.000000] (10:worker-4@Tremblay) Hello simgrid, I'm ready to compute after a regular lock
+>[ 0.000000] (9:worker-4(mgr)@Jupiter) I'm done, good bye
+>[ 0.000000] (2:worker-0@Tremblay) I'm done, good bye
+>[ 0.000000] (4:worker-1@Tremblay) I'm done, good bye
+>[ 0.000000] (6:worker-2@Tremblay) I'm done, good bye
+>[ 0.000000] (8:worker-3@Tremblay) I'm done, good bye
+>[ 0.000000] (10:worker-4@Tremblay) I'm done, good bye
+>[ 0.000000] (0:maestro@) Result[0] -> 2
+>[ 0.000000] (0:maestro@) Result[1] -> 2
+>[ 0.000000] (0:maestro@) Result[2] -> 2
+>[ 0.000000] (0:maestro@) Result[3] -> 2
+>[ 0.000000] (0:maestro@) Result[4] -> 2
* That is, activities are all the things that do take time to the actor in the simulated world.
*/
class XBT_PUBLIC Activity : public xbt::Extendable<Activity> {
+#ifndef DOXYGEN
friend Comm;
friend Exec;
friend Io;
-#ifndef DOXYGEN
+ 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);
#endif
private:
static xbt::signal<void(Activity&)> on_veto;
- static xbt::signal<void(Activity&)> on_completion;
+ static xbt::signal<void(Activity const&)> on_completion;
+ static xbt::signal<void(Activity const&)> on_suspended;
+ static xbt::signal<void(Activity const&)> on_resumed;
public:
/*! Add a callback fired each time that the activity fails to start because of a veto (e.g., unsolved dependency or no
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); }
void vetoable_start()
{
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();
+ /** Returns some debug information about the barrier */
+ std::string to_string() const;
#ifndef DOXYGEN
/* refcounting */
static xbt::signal<void(Comm const&)> on_send;
static xbt::signal<void(Comm const&)> on_recv;
static xbt::signal<void(Comm const&)> on_start;
- static xbt::signal<void(Comm const&)> on_completion;
#endif
static void on_send_cb(const std::function<void(Comm const&)>& cb) { on_send.connect(cb); }
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); }
- static void on_completion_cb(const std::function<void(Activity const&)>& cb) { on_completion.connect(cb); }
/* More callbacks */
CommPtr set_copy_data_callback(const std::function<void(kernel::activity::CommImpl*, void*, size_t)>& callback);
static void copy_buffer_callback(kernel::activity::CommImpl*, void*, size_t);
/*! 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);
-
-#ifndef DOXYGEN
- XBT_ATTRIB_DEPRECATED_v332("Please use a plain vector for parameter") static int wait_any(
- const std::vector<CommPtr>* comms)
- {
- return static_cast<int>(wait_any_for(*comms, -1));
- }
- XBT_ATTRIB_DEPRECATED_v332("Please use a plain vector for first parameter") static int wait_any_for(
- const std::vector<CommPtr>* comms, double timeout)
- {
- return static_cast<int>(wait_any_for(*comms, timeout));
- }
- XBT_ATTRIB_DEPRECATED_v332("Please use a plain vector for parameter") static void wait_all(
- const std::vector<CommPtr>* comms)
- {
- wait_all(*comms);
- }
- XBT_ATTRIB_DEPRECATED_v332("Please use a plain vector for parameter") static int test_any(
- const std::vector<CommPtr>* comms)
- {
- return static_cast<int>(test_any(*comms));
- }
-#endif
};
} // namespace s4u
} // namespace simgrid
/*! 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);
-#ifndef DOXYGEN
- XBT_ATTRIB_DEPRECATED_v332("Please use a plain vector for parameter")
- static int wait_any(std::vector<ExecPtr>* execs) { return static_cast<int>(wait_any_for(*execs, -1)); }
- XBT_ATTRIB_DEPRECATED_v332("Please use a plain vector for first parameter")
- static int wait_any_for(std::vector<ExecPtr>* execs, double timeout) { return static_cast<int>(wait_any_for(*execs, timeout)); }
-#endif
-
/** @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;
/** @brief Get the netpoint associated to this netzone */
kernel::routing::NetPoint* get_netpoint();
-#ifndef DOXYGEN
- XBT_ATTRIB_DEPRECATED_v332("Please use set_parent() to manage NetZone's relationship") NetZone* add_child(
- NetZone* new_zone);
-#endif
-
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);
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);
-#ifndef DOXYGEN
- XBT_ATTRIB_DEPRECATED_v332(
- "Please use add_route() method which uses s4u::LinkInRoute instead of "
- "LinkImpl") void add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
- kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
- const std::vector<kernel::resource::StandardLinkImpl*>& link_list, bool symmetrical);
-
- XBT_ATTRIB_DEPRECATED_v332(
- "Please use add_bypass_route() method which uses s4u::LinkInRoute instead of "
- "LinkImpl") void add_bypass_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
- kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
- const std::vector<kernel::resource::StandardLinkImpl*>& link_list,
- bool /*symmetrical*/);
-#endif
-
void 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);
-#ifndef DOXYGEN
- /*** Called on each newly created regular route (not on bypass routes) */
- static xbt::signal<void(bool symmetrical, kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
- kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
- std::vector<kernel::resource::StandardLinkImpl*> const& link_list)>
- on_route_creation; // XBT_ATTRIB_DEPRECATED_v332 : should not be used by users, used by ns3.. if necessary,
- // signal shouldn't use LinkImpl*
-
private:
+#ifndef DOXYGEN
static xbt::signal<void(NetZone const&)> on_creation;
static xbt::signal<void(NetZone const&)> on_seal;
#endif
/** @brief Seal this netzone configuration */
NetZone* seal();
-
-private:
-#ifndef DOXYGEN
- /** @brief XBT_ATTRIB_DEPRECATED_v332 Auxiliary function to convert types */
- static std::vector<LinkInRoute>
- convert_to_linkInRoute(const std::vector<kernel::resource::StandardLinkImpl*>& link_list);
-#endif
};
// External constructors so that the types (and the types of their content) remain hidden
class XBT_PUBLIC Semaphore {
#ifndef DOXYGEN
friend kernel::activity::SemaphoreImpl;
- friend void kernel::activity::intrusive_ptr_release(kernel::activity::SemaphoreImpl* sem);
+ friend XBT_PUBLIC void kernel::activity::intrusive_ptr_release(kernel::activity::SemaphoreImpl* sem);
#endif
kernel::activity::SemaphoreImpl* const pimpl_;
- friend void intrusive_ptr_add_ref(const Semaphore* sem);
- friend void intrusive_ptr_release(const Semaphore* sem);
+ friend XBT_PUBLIC void intrusive_ptr_add_ref(const Semaphore* sem);
+ friend XBT_PUBLIC void intrusive_ptr_release(const Semaphore* sem);
explicit Semaphore(kernel::activity::SemaphoreImpl* sem) : pimpl_(sem) {}
~Semaphore() = default;
SUSPENDED, /**< Suspend/resume does not involve disk I/O, so we assume there is no transition states. */
DESTROYED
);
-#ifndef DOXYGEN
- using state XBT_ATTRIB_DEPRECATED_v332("Please use VirtualMachine::State") = State;
-#endif
kernel::resource::VirtualMachineImpl* get_vm_impl() const { return pimpl_vm_; }
void start();
XBT_ATTRIB_DEPRECATED_v333("Please use simgrid_set_maestro()") XBT_PUBLIC
void SIMIX_set_maestro(void (*code)(void*), void* data);
-/* Simulation execution */
-XBT_ATTRIB_DEPRECATED_v332("Please use EngineImpl:run()") XBT_PUBLIC void SIMIX_run();
-XBT_ATTRIB_DEPRECATED_v332("Please use simgrid_get_clock() or Engine::get_clock()") XBT_PUBLIC double SIMIX_get_clock();
-
SG_END_DECL
/********************************* Process ************************************/
#define XBT_ATTRIB_DEPRECATED(mesg) __attribute__((deprecated(mesg)))
#endif
-#define XBT_ATTRIB_DEPRECATED_v332(mesg) \
- XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.31)")
#define XBT_ATTRIB_DEPRECATED_v333(mesg) \
XBT_ATTRIB_DEPRECATED(mesg " (this compatibility wrapper will be dropped after v3.32)")
#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)")
/* Work around https://github.com/microsoft/vscode-cpptools/issues/4503 */
#ifdef __INTELLISENSE__
setup(
name='simgrid',
- version='3.30.1',
+ version='3.31.1',
author='Da SimGrid Team',
author_email='simgrid-community@inria.fr',
description='Toolkit for scalable simulation of distributed applications',
sonar.organization=simgrid
sonar.projectKey=simgrid_simgrid
sonar.projectName=SimGrid
-sonar.projectVersion=3.30.1
+sonar.projectVersion=3.31.1
sonar.links.homepage=https://simgrid.org
sonar.links.issue=https://framagit.org/simgrid/simgrid/issues
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.")
- // use py::overload_cast for wait_all/wait_any, until the overload marked XBT_ATTRIB_DEPRECATED_v332 is removed
.def_static(
- "wait_all", py::overload_cast<const std::vector<simgrid::s4u::CommPtr>&>(&simgrid::s4u::Comm::wait_all),
+ "wait_all", &simgrid::s4u::Comm::wait_all,
py::arg("comms"),
py::call_guard<py::gil_scoped_release>(),
"Block until the completion of all communications in the list.")
"Block until the completion of all communications in the list, or raises TimeoutException after "
"the specified timeout.")
.def_static(
- "wait_any", py::overload_cast<const std::vector<simgrid::s4u::CommPtr>&>(&simgrid::s4u::Comm::wait_any),
+ "wait_any", &simgrid::s4u::Comm::wait_any,
py::arg("comms"),
py::call_guard<py::gil_scoped_release>(),
"Block until the completion of any communication in the list and return the index of the terminated one.")
.def_static(
"wait_any_for",
- py::overload_cast<const std::vector<simgrid::s4u::CommPtr>&, double>(&simgrid::s4u::Comm::wait_any_for),
+ &simgrid::s4u::Comm::wait_any_for,
py::arg("comms"), py::arg("timeout"),
py::call_guard<py::gil_scoped_release>(),
"Block until the completion of any communication in the list and return the index of the terminated "
#include <simgrid/s4u/Host.hpp>
#include <simgrid/sg_config.hpp>
-#define SIMIX_H_NO_DEPRECATED_WARNING // avoid deprecation warning on include (remove with XBT_ATTRIB_DEPRECATED_v332)
-#include <simgrid/simix.h>
-
#include "mc/mc.h"
#include "src/kernel/EngineImpl.hpp"
#include "src/kernel/resource/StandardLinkImpl.hpp"
#include "src/mc/remote/AppSide.hpp"
#endif
-double NOW = 0;
-
XBT_LOG_NEW_DEFAULT_CATEGORY(ker_engine, "Logging specific to Engine (kernel)");
namespace simgrid {
namespace kernel {
+double EngineImpl::now_ = 0.0;
EngineImpl* EngineImpl::instance_ = nullptr; /* That singleton is awful too. */
config::Flag<double> cfg_breakpoint{"debug/breakpoint",
void EngineImpl::load_platform(const std::string& platf)
{
double start = xbt_os_time();
- if (boost::algorithm::ends_with(platf, ".so") or boost::algorithm::ends_with(platf, ".dylib")) {
+ if (boost::algorithm::ends_with(platf, ".so") || boost::algorithm::ends_with(platf, ".dylib")) {
#ifdef _WIN32
xbt_die("loading platform through shared library isn't supported on windows");
#else
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)
+ if (next_event_date > now_)
break;
double value = -1.0;
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);
+ model->update_actions_state(now_, 0.0);
}
double EngineImpl::solve(double max_date) const
resource::Resource* resource = nullptr;
if (max_date != -1.0) {
- xbt_assert(max_date >= NOW, "You asked to simulate up to %f, but that's in the past already", max_date);
+ xbt_assert(max_date >= now_, "You asked to simulate up to %f, but that's in the past already", max_date);
- time_delta = max_date - NOW;
+ time_delta = max_date - now_;
}
XBT_DEBUG("Looking for next event in all models");
if (not model->next_occurring_event_is_idempotent()) {
continue;
}
- double next_event = model->next_occurring_event(NOW);
+ 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;
}
continue;
if (next_event_date != -1.0) {
- time_delta = std::min(next_event_date - NOW, time_delta);
+ time_delta = std::min(next_event_date - now_, time_delta);
} else {
- time_delta = std::max(next_event_date - NOW, time_delta); // Get the positive component
+ time_delta = std::max(next_event_date - now_, time_delta); // Get the positive component
}
XBT_DEBUG("Run the NS3 network at most %fs", time_delta);
time_delta = model_next_action_end;
}
- if (next_event_date < 0.0 || (next_event_date > NOW + time_delta)) {
+ if (next_event_date < 0.0 || (next_event_date > now_ + time_delta)) {
// next event may have already occurred or will after the next resource change, then bail out
XBT_DEBUG("no next usable TRACE event. Stop searching for it");
break;
}
- XBT_DEBUG("Updating models (min = %g, NOW = %g, next_event_date = %g)", time_delta, NOW, next_event_date);
+ XBT_DEBUG("Updating models (min = %g, NOW = %g, next_event_date = %g)", time_delta, now_, next_event_date);
while (auto* event = profile::future_evt_set.pop_leq(next_event_date, &value, &resource)) {
if (resource->is_used() || (watched_hosts().find(resource->get_cname()) != watched_hosts().end())) {
- time_delta = next_event_date - NOW;
+ time_delta = next_event_date - now_;
XBT_DEBUG("This event invalidates the next_occurring_event() computation of models. Next event set to %f",
time_delta);
}
- // FIXME: I'm too lame to update NOW live, so I change it and restore it so that the real update with surf_min
+ // FIXME: I'm too lame to update now_ live, so I change it and restore it so that the real update with surf_min
// will work
- double round_start = NOW;
- NOW = next_event_date;
+ double round_start = now_;
+ now_ = next_event_date;
/* update state of the corresponding resource to the new value. Does not touch lmm.
It will be modified if needed when updating actions */
XBT_DEBUG("Calling update_resource_state for resource %s", resource->get_cname());
resource->apply_event(event, value);
- NOW = round_start;
+ now_ = round_start;
}
}
XBT_DEBUG("Duration set to %f", time_delta);
// Bump the time: jump into the future
- NOW = NOW + time_delta;
+ now_ += time_delta;
// Inform the models of the date change
for (auto const& model : models_)
- model->update_actions_state(NOW, time_delta);
+ model->update_actions_state(now_, time_delta);
s4u::Engine::on_time_advance(time_delta);
next_time = std::min(next_time, max_date);
}
- XBT_DEBUG("Calling solve(%g) %g", next_time, NOW);
+ XBT_DEBUG("Calling solve(%g) %g", next_time, now_);
elapsed_time = solve(next_time);
- XBT_DEBUG("Moving time ahead. NOW=%g; elapsed: %g", NOW, elapsed_time);
+ XBT_DEBUG("Moving time ahead. NOW=%g; elapsed: %g", now_, elapsed_time);
// Execute timers until there isn't anything to be done:
bool again = false;
XBT_CRITICAL("Oops! Daemon actors cannot do any blocking activity (communications, synchronization, etc) "
"once the simulation is over. Please fix your on_exit() functions.");
} else {
- XBT_CRITICAL("Oops! Deadlock or code not perfectly clean.");
+ XBT_CRITICAL("Oops! Deadlock detected, some activities are still around but will never complete. "
+ "This usually happens when the user code is not perfectly clean.");
}
display_all_actor_status();
simgrid::s4u::Engine::on_deadlock();
}
}
} while ((vetoed_activities == nullptr || vetoed_activities->empty()) &&
- ((elapsed_time > -1.0 && not double_equals(max_date, NOW, 0.00001)) || has_actors_to_run()));
+ ((elapsed_time > -1.0 && not double_equals(max_date, now_, 0.00001)) || has_actors_to_run()));
if (not actor_list_.empty() && max_date < 0 && not(vetoed_activities == nullptr || vetoed_activities->empty()))
THROW_IMPOSSIBLE;
double EngineImpl::get_clock()
{
- return NOW;
+ return now_;
}
} // namespace kernel
} // namespace simgrid
-
-void SIMIX_run() // XBT_ATTRIB_DEPRECATED_v332
-{
- simgrid::kernel::EngineImpl::get_instance()->run(-1);
-}
xbt_dynar_t actors_vector_ = xbt_dynar_new(sizeof(actor::ActorImpl*), nullptr);
#endif
+ static double now_;
static EngineImpl* instance_;
actor::ActorImpl* maestro_ = nullptr;
context::ContextFactory* context_factory_ = nullptr;
* under the terms of the license (GNU LGPL) which comes with this package. */
#include <simgrid/modelchecker.h>
+#include <simgrid/s4u/Activity.hpp>
#include <simgrid/s4u/Engine.hpp>
#include "src/kernel/activity/ActivityImpl.hpp"
return;
XBT_VERB("This activity is suspended (remain: %f)", surf_action_->get_remains());
surf_action_->suspend();
- on_suspended(*this);
+ s4u::Activity::on_suspended(*get_iface());
}
void ActivityImpl::resume()
return;
XBT_VERB("This activity is resumed (remain: %f)", surf_action_->get_remains());
surf_action_->resume();
- on_resumed(*this);
+ s4u::Activity::on_resumed(*get_iface());
}
void ActivityImpl::cancel()
delete activity;
}
}
-xbt::signal<void(ActivityImpl const&)> ActivityImpl::on_resumed;
-xbt::signal<void(ActivityImpl const&)> ActivityImpl::on_suspended;
}
}
} // namespace simgrid::kernel::activity::
friend XBT_PUBLIC void intrusive_ptr_add_ref(ActivityImpl* activity);
friend XBT_PUBLIC void intrusive_ptr_release(ActivityImpl* activity);
int get_refcount() const { return static_cast<int>(refcount_); } // For debugging purpose
-
- static xbt::signal<void(ActivityImpl const&)> on_suspended;
- static xbt::signal<void(ActivityImpl const&)> on_resumed;
};
/* This class exists to allow chained setters as in exec->set_name()->set_priority()->set_blah()
}
s4u::Barrier& get_iface() { return piface_; }
+
+ std::string to_string() const
+ {
+ return xbt::string_printf("Barrier %u: %zu of %u", id_, ongoing_acquisitions_.size(), expected_actors_);
+ }
};
} // namespace activity
} // namespace kernel
namespace actor {
/*------------------------- [ ActorIDTrait ] -------------------------*/
-static unsigned long maxpid = 0;
-unsigned long get_maxpid()
-{
- return maxpid;
-}
-unsigned long* get_maxpid_addr()
-{
- return &maxpid;
-}
-ActorIDTrait::ActorIDTrait(const std::string& name, aid_t ppid) : name_(name), pid_(maxpid++), ppid_(ppid) {}
+unsigned long ActorIDTrait::maxpid_ = 0;
+
+ActorIDTrait::ActorIDTrait(const std::string& name, aid_t ppid) : name_(name), pid_(maxpid_++), ppid_(ppid) {}
ActorImpl* ActorImpl::self()
{
aid_t pid_ = 0;
aid_t ppid_ = -1;
+ static unsigned long maxpid_;
+
public:
explicit ActorIDTrait(const std::string& name, aid_t ppid);
const xbt::string& get_name() const { return name_; }
const char* get_cname() const { return name_.c_str(); }
aid_t get_pid() const { return pid_; }
aid_t get_ppid() const { return ppid_; }
+
+ static unsigned long get_maxpid() { return maxpid_; }
+ // In MC mode, the application sends this pointer to the MC
+ static unsigned long* get_maxpid_addr() { return &maxpid_; }
};
-XBT_PUBLIC unsigned long get_maxpid();
-XBT_PUBLIC unsigned long* get_maxpid_addr(); // In MC mode, the application sends this pointers to the MC
/*------------------------- [ ActorRestartingTrait ] -------------------------*/
class XBT_PUBLIC ActorRestartingTrait {
std::unordered_map<s4u::Disk::Operation, s4u::NonLinearResourceCb> sharing_policy_cb_ = {};
std::function<s4u::Disk::IoFactorCb> factor_cb_ = {};
+ 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) */
+
void apply_sharing_policy_cfg();
protected:
~DiskImpl() override = default; // Disallow direct deletion. Call destroy() instead.
public:
- 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) */
-
explicit DiskImpl(const std::string& name, double read_bandwidth, double write_bandwidth);
DiskImpl(const DiskImpl&) = delete;
DiskImpl& operator=(const DiskImpl&) = delete;
DiskImpl* set_host(s4u::Host* host);
s4u::Host* get_host() const { return host_; }
- virtual void set_read_bandwidth(double read_bw) = 0;
+ virtual void set_read_bandwidth(double value) { read_bw_.peak = value; }
double get_read_bandwidth() const { return read_bw_.peak * read_bw_.scale; }
- virtual void set_write_bandwidth(double write_bw) = 0;
+ virtual void set_write_bandwidth(double value) { write_bw_.peak = value; }
double get_write_bandwidth() const { return write_bw_.peak * write_bw_.scale; }
- virtual void set_readwrite_bandwidth(double bw) = 0;
+ virtual void set_readwrite_bandwidth(double value) { readwrite_bw_ = value; }
+ double get_readwrite_bandwidth() const { return readwrite_bw_; }
DiskImpl* set_read_constraint(lmm::Constraint* constraint_read);
lmm::Constraint* get_read_constraint() const { return constraint_read_; }
DiskImpl* set_write_constraint(lmm::Constraint* constraint_write);
lmm::Constraint* get_write_constraint() const { return constraint_write_; }
+ profile::Event* get_read_event() const { return read_bw_.event; }
+ void unref_read_event() { tmgr_trace_event_unref(&read_bw_.event); }
+
+ profile::Event* get_write_event() const { return write_bw_.event; }
+ void unref_write_event() { tmgr_trace_event_unref(&write_bw_.event); }
+
DiskImpl* set_read_bandwidth_profile(profile::Profile* profile);
DiskImpl* set_write_bandwidth_profile(profile::Profile* profile);
}
}
-static s4u::VirtualMachine* get_vm_from_activity(kernel::activity::ActivityImpl const& act)
+static s4u::VirtualMachine* get_vm_from_activity(s4u::Activity const& act)
{
- auto* exec = dynamic_cast<kernel::activity::ExecImpl const*>(&act);
+ auto* exec = dynamic_cast<kernel::activity::ExecImpl const*>(act.get_impl());
return exec != nullptr ? dynamic_cast<s4u::VirtualMachine*>(exec->get_host()) : nullptr;
}
-static void add_active_activity(kernel::activity::ActivityImpl const& act)
+static void add_active_activity(s4u::Activity const& act)
{
const s4u::VirtualMachine* vm = get_vm_from_activity(act);
if (vm != nullptr) {
}
}
-static void remove_active_activity(kernel::activity::ActivityImpl const& act)
+static void remove_active_activity(s4u::Activity const& act)
{
const s4u::VirtualMachine* vm = get_vm_from_activity(act);
if (vm != nullptr) {
s4u::Host::on_state_change_cb(host_state_change);
s4u::Exec::on_start_cb(add_active_exec);
s4u::Activity::on_completion_cb(remove_active_exec);
- activity::ActivityImpl::on_resumed.connect(add_active_activity);
- activity::ActivityImpl::on_suspended.connect(remove_active_activity);
+ s4u::Activity::on_resumed_cb(add_active_activity);
+ s4u::Activity::on_suspended_cb(remove_active_activity);
}
double VMModel::next_occurring_event(double now)
fes_ = fes;
- if(event_list.empty())
- cb(event_list);
-
- if(event_list.empty()) {
+ if (get_enough_events(0)) {
+ fes_->add_event(event_list[0].date_, event);
+ } else {
event->free_me = true;
tmgr_trace_event_unref(&event);
- } else {
- fes_->add_event(event_list[0].date_, event);
}
return event;
}
event->idx++;
- if (event->idx == event_list.size())
- cb(event_list);
- if(event->idx>=event_list.size())
- event->free_me = true;
- else {
- const DatedValue& nextDateVal = event_list.at(event->idx);
+ if (get_enough_events(event->idx)) {
+ const DatedValue& nextDateVal = event_list[event->idx];
xbt_assert(nextDateVal.date_>=0);
xbt_assert(nextDateVal.value_>=0);
fes_->add_event(event_date +nextDateVal.date_, event);
+ } else {
+ event->free_me = true;
}
return dateVal;
}
{
xbt_assert(trace_list.find(name) == trace_list.end(), "Refusing to define trace %s twice", name.c_str());
trace_list.insert({name,this});
- cb(event_list);
+ get_enough_events(0);
}
} // namespace profile
std::vector<DatedValue> event_list;
FutureEvtSet* fes_ = nullptr;
double repeat_delay;
+
+ bool get_enough_events(size_t index)
+ {
+ if (index >= event_list.size() && cb)
+ cb(event_list);
+ return index < event_list.size();
+ }
};
} // namespace profile
}
xbt_assert(splittedval.size() > i, "Invalid profile line");
- if (i == 1 or i == 2) {
+ if (i == 1 || i == 2) {
stochevent.date_params = {std::stod(splittedval[i - 1])};
} else if (i == 3) {
stochevent.date_params = {std::stod(splittedval[1]), std::stod(splittedval[2])};
}
xbt_assert(splittedval.size() > i + j, "Invalid profile line");
- if (j == 0 or j == 1) {
+ if (j == 0 || j == 1) {
stochevent.value_params = {std::stod(splittedval[i + j])};
} else if (j == 2) {
stochevent.value_params = {std::stod(splittedval[i + 1]), std::stod(splittedval[i + 2])};
pattern.emplace_back(stochevent);
}
- xbt_assert(not stochastic or periodicity <= 0, "If you want periodicity with stochastic profiles, use LOOP_AFTER");
+ xbt_assert(not stochastic || periodicity <= 0, "If you want periodicity with stochastic profiles, use LOOP_AFTER");
if (periodicity > 0) {
- xbt_assert(loop and loop_delay == 0);
+ xbt_assert(loop && loop_delay == 0);
loop_delay = periodicity - last_date;
}
double get_repeat_delay() const
{
- if (not stochastic and loop)
+ if (not stochastic && loop)
return loop_delay;
return -1.0;
}
void operator()(std::vector<DatedValue>& event_list) const
{
size_t initial_size = event_list.size();
- if (loop or not initial_size) {
+ if (loop || not initial_size) {
for (auto const& dv : pattern)
event_list.emplace_back(dv.get_datedvalue());
if (initial_size)
Profile* ProfileBuilder::from_void() {
- static Profile void_profile("__void__",[](std::vector<DatedValue>&){},-1.0);
+ static Profile void_profile("__void__", nullptr, -1.0);
return &void_profile;
}
xbt_assert(not dst->is_netzone(),
"When defining a route, dst cannot be a netzone such as '%s'. Did you meant to have a NetzoneRoute?",
dstName);
- s4u::NetZone::on_route_creation(symmetrical, src, dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
NetZoneImpl::on_route_creation(symmetrical, src, dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
} else {
XBT_DEBUG("Load NetzoneRoute from %s@%s to %s@%s", srcName, gw_src->get_cname(), dstName, gw_dst->get_cname());
"Invalid NetzoneRoute from %s@%s to %s@%s: gw_dst %s belongs to %s, not to %s.", srcName,
gw_src->get_cname(), dstName, gw_dst->get_cname(), gw_dst->get_cname(),
gw_dst->get_englobing_zone()->get_cname(), dst->get_cname());
- s4u::NetZone::on_route_creation(symmetrical, gw_src, gw_dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
NetZoneImpl::on_route_creation(symmetrical, gw_src, gw_dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
}
}
std::unique_ptr<RemoteProcess> remote_process_;
Exploration* exploration_ = nullptr;
+ unsigned long visited_states_ = 0;
+
// Expect MessageType::SIMCALL_TO_STRING or MessageType::SIMCALL_DOT_LABEL
std::string simcall_to_string(MessageType type, aid_t aid, int times_considered);
Exploration* get_exploration() const { return exploration_; }
void set_exploration(Exploration* exploration) { exploration_ = exploration; }
+ unsigned long get_visited_states() const { return visited_states_; }
+ void inc_visited_states() { visited_states_++; }
+
private:
void setup_ignore();
bool handle_message(const char* buffer, ssize_t size);
void handle_waitpid();
-
-public:
- unsigned long visited_states = 0;
};
}
VisitedStates::addVisitedState(unsigned long state_number, simgrid::mc::State* graph_state, bool compare_snapshots)
{
auto new_state = std::make_unique<simgrid::mc::VisitedState>(state_number);
- graph_state->system_state_ = new_state->system_state;
+ 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->num_);
+ new_state->num, graph_state->get_num());
auto range = boost::range::equal_range(states_, new_state.get(), Api::get().compare_pair());
void Api::mc_inc_visited_states() const
{
- mc_model_checker->visited_states++;
+ mc_model_checker->inc_visited_states();
}
unsigned long Api::mc_get_visited_states() const
{
- return mc_model_checker->visited_states;
+ return mc_model_checker->get_visited_states();
}
void Api::mc_exit(int status) const
mc_model_checker->exit(status);
}
-void Api::restore_state(std::shared_ptr<simgrid::mc::Snapshot> system_state) const
+void Api::restore_state(simgrid::mc::Snapshot* system_state) const
{
system_state->restore(&mc_model_checker->get_remote_process());
}
XBT_ATTRIB_NORETURN void mc_exit(int status) const;
// STATE APIs
- void restore_state(std::shared_ptr<simgrid::mc::Snapshot> system_state) const;
+ void restore_state(Snapshot* system_state) const;
// SNAPSHOT APIs
bool snapshot_equal(const Snapshot* s1, const Snapshot* s2) const;
/* Outgoing transition: what was the last transition that we took to leave this state? */
std::unique_ptr<Transition> transition_;
-public:
- explicit State();
-
/** Sequential state number (used for debugging) */
long num_ = 0;
std::vector<ActorState> actor_states_;
/** Snapshot of system state (if needed) */
- std::shared_ptr<simgrid::mc::Snapshot> system_state_;
+ std::shared_ptr<Snapshot> system_state_;
+
+public:
+ explicit State();
/* Returns a positive number if there is another transition to pick, or -1 if not */
int next_transition() const;
/* Explore a new path; the parameter must be the result of a previous call to next_transition() */
void execute_next(int next);
+ long get_num() const { return num_; }
std::size_t count_todo() const;
void mark_todo(aid_t actor) { this->actor_states_[actor].mark_todo(); }
+ bool is_done(aid_t actor) const { return this->actor_states_[actor].is_done(); }
Transition* get_transition() const;
void set_transition(Transition* t) { transition_.reset(t); }
+ Snapshot* get_system_state() const { return system_state_.get(); }
+ void set_system_state(std::shared_ptr<Snapshot> state) { system_state_ = std::move(state); }
+
/* Returns the total amount of states created so far (for statistics) */
static long get_expanded_states() { return expended_states_; }
};
/********** State Extension ***********/
class StateCommDet {
- CommDetExtension* checker_;
-
public:
std::vector<std::vector<simgrid::mc::PatternCommunication>> incomplete_comm_pattern_;
std::vector<unsigned> communication_indices_;
static simgrid::xbt::Extension<simgrid::mc::State, StateCommDet> EXTENSION_ID;
- explicit StateCommDet(CommDetExtension* checker) : checker_(checker)
+ explicit StateCommDet(CommDetExtension* checker)
{
const unsigned long maxpid = Api::get().get_maxpid();
for (unsigned long i = 0; i < maxpid; i++) {
std::vector<simgrid::mc::PatternCommunication> res;
- for (auto const& comm : checker_->incomplete_communications_pattern[i])
+ for (auto const& comm : checker->incomplete_communications_pattern[i])
res.push_back(comm->dup());
incomplete_comm_pattern_.push_back(std::move(res));
}
- for (auto const& list_process_comm : checker_->initial_communications_pattern)
+ for (auto const& list_process_comm : checker->initial_communications_pattern)
this->communication_indices_.push_back(list_process_comm.index_comm);
}
};
void DFSExplorer::check_non_termination(const State* current_state)
{
for (auto state = stack_.rbegin(); state != stack_.rend(); ++state)
- if (Api::get().snapshot_equal((*state)->system_state_.get(), current_state->system_state_.get())) {
- XBT_INFO("Non-progressive cycle: state %ld -> state %ld", (*state)->num_, current_state->num_);
+ if (Api::get().snapshot_equal((*state)->get_system_state(), current_state->get_system_state())) {
+ XBT_INFO("Non-progressive cycle: state %ld -> state %ld", (*state)->get_num(), current_state->get_num());
XBT_INFO("******************************************");
XBT_INFO("*** NON-PROGRESSIVE CYCLE DETECTED ***");
XBT_INFO("******************************************");
std::vector<std::string> DFSExplorer::get_textual_trace() // override
{
std::vector<std::string> trace;
- for (auto const& state : stack_)
- trace.push_back(state->get_transition()->to_string());
+ 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()));
+ }
return trace;
}
State* state = stack_.back().get();
XBT_DEBUG("**************************************************");
- XBT_DEBUG("Exploration depth=%zu (state:%ld; %zu interleaves)", stack_.size(), state->num_, state->count_todo());
+ XBT_DEBUG("Exploration depth=%zu (state:%ld; %zu interleaves)", stack_.size(), state->get_num(),
+ state->count_todo());
Api::get().mc_inc_visited_states();
XBT_DEBUG("There remains %zu actors, but none to interleave (depth %zu).",
mc_model_checker->get_remote_process().actors().size(), stack_.size() + 1);
- if (mc_model_checker->get_remote_process().actors().empty())
+ if (mc_model_checker->get_remote_process().actors().empty()) {
mc_model_checker->finalize_app();
+ XBT_VERB("Execution came to an end at %s (state: %ld, depth: %zu)", get_record_trace().to_string().c_str(),
+ state->get_num(), stack_.size());
+ }
this->backtrack();
continue;
}
// 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->num_, state->count_todo());
+ state->get_transition()->to_string().c_str(), stack_.size(), state->get_num(), state->count_todo());
std::string req_str;
if (dot_output != nullptr)
/* 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->num_, next_state.get(), true);
+ visited_state_ = visited_states_.addVisitedState(next_state->get_num(), next_state.get(), true);
/* If this is a new state (or if we don't care about state-equality reduction) */
if (visited_state_ == nullptr) {
}
if (dot_output != nullptr)
- std::fprintf(dot_output, "\"%ld\" -> \"%ld\" [%s];\n", state->num_, next_state->num_, req_str.c_str());
+ std::fprintf(dot_output, "\"%ld\" -> \"%ld\" [%s];\n", state->get_num(), next_state->get_num(),
+ req_str.c_str());
} else if (dot_output != nullptr)
- std::fprintf(dot_output, "\"%ld\" -> \"%ld\" [%s];\n", state->num_,
+ std::fprintf(dot_output, "\"%ld\" -> \"%ld\" [%s];\n", state->get_num(),
visited_state_->original_num == -1 ? visited_state_->num : visited_state_->original_num,
req_str.c_str());
break;
} else if (prev_state->get_transition()->depends(state->get_transition())) {
XBT_VERB("Dependent Transitions:");
- XBT_VERB(" %s (state=%ld)", prev_state->get_transition()->to_string().c_str(), prev_state->num_);
- XBT_VERB(" %s (state=%ld)", state->get_transition()->to_string().c_str(), state->num_);
+ 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());
- if (not prev_state->actor_states_[issuer_id].is_done())
+ if (not prev_state->is_done(issuer_id))
prev_state->mark_todo(issuer_id);
else
XBT_DEBUG("Actor %ld is in done set", issuer_id);
break;
} else {
XBT_VERB("INDEPENDENT Transitions:");
- XBT_VERB(" %s (state=%ld)", prev_state->get_transition()->to_string().c_str(), prev_state->num_);
- XBT_VERB(" %s (state=%ld)", state->get_transition()->to_string().c_str(), state->num_);
+ 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());
}
}
}
if (state->count_todo() && stack_.size() < (std::size_t)_sg_mc_max_depth) {
/* We found a back-tracking point, let's loop */
- XBT_DEBUG("Back-tracking to state %ld at depth %zu", state->num_, stack_.size() + 1);
+ XBT_DEBUG("Back-tracking to state %ld at depth %zu", state->get_num(), stack_.size() + 1);
stack_.push_back(
std::move(state)); // Put it back on the stack from which it was removed earlier in this while loop
this->restore_state();
- XBT_DEBUG("Back-tracking to state %ld at depth %zu done", stack_.back()->num_, stack_.size());
+ XBT_DEBUG("Back-tracking to state %ld at depth %zu done", stack_.back()->get_num(), stack_.size());
break;
} else {
- XBT_DEBUG("Delete state %ld at depth %zu", state->num_, stack_.size() + 1);
+ XBT_DEBUG("Delete state %ld at depth %zu", state->get_num(), stack_.size() + 1);
}
}
}
{
/* If asked to rollback on a state that has a snapshot, restore it */
State* last_state = stack_.back().get();
- if (last_state->system_state_) {
- Api::get().restore_state(last_state->system_state_);
+ if (auto* system_state = last_state->get_system_state()) {
+ Api::get().restore_state(system_state);
on_restore_system_state_signal(last_state);
return;
}
: num(pair_num), automaton_state(automaton_state)
{
this->graph_state = std::move(graph_state);
- if (this->graph_state->system_state_ == nullptr)
- this->graph_state->system_state_ = std::make_shared<Snapshot>(pair_num);
+ if (not this->graph_state->get_system_state())
+ this->graph_state->set_system_state(std::make_shared<Snapshot>(pair_num));
this->heap_bytes_used = Api::get().get_remote_heap_bytes();
this->actors_count = Api::get().get_actors().size();
this->other_num = -1;
std::shared_ptr<simgrid::mc::VisitedPair> const& pair_test = *i;
if (xbt_automaton_state_compare(pair_test->automaton_state, new_pair->automaton_state) != 0 ||
*(pair_test->atomic_propositions) != *(new_pair->atomic_propositions) ||
- not Api::get().snapshot_equal(pair_test->graph_state->system_state_.get(),
- new_pair->graph_state->system_state_.get()))
+ not Api::get().snapshot_equal(pair_test->graph_state->get_system_state(),
+ new_pair->graph_state->get_system_state()))
continue;
XBT_INFO("Pair %d already reached (equal to pair %d) !", new_pair->num, pair_test->num);
exploration_stack_.pop_back();
/* Intermediate backtracking */
if (_sg_mc_checkpoint > 0) {
const Pair* pair = exploration_stack_.back().get();
- if (pair->graph_state->system_state_) {
- Api::get().restore_state(pair->graph_state->system_state_);
+ if (auto* system_state = pair->graph_state->get_system_state()) {
+ Api::get().restore_state(system_state);
return;
}
}
const VisitedPair* pair_test = i->get();
if (xbt_automaton_state_compare(pair_test->automaton_state, visited_pair->automaton_state) != 0 ||
*(pair_test->atomic_propositions) != *(visited_pair->atomic_propositions) ||
- not Api::get().snapshot_equal(pair_test->graph_state->system_state_.get(),
- visited_pair->graph_state->system_state_.get()))
+ not Api::get().snapshot_equal(pair_test->graph_state->get_system_state(),
+ visited_pair->graph_state->get_system_state()))
continue;
if (pair_test->other_num == -1)
visited_pair->other_num = pair_test->num;
{
if (simgrid::mc::processes_time.empty())
return 0;
- if (process != nullptr)
- return simgrid::mc::processes_time[process->get_pid()];
- return -1;
+ if (process == nullptr)
+ return -1;
+ return simgrid::mc::processes_time.at(process->get_pid());
}
void MC_process_clock_add(const simgrid::kernel::actor::ActorImpl* process, double amount)
{
- simgrid::mc::processes_time[process->get_pid()] += amount;
+ simgrid::mc::processes_time.at(process->get_pid()) += amount;
}
void simgrid::mc::RecordTrace::replay(const std::string& path_string)
{
- simgrid::mc::processes_time.resize(simgrid::kernel::actor::get_maxpid());
+ simgrid::mc::processes_time.resize(kernel::actor::ActorImpl::get_maxpid());
simgrid::mc::RecordTrace trace(path_string.c_str());
trace.replay();
for (auto* item : trace.transitions_)
strerror(errno));
s_mc_message_initial_addresses_t message{MessageType::INITIAL_ADDRESSES, mmalloc_preinit(),
- kernel::actor::get_maxpid_addr(), actors_addr};
+ kernel::actor::ActorImpl::get_maxpid_addr(), actors_addr};
xbt_assert(instance_->channel_.send(message) == 0, "Could not send the initial message with addresses.");
instance_->handle_messages();
void AppSide::main_loop() const
{
- simgrid::mc::processes_time.resize(simgrid::kernel::actor::get_maxpid());
+ 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]));
}
std::string TestAnyTransition::to_string(bool verbose) const
{
- auto res = xbt::string_printf("%ld: TestAny{ ", aid_);
+ auto res = xbt::string_printf("TestAny{ ");
for (auto const* t : transitions_)
res += t->to_string(verbose);
- res += "}";
+ res += " }";
return res;
}
bool TestAnyTransition::depends(const Transition* other) const
}
std::string WaitAnyTransition::to_string(bool verbose) const
{
- auto res = xbt::string_printf("%ld: WaitAny{ ", aid_);
+ auto res = xbt::string_printf("WaitAny{ ");
for (auto const* t : transitions_)
res += t->to_string(verbose);
- res += "}";
+ res += " }";
return res;
}
bool WaitAnyTransition::depends(const Transition* other) const
}
std::string CommWaitTransition::to_string(bool verbose) const
{
- auto res = xbt::string_printf("%ld: WaitComm(from %ld to %ld, mbox=%u, %s", aid_, sender_, receiver_, mbox_,
+ 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_);
if (sbuff_ != 0 && rbuff_ != 0 && wait->sbuff_ != 0 && wait->rbuff_ != 0 && rbuff_ != wait->sbuff_ &&
rbuff_ != wait->rbuff_ && rbuff_ != sbuff_)
return false;
+
+ return true;
}
- return true;
+ return false; // Comm transitions are INDEP with non-comm transitions
}
CommTestTransition::CommTestTransition(aid_t issuer, int times_considered, std::stringstream& stream)
: Transition(Type::COMM_TEST, issuer, times_considered)
}
std::string CommTestTransition::to_string(bool verbose) const
{
- auto res = xbt::string_printf("%ld: TestComm(from %ld to %ld, mbox=%u", aid_, sender_, receiver_, mbox_);
+ 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_);
return false;
}
- return true;
+ return false; // Comm transitions are INDEP with non-comm transitions
}
CommRecvTransition::CommRecvTransition(aid_t issuer, int times_considered, std::stringstream& stream)
}
std::string CommRecvTransition::to_string(bool verbose) const
{
- auto res = xbt::string_printf("%ld: iRecv(mbox=%u", aid_, mbox_);
+ auto res = xbt::string_printf("iRecv(mbox=%u", mbox_);
if (verbose)
res += ", rbuff=" + xbt::string_printf("%" PRIxPTR, rbuff_);
res += ")";
if ((aid_ != test->sender_) && (aid_ != test->receiver_) && (test->rbuff_ != rbuff_))
return false;
+
+ return true; // DEP with other send transitions
}
if (auto* wait = dynamic_cast<const CommWaitTransition*>(other)) {
if ((aid_ != wait->sender_) && (aid_ != wait->receiver_) && (wait->rbuff_ != rbuff_))
return false;
+
+ return true; // DEP with other wait transitions
}
- return true;
+ return false; // Comm transitions are INDEP with non-comm transitions
}
CommSendTransition::CommSendTransition(aid_t issuer, int times_considered, std::stringstream& stream)
}
std::string CommSendTransition::to_string(bool verbose = false) const
{
- auto res = xbt::string_printf("%ld: iSend(mbox=%u", aid_, mbox_);
+ auto res = xbt::string_printf("iSend(mbox=%u", mbox_);
if (verbose)
res += ", sbuff=" + xbt::string_printf("%" PRIxPTR, sbuff_) + ", size=" + std::to_string(size_);
res += ")";
if ((aid_ != test->sender_) && (aid_ != test->receiver_) && (test->sbuff_ != sbuff_))
return false;
+
+ return true; // DEP with other test transitions
}
if (const auto* wait = dynamic_cast<const CommWaitTransition*>(other)) {
if ((aid_ != wait->sender_) && (aid_ != wait->receiver_) && (wait->sbuff_ != sbuff_))
return false;
+
+ return true; // DEP with other wait transitions
}
- return true;
+ return false; // Comm transitions are INDEP with non-comm transitions
}
} // namespace mc
namespace s4u {
xbt::signal<void(Activity&)> Activity::on_veto;
-xbt::signal<void(Activity&)> Activity::on_completion;
+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 Actor::join(double timeout) const
{
+ xbt_assert(not(MC_is_active() || MC_record_replay_is_active()),
+ "Actor::join() is not usable in MC yet. Please report this bug.");
+
kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
const kernel::actor::ActorImpl* target = pimpl_;
kernel::actor::simcall_blocking([issuer, target, timeout] {
kernel::actor::simcall_answered([issuer, this] { return pimpl_->acquire_async(issuer); }, &lock_observer);
kernel::actor::BarrierObserver wait_observer{issuer, mc::Transition::Type::BARRIER_WAIT, acquisition.get()};
- return kernel::actor::simcall_blocking([issuer, acquisition] { return acquisition->wait_for(issuer, -1); },
+ return kernel::actor::simcall_blocking([issuer, acquisition] { acquisition->wait_for(issuer, -1); },
&wait_observer);
} else { // Do it in one simcall only
}
}
+std::string Barrier::to_string() const
+{
+ return pimpl_->to_string();
+}
+
void intrusive_ptr_add_ref(Barrier* barrier)
{
intrusive_ptr_add_ref(barrier->pimpl_);
namespace s4u {
xbt::signal<void(Comm const&)> Comm::on_send;
xbt::signal<void(Comm const&)> Comm::on_recv;
-xbt::signal<void(Comm const&)> Comm::on_completion;
CommPtr Comm::set_copy_data_callback(const std::function<void(kernel::activity::CommImpl*, void*, size_t)>& callback)
{
} // namespace s4u
} // namespace simgrid
-double SIMIX_get_clock() // XBT_ATTRIB_DEPRECATED_v332
-{
- return simgrid::s4u::Engine::get_clock();
-}
-
/* **************************** Public C interface *************************** */
void simgrid_init(int* argc, char** argv)
{
kernel::actor::simcall_answered([issuer, this] { return pimpl_->lock_async(issuer); }, &lock_observer);
kernel::actor::MutexObserver wait_observer{issuer, mc::Transition::Type::MUTEX_WAIT, pimpl_};
- kernel::actor::simcall_blocking([issuer, acquisition] { return acquisition->wait_for(issuer, -1); },
- &wait_observer);
+ kernel::actor::simcall_blocking([issuer, &acquisition] { acquisition->wait_for(issuer, -1); }, &wait_observer);
} else { // Do it in one simcall only
kernel::actor::simcall_blocking([issuer, this] { pimpl_->lock_async(issuer)->wait_for(issuer, -1); });
namespace simgrid {
namespace s4u {
-xbt::signal<void(bool symmetrical, kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
- kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
- std::vector<kernel::resource::StandardLinkImpl*> const& link_list)>
- NetZone::on_route_creation;
xbt::signal<void(NetZone const&)> NetZone::on_creation;
xbt::signal<void(NetZone const&)> NetZone::on_seal;
return res;
}
-NetZone* NetZone::add_child(NetZone* new_zone) // XBT_ATTRIB_DEPRECATED_v332
-{
- new_zone->set_parent(this);
- return this;
-}
-
const std::string& NetZone::get_name() const
{
return pimpl_->get_name();
return pimpl_->add_component(elm);
}
-// XBT_ATTRIB_DEPRECATED_v332
-std::vector<LinkInRoute>
-NetZone::convert_to_linkInRoute(const std::vector<kernel::resource::StandardLinkImpl*>& link_list)
-{
- std::vector<LinkInRoute> links;
- for (const auto* link : link_list) {
- links.emplace_back(LinkInRoute(link->get_iface()));
- }
- return links;
-}
-
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)
pimpl_->add_route(src, dst, gw_src, gw_dst, link_list, symmetrical);
}
-// XBT_ATTRIB_DEPRECATED_v332
-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<kernel::resource::StandardLinkImpl*>& link_list, bool symmetrical)
-{
- pimpl_->add_route(src, dst, gw_src, gw_dst, convert_to_linkInRoute(link_list), symmetrical);
-}
-
-// XBT_ATTRIB_DEPRECATED_v332
-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<kernel::resource::StandardLinkImpl*>& link_list, bool /*symmetrical*/)
-{
- pimpl_->add_bypass_route(src, dst, gw_src, gw_dst, convert_to_linkInRoute(link_list));
-}
-
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)
kernel::actor::SemaphoreAcquisitionObserver wait_observer{issuer, mc::Transition::Type::SEM_WAIT, acquisition.get(),
timeout};
- return kernel::actor::simcall_blocking(
- [issuer, acquisition, timeout] { return acquisition->wait_for(issuer, timeout); }, &wait_observer);
+ return kernel::actor::simcall_blocking([issuer, acquisition, timeout] { acquisition->wait_for(issuer, timeout); },
+ &wait_observer);
} else { // Do it in one simcall only and without observer
kernel::actor::SemaphoreAcquisitionObserver observer{issuer, mc::Transition::Type::SEM_WAIT, nullptr, timeout};
return kernel::actor::simcall_blocking(
- [this, issuer, timeout] { return pimpl_->acquire_async(issuer)->wait_for(issuer, timeout); }, &observer);
+ [this, issuer, timeout] { pimpl_->acquire_async(issuer)->wait_for(issuer, timeout); }, &observer);
}
}
smpi_process()->mark_as_initialized();
smpi_mpi_init();
+ CHECK_COLLECTIVE(smpi_process()->comm_world(), "MPI_Init")
return MPI_SUCCESS;
}
int PMPI_Finalize()
{
smpi_bench_end();
+ CHECK_COLLECTIVE(smpi_process()->comm_world(), "MPI_Finalize")
aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
+ smpi_process()->mark_as_finalizing();
TRACE_smpi_comm_in(rank_traced, __func__, new simgrid::instr::NoOpTIData("finalize"));
if(simgrid::config::get_value<bool>("smpi/finalization-barrier"))
{
CHECK_COMM(1)
CHECK_REQUEST(2)
-
+ CHECK_COLLECTIVE(comm, request == MPI_REQUEST_IGNORED ? "PMPI_Barrier" : "PMPI_Ibarrier")
const SmpiBenchGuard suspend_bench;
aid_t pid = simgrid::s4u::this_actor::get_pid();
TRACE_smpi_comm_in(pid, request == MPI_REQUEST_IGNORED ? "PMPI_Barrier" : "PMPI_Ibarrier",
CHECK_BUFFER(1, buf, count, datatype)
CHECK_ROOT(4)
CHECK_REQUEST(6)
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Bcast" : "PMPI_Ibcast") + " with root " +
+ std::to_string(root))
const SmpiBenchGuard suspend_bench;
aid_t pid = simgrid::s4u::this_actor::get_pid();
}
CHECK_ROOT(7)
CHECK_REQUEST(9)
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Gather" : "PMPI_Igather") + +" with root " +
+ std::to_string(root))
const void* real_sendbuf = sendbuf;
int real_sendcount = sendcount;
}
CHECK_ROOT(8)
CHECK_REQUEST(10)
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Gatherv" : "PMPI_Igatherv") +
+ " with root " + std::to_string(root))
if (rank == root){
for (int i = 0; i < comm->size(); i++) {
CHECK_BUFFER(1, sendbuf, sendcount, sendtype)
CHECK_BUFFER(4, recvbuf, recvcount, recvtype)
CHECK_REQUEST(8)
+ CHECK_COLLECTIVE(comm, request == MPI_REQUEST_IGNORED ? "PMPI_Allgather" : "PMPI_Iallggather")
if (sendbuf == MPI_IN_PLACE) {
sendbuf = static_cast<char*>(recvbuf) + recvtype->get_extent() * recvcount * comm->rank();
CHECK_COUNT(5, recvcounts[i])
CHECK_BUFFER(4, recvbuf, recvcounts[i], recvtype)
}
+ CHECK_COLLECTIVE(comm, MPI_REQUEST_IGNORED ? "PMPI_Allgatherv" : "PMPI_Iallgatherv")
const SmpiBenchGuard suspend_bench;
if (sendbuf == MPI_IN_PLACE) {
}
CHECK_ROOT(8)
CHECK_REQUEST(9)
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Scatter" : "PMPI_Iscatter") +
+ " with root " + std::to_string(root))
if (recvbuf == MPI_IN_PLACE) {
recvtype = sendtype;
} else {
CHECK_NOT_IN_PLACE_ROOT(4, recvbuf)
}
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Scatterv" : "PMPI_Iscatterv") +
+ " with root " + std::to_string(root))
const SmpiBenchGuard suspend_bench;
CHECK_OP(5, op, datatype)
CHECK_ROOT(7)
CHECK_REQUEST(8)
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Reduce" : "PMPI_Ireduce") + " with op " +
+ op->name() + " and root " + std::to_string(root))
const SmpiBenchGuard suspend_bench;
aid_t pid = simgrid::s4u::this_actor::get_pid();
CHECK_BUFFER(1, sendbuf, count, datatype)
CHECK_BUFFER(2, recvbuf, count, datatype)
CHECK_REQUEST(7)
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Alleduce" : "PMPI_Iallreduce") +
+ " with op " + op->name())
const SmpiBenchGuard suspend_bench;
std::vector<unsigned char> tmp_sendbuf;
CHECK_BUFFER(2,recvbuf,count, datatype)
CHECK_REQUEST(7)
CHECK_OP(5, op, datatype)
+ CHECK_COLLECTIVE(comm,
+ std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Scan" : "PMPI_Iscan") + " with op " + op->name())
const SmpiBenchGuard suspend_bench;
aid_t pid = simgrid::s4u::this_actor::get_pid();
CHECK_BUFFER(2, recvbuf, count, datatype)
CHECK_REQUEST(7)
CHECK_OP(5, op, datatype)
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Exscan" : "PMPI_Iexscan") + " with op " +
+ op->name())
const SmpiBenchGuard suspend_bench;
aid_t pid = simgrid::s4u::this_actor::get_pid();
CHECK_BUFFER(1, sendbuf, recvcounts[i], datatype)
CHECK_BUFFER(2, recvbuf, recvcounts[i], datatype)
}
+ CHECK_COLLECTIVE(comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Reduce_scatter" : "PMPI_Ireduce_scatter") +
+ " with op " + op->name())
const SmpiBenchGuard suspend_bench;
aid_t pid = simgrid::s4u::this_actor::get_pid();
CHECK_BUFFER(2, recvbuf, recvcount, datatype)
CHECK_REQUEST(7)
CHECK_OP(5, op, datatype)
+ CHECK_COLLECTIVE(
+ comm, std::string(request == MPI_REQUEST_IGNORED ? "PMPI_Reduce_scatter_block" : "PMPI_Ireduce_scatter_block") +
+ " with op " + op->name())
const SmpiBenchGuard suspend_bench;
int count = comm->size();
CHECK_COUNT(5, recvcount)
CHECK_BUFFER(4, recvbuf, recvcount, recvtype)
CHECK_REQUEST(8)
+ CHECK_COLLECTIVE(comm, request == MPI_REQUEST_IGNORED ? "PMPI_Alltoall" : "PMPI_Ialltoall")
aid_t pid = simgrid::s4u::this_actor::get_pid();
int real_sendcount = sendcount;
CHECK_NULL(6, MPI_ERR_COUNT, recvcounts)
CHECK_NULL(7, MPI_ERR_ARG, recvdispls)
CHECK_REQUEST(10)
+ CHECK_COLLECTIVE(comm, request == MPI_REQUEST_IGNORED ? "PMPI_Alltoallv" : "PMPI_Ialltoallv")
aid_t pid = simgrid::s4u::this_actor::get_pid();
int size = comm->size();
CHECK_TYPE(8, recvtypes[i])
CHECK_BUFFER(5, recvbuf, recvcounts[i], recvtypes[i])
}
+ CHECK_COLLECTIVE(comm, request == MPI_REQUEST_IGNORED ? "PMPI_Alltoallw" : "PMPI_Ialltoallw")
const SmpiBenchGuard suspend_bench;
{
CHECK_NULL(4, MPI_ERR_ARG, comm_out)
CHECK_COMM2(1, comm)
+ CHECK_COLLECTIVE(comm, __func__)
if( color != MPI_UNDEFINED)//we use a negative value for MPI_UNDEFINED
CHECK_NEGATIVE(3, MPI_ERR_ARG, color)
const SmpiBenchGuard suspend_bench;
{
CHECK_COMM(1)
CHECK_NULL(5, MPI_ERR_ARG, newcomm)
+ CHECK_COLLECTIVE(comm, __func__)
const SmpiBenchGuard suspend_bench;
*newcomm = comm->split_type(split_type, key, info);
return MPI_SUCCESS;
int PMPI_File_open(MPI_Comm comm, const char *filename, int amode, MPI_Info info, MPI_File *fh){
CHECK_COMM(1)
+ CHECK_COLLECTIVE(comm, "MPI_File_open")
CHECK_NULL(2, MPI_ERR_FILE, filename)
if (amode < 0)
return MPI_ERR_AMODE;
int PMPI_File_close(MPI_File *fh){
CHECK_NULL(2, MPI_ERR_ARG, fh)
+ CHECK_COLLECTIVE((*fh)->comm(), __func__)
const SmpiBenchGuard suspend_bench;
int ret = simgrid::smpi::File::close(fh);
*fh = MPI_FILE_NULL;
int PMPI_File_seek_shared(MPI_File fh, MPI_Offset offset, int whence){
CHECK_FILE(1, fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
const SmpiBenchGuard suspend_bench;
int ret = fh->seek_shared(offset,whence);
return ret;
int PMPI_File_read_all(MPI_File fh, void *buf, int count,MPI_Datatype datatype, MPI_Status *status){
CHECK_FILE_INPUTS
CHECK_WRONLY(fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
const SmpiBenchGuard suspend_bench;
aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
TRACE_smpi_comm_in(rank_traced, __func__, new simgrid::instr::CpuTIData("IO - read_all", count * datatype->size()));
int PMPI_File_read_ordered(MPI_File fh, void *buf, int count,MPI_Datatype datatype, MPI_Status *status){
CHECK_FILE_INPUTS
CHECK_WRONLY(fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
const SmpiBenchGuard suspend_bench;
aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
TRACE_smpi_comm_in(rank_traced, __func__,
int PMPI_File_write_all(MPI_File fh, const void *buf, int count,MPI_Datatype datatype, MPI_Status *status){
CHECK_FILE_INPUTS
CHECK_RDONLY(fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
const SmpiBenchGuard suspend_bench;
aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
TRACE_smpi_comm_in(rank_traced, __func__, new simgrid::instr::CpuTIData("IO - write_all", count * datatype->size()));
int PMPI_File_write_ordered(MPI_File fh, const void *buf, int count,MPI_Datatype datatype, MPI_Status *status){
CHECK_FILE_INPUTS
CHECK_RDONLY(fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
const SmpiBenchGuard suspend_bench;
aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
TRACE_smpi_comm_in(rank_traced, __func__,
int PMPI_File_read_at_all(MPI_File fh, MPI_Offset offset, void *buf, int count,MPI_Datatype datatype, MPI_Status *status){
CHECK_FILE_INPUT_OFFSET
CHECK_WRONLY(fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
const SmpiBenchGuard suspend_bench;
aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
TRACE_smpi_comm_in(rank_traced, __func__,
int PMPI_File_write_at_all(MPI_File fh, MPI_Offset offset, const void *buf, int count,MPI_Datatype datatype, MPI_Status *status){
CHECK_FILE_INPUT_OFFSET
CHECK_RDONLY(fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
const SmpiBenchGuard suspend_bench;
aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
TRACE_smpi_comm_in(rank_traced, __func__,
int PMPI_File_set_view(MPI_File fh, MPI_Offset disp, MPI_Datatype etype, MPI_Datatype filetype, const char *datarep, MPI_Info info){
CHECK_FILE(1, fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
if(not ((fh->flags() & MPI_MODE_SEQUENTIAL) && (disp == MPI_DISPLACEMENT_CURRENT)))
CHECK_OFFSET(2, disp)
CHECK_TYPE(3, etype)
int PMPI_File_set_size(MPI_File fh, MPI_Offset size)
{
CHECK_FILE(1, fh)
+ CHECK_COLLECTIVE(fh->comm(), __func__)
fh->set_size(size);
return MPI_SUCCESS;
}
CHECK_NEGATIVE(2, MPI_ERR_ARG, ndims)
for (int i = 0; i < ndims; i++)
CHECK_NEGATIVE(2, MPI_ERR_ARG, dims[i])
+ CHECK_COLLECTIVE(comm, __func__)
const auto* topo = new simgrid::smpi::Topo_Cart(comm, ndims, dims, periodic, reorder, comm_cart);
if (*comm_cart == MPI_COMM_NULL) {
delete topo;
CHECK_COMM(1)
CHECK_NULL(1, MPI_ERR_TOPOLOGY, comm->topo())
CHECK_NULL(3, MPI_ERR_ARG, comm_new)
+ CHECK_COLLECTIVE(comm, __func__)
auto* topo = static_cast<MPIR_Cart_Topology>(comm->topo().get());
if (topo==nullptr) {
return MPI_ERR_ARG;
int PMPI_Win_create( void *base, MPI_Aint size, int disp_unit, MPI_Info info, MPI_Comm comm, MPI_Win *win){
int retval = 0;
CHECK_COMM(5)
+ CHECK_BUFFER(1, base, size, MPI_BYTE)
CHECK_NEGATIVE(2, MPI_ERR_OTHER, size)
CHECK_NEGATIVE(3, MPI_ERR_OTHER, disp_unit)
+ CHECK_COLLECTIVE(comm, __func__)
const SmpiBenchGuard suspend_bench;
if (base == nullptr && size != 0){
retval= MPI_ERR_OTHER;
int PMPI_Win_free( MPI_Win* win){
CHECK_NULL(1, MPI_ERR_WIN, win)
CHECK_WIN(1, (*win))
+ CHECK_COLLECTIVE((*win)->comm(), __func__)
if (_smpi_cfg_pedantic && (*win)->opened() == 1){//only check in pedantic mode, as it's not clear this is illegal
XBT_WARN("Attempt to destroy a MPI_Win too early -missing MPI_Win_fence ?");
return MPI_ERR_WIN;
}
const SmpiBenchGuard suspend_bench;
- delete *win;
- return MPI_SUCCESS;
+ return simgrid::smpi::Win::del(*win);
}
int PMPI_Win_set_name(MPI_Win win, const char * name)
rank /* send_chunk*/, send_count, send_type);
}
win->fence(assert);
- delete win;
+ simgrid::smpi::Win::del(win);
return 0;
}
#include "../coll_tuned_topo.hpp"
#include "../colls_private.hpp"
+#include "smpi_actor.hpp"
namespace simgrid{
namespace smpi{
int barrier__mvapich2_pair(MPI_Comm comm)
int size, rank;
int d, dst, src;
int mpi_errno = MPI_SUCCESS;
+ int tag = smpi_process()->finalizing() ? COLL_TAG_BARRIER-1: COLL_TAG_BARRIER;
size = comm->size();
/* Trivial barriers return immediately */
if (rank < surfeit) {
/* get the fanin letter from the upper "half" process: */
dst = N2_prev + rank;
- Request::recv(nullptr, 0, MPI_BYTE, dst, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, dst, tag, comm, MPI_STATUS_IGNORE);
}
/* combine on embedded N2_prev power-of-two processes */
for (d = 1; d < N2_prev; d <<= 1) {
dst = (rank ^ d);
- Request::sendrecv(nullptr, 0, MPI_BYTE, dst, COLL_TAG_BARRIER, nullptr, 0, MPI_BYTE, dst, COLL_TAG_BARRIER,
+ Request::sendrecv(nullptr, 0, MPI_BYTE, dst, tag, nullptr, 0, MPI_BYTE, dst, tag,
comm, MPI_STATUS_IGNORE);
}
/* fanout data to nodes above N2_prev... */
if (rank < surfeit) {
dst = N2_prev + rank;
- Request::send(nullptr, 0, MPI_BYTE, dst, COLL_TAG_BARRIER, comm);
+ Request::send(nullptr, 0, MPI_BYTE, dst, tag, comm);
}
} else {
/* fanin data to power of 2 subset */
src = rank - N2_prev;
- Request::sendrecv(nullptr, 0, MPI_BYTE, src, COLL_TAG_BARRIER, nullptr, 0, MPI_BYTE, src, COLL_TAG_BARRIER,
+ Request::sendrecv(nullptr, 0, MPI_BYTE, src, tag, nullptr, 0, MPI_BYTE, src, tag,
comm, MPI_STATUS_IGNORE);
}
#include "../coll_tuned_topo.hpp"
#include "../colls_private.hpp"
+#include "smpi_actor.hpp"
/*
* Barrier is meant to be a synchronous operation, as some BTLs can mark
rank = comm->rank();
size = comm->size();
-
+ int tag = smpi_process()->finalizing() ? COLL_TAG_BARRIER-1: COLL_TAG_BARRIER;
XBT_DEBUG("ompi_coll_tuned_barrier_ompi_doublering rank %d", rank);
left = ((rank-1+size)%size);
right = ((rank+1)%size);
if (rank > 0) { /* receive message from the left */
- Request::recv(nullptr, 0, MPI_BYTE, left, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, left, tag, comm, MPI_STATUS_IGNORE);
}
/* Send message to the right */
- Request::send(nullptr, 0, MPI_BYTE, right, COLL_TAG_BARRIER, comm);
+ Request::send(nullptr, 0, MPI_BYTE, right, tag, comm);
/* root needs to receive from the last node */
if (rank == 0) {
- Request::recv(nullptr, 0, MPI_BYTE, left, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, left, tag, comm, MPI_STATUS_IGNORE);
}
/* Allow nodes to exit */
if (rank > 0) { /* post Receive from left */
- Request::recv(nullptr, 0, MPI_BYTE, left, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, left, tag, comm, MPI_STATUS_IGNORE);
}
/* send message to the right one */
- Request::send(nullptr, 0, MPI_BYTE, right, COLL_TAG_BARRIER, comm);
+ Request::send(nullptr, 0, MPI_BYTE, right, tag, comm);
/* rank 0 post receive from the last node */
if (rank == 0) {
- Request::recv(nullptr, 0, MPI_BYTE, left, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, left, tag, comm, MPI_STATUS_IGNORE);
}
return MPI_SUCCESS;
rank = comm->rank();
size = comm->size();
+ int tag = smpi_process()->finalizing() ? COLL_TAG_BARRIER-1: COLL_TAG_BARRIER;
XBT_DEBUG(
"ompi_coll_tuned_barrier_ompi_recursivedoubling rank %d",
rank);
if (rank >= adjsize) {
/* send message to lower ranked node */
remote = rank - adjsize;
- Request::sendrecv(nullptr, 0, MPI_BYTE, remote, COLL_TAG_BARRIER, nullptr, 0, MPI_BYTE, remote,
- COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::sendrecv(nullptr, 0, MPI_BYTE, remote, tag, nullptr, 0, MPI_BYTE, remote,
+ tag, comm, MPI_STATUS_IGNORE);
} else if (rank < (size - adjsize)) {
/* receive message from high level rank */
- Request::recv(nullptr, 0, MPI_BYTE, rank + adjsize, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, rank + adjsize, tag, comm, MPI_STATUS_IGNORE);
}
}
if (remote >= adjsize) continue;
/* post receive from the remote node */
- Request::sendrecv(nullptr, 0, MPI_BYTE, remote, COLL_TAG_BARRIER, nullptr, 0, MPI_BYTE, remote,
- COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::sendrecv(nullptr, 0, MPI_BYTE, remote, tag, nullptr, 0, MPI_BYTE, remote,
+ tag, comm, MPI_STATUS_IGNORE);
}
}
if (rank < (size - adjsize)) {
/* send enter message to higher ranked node */
remote = rank + adjsize;
- Request::send(nullptr, 0, MPI_BYTE, remote, COLL_TAG_BARRIER, comm);
+ Request::send(nullptr, 0, MPI_BYTE, remote, tag, comm);
}
}
rank = comm->rank();
size = comm->size();
+ int tag = smpi_process()->finalizing() ? COLL_TAG_BARRIER-1: COLL_TAG_BARRIER;
XBT_DEBUG(
"ompi_coll_tuned_barrier_ompi_bruck rank %d", rank);
to = (rank + distance) % size;
/* send message to lower ranked node */
- Request::sendrecv(nullptr, 0, MPI_BYTE, to, COLL_TAG_BARRIER, nullptr, 0, MPI_BYTE, from, COLL_TAG_BARRIER,
+ Request::sendrecv(nullptr, 0, MPI_BYTE, to, tag, nullptr, 0, MPI_BYTE, from, tag,
comm, MPI_STATUS_IGNORE);
}
int remote;
remote = comm->rank();
+ int tag = smpi_process()->finalizing() ? COLL_TAG_BARRIER-1: COLL_TAG_BARRIER;
XBT_DEBUG(
"ompi_coll_tuned_barrier_ompi_two_procs rank %d", remote);
remote = (remote + 1) & 0x1;
- Request::sendrecv(nullptr, 0, MPI_BYTE, remote, COLL_TAG_BARRIER, nullptr, 0, MPI_BYTE, remote, COLL_TAG_BARRIER,
+ Request::sendrecv(nullptr, 0, MPI_BYTE, remote, tag, nullptr, 0, MPI_BYTE, remote, tag,
comm, MPI_STATUS_IGNORE);
return (MPI_SUCCESS);
}
int size = comm->size();
int rank = comm->rank();
+ int tag = smpi_process()->finalizing() ? COLL_TAG_BARRIER-1: COLL_TAG_BARRIER;
/* All non-root send & receive zero-length message. */
if (rank > 0) {
- Request::send(nullptr, 0, MPI_BYTE, 0, COLL_TAG_BARRIER, comm);
+ Request::send(nullptr, 0, MPI_BYTE, 0, tag, comm);
- Request::recv(nullptr, 0, MPI_BYTE, 0, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, 0, tag, comm, MPI_STATUS_IGNORE);
}
/* The root collects and broadcasts the messages. */
requests = new MPI_Request[size];
for (i = 1; i < size; ++i) {
- requests[i] = Request::irecv(nullptr, 0, MPI_BYTE, i, COLL_TAG_BARRIER, comm);
+ requests[i] = Request::irecv(nullptr, 0, MPI_BYTE, i, tag, comm);
}
Request::waitall( size-1, requests+1, MPI_STATUSES_IGNORE );
for (i = 1; i < size; ++i) {
- requests[i] = Request::isend(nullptr, 0, MPI_BYTE, i, COLL_TAG_BARRIER, comm);
+ requests[i] = Request::isend(nullptr, 0, MPI_BYTE, i, tag, comm);
}
Request::waitall( size-1, requests+1, MPI_STATUSES_IGNORE );
delete[] requests;
rank = comm->rank();
size = comm->size();
+ int tag = smpi_process()->finalizing() ? COLL_TAG_BARRIER-1: COLL_TAG_BARRIER;
XBT_DEBUG(
"ompi_coll_tuned_barrier_ompi_tree %d",
rank);
partner = rank ^ jump;
if (!(partner & (jump-1)) && partner < size) {
if (partner > rank) {
- Request::recv(nullptr, 0, MPI_BYTE, partner, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, partner, tag, comm, MPI_STATUS_IGNORE);
} else if (partner < rank) {
- Request::send(nullptr, 0, MPI_BYTE, partner, COLL_TAG_BARRIER, comm);
+ Request::send(nullptr, 0, MPI_BYTE, partner, tag, comm);
}
}
}
partner = rank ^ jump;
if (!(partner & (jump-1)) && partner < size) {
if (partner > rank) {
- Request::send(nullptr, 0, MPI_BYTE, partner, COLL_TAG_BARRIER, comm);
+ Request::send(nullptr, 0, MPI_BYTE, partner, tag, comm);
} else if (partner < rank) {
- Request::recv(nullptr, 0, MPI_BYTE, partner, COLL_TAG_BARRIER, comm, MPI_STATUS_IGNORE);
+ Request::recv(nullptr, 0, MPI_BYTE, partner, tag, comm, MPI_STATUS_IGNORE);
}
}
}
constexpr unsigned MPI_REQ_CANCELLED = 0x8000;
constexpr unsigned MPI_REQ_NBC = 0x10000;
-enum class SmpiProcessState { UNINITIALIZED, INITIALIZING, INITIALIZED /*(=MPI_Init called)*/, FINALIZED };
+enum class SmpiProcessState { UNINITIALIZED, INITIALIZING, INITIALIZED /*(=MPI_Init called)*/, FINALIZING, FINALIZED };
constexpr int COLL_TAG_REDUCE = -112;
constexpr int COLL_TAG_SCATTER = -223;
#define CHECK_COMM2(num, comm)\
CHECK_MPI_NULL((num), MPI_COMM_NULL, MPI_ERR_COMM, (comm))
+#define CHECK_COLLECTIVE(comm, call) \
+ { \
+ if (_smpi_cfg_pedantic) { \
+ std::string call_string = (call); \
+ CHECK_ARGS((simgrid::smpi::utils::check_collectives_ordering((comm), call_string) != MPI_SUCCESS), \
+ MPI_ERR_OTHER, "%s: collective mismatch", call_string.c_str()) \
+ } \
+ }
+
#define CHECK_DELETED(num, err, obj)\
CHECK_ARGS((obj)->deleted(), (err), "%s: param %d %s has already been freed", __func__, (num),\
_XBT_STRINGIFY(obj))
int finalized() const;
int initializing() const;
int initialized() const;
+ int finalizing() const;
void mark_as_initialized();
+ void mark_as_finalizing();
void set_replaying(bool value);
bool replaying() const;
std::string get_instance_id() const { return instance_id_;}
std::unordered_map<std::string, unsigned int> sent_messages_;
std::unordered_map<std::string, unsigned int> recv_messages_;
+ unsigned int collectives_count_ = 0;
+ std::vector<unsigned int> collectives_counts_; // for MPI_COMM_WORLD only
public:
static std::unordered_map<int, smpi_key_elem> keyvals_;
void increment_sent_messages_count(int src, int dst, int tag);
unsigned int get_received_messages_count(int src, int dst, int tag);
void increment_received_messages_count(int src, int dst, int tag);
+ unsigned int get_collectives_count();
+ void increment_collectives_count();
};
} // namespace smpi
int refcount_ = 1;
bool is_predefined_;
int types_; //bitmask of the allowed datatypes flags
+ std::string name_;
public:
- Op(MPI_User_function* function, bool commutative, bool predefined=false, int types=0) : func_(function), is_commutative_(commutative), is_predefined_(predefined), types_(types) {if(not predefined) this->add_f();}
+ Op(MPI_User_function* function, bool commutative, bool predefined = false, int types = 0, std::string name = "MPI_Op")
+ : func_(function), is_commutative_(commutative), is_predefined_(predefined), types_(types), name_(std::move(name))
+ {
+ if (not predefined)
+ this->add_f();
+ }
bool is_commutative() const { return is_commutative_; }
bool is_predefined() const { return is_predefined_; }
bool is_fortran_op() const { return is_fortran_op_; }
int allowed_types() const { return types_; }
- std::string name() const override {return std::string("MPI_Op");}
+ std::string name() const override {return name_;}
// tell that we were created from fortran, so we need to translate the type to fortran when called
void set_fortran_op() { is_fortran_op_ = true; }
void apply(const void* invec, void* inoutvec, const int* len, MPI_Datatype datatype) const;
#include <xbt/base.h>
#include "smpi_f2c.hpp"
+#include "smpi_comm.hpp"
#include <cstddef>
#include <string>
XBT_PUBLIC void set_current_buffer(int i, const char* name, const void* handle);
XBT_PUBLIC size_t get_buffer_size(const void* ptr);
XBT_PUBLIC void account_free(const void* ptr);
+XBT_PUBLIC int check_collectives_ordering(MPI_Comm comm, const std::string& call);
} // namespace utils
} // namespace smpi
Win(MPI_Info info, MPI_Comm comm) : Win(MPI_BOTTOM, 0, 1, info, comm, false, true){};
Win(const Win&) = delete;
Win& operator=(const Win&) = delete;
- ~Win() override;
+ static int del(Win* win);
int attach (void *base, MPI_Aint size);
int detach (const void *base);
void get_name(char* name, int* length) const;
state_ = SmpiProcessState::INITIALIZED;
}
+/** @brief Mark a process as finalizing (=MPI_Finalize called) */
+void ActorExt::mark_as_finalizing()
+{
+ if (state_ != SmpiProcessState::FINALIZED)
+ state_ = SmpiProcessState::FINALIZING;
+}
+
+/** @brief Check if a process is finalizing */
+int ActorExt::finalizing() const
+{
+ return (state_ == SmpiProcessState::FINALIZING);
+}
+
void ActorExt::set_replaying(bool value)
{
if (state_ != SmpiProcessState::FINALIZED)
simgrid::config::Flag<bool> _smpi_cfg_default_errhandler_is_error{
"smpi/errors-are-fatal", "Whether MPI errors are fatal or just return. Default is true", true };
simgrid::config::Flag<bool> _smpi_cfg_pedantic{
- "smpi/pedantic", "Activate extra checks that may crash slightly incorrect codes which would not crash on actual implementations", true };
+ "smpi/pedantic", "Activate extra checks that may crash slightly incorrect codes which would not crash on actual implementations", false };
simgrid::config::Flag<double> _smpi_init_sleep(
"smpi/init", "Time to inject inside a call to MPI_Init", 0.0);
#if HAVE_PAPI
#include "src/surf/xml/platf.hpp"
#include "xbt/file.hpp"
#include "xbt/log.h"
+#include "xbt/ex.h"
#include "xbt/parse_units.hpp"
#include "xbt/sysdep.h"
#include <algorithm>
std::unordered_map<const void*, alloc_metadata_t> allocs;
+std::unordered_map<int, std::vector<std::string>> collective_calls;
+
std::vector<s_smpi_factor_t> parse_factor(const std::string& smpi_coef_string)
{
std::vector<s_smpi_factor_t> smpi_factor;
}
}
+int check_collectives_ordering(MPI_Comm comm, const std::string& call)
+{
+ unsigned int count = comm->get_collectives_count();
+ comm->increment_collectives_count();
+ auto vec = collective_calls.find(comm->id());
+ if (vec == collective_calls.end()) {
+ collective_calls.emplace(comm->id(), std::vector<std::string>{call});
+ } else {
+ // are we the first ? add the call
+ if (vec->second.size() == count) {
+ vec->second.emplace_back(call);
+ } else if (vec->second.size() > count) {
+ if (vec->second[count] != call) {
+ XBT_WARN("Collective operation mismatch. For process %ld, expected %s, got %s",
+ simgrid::s4u::this_actor::get_pid(), vec->second[count].c_str(), call.c_str());
+ return MPI_ERR_OTHER;
+ }
+ } else {
+ THROW_IMPOSSIBLE;
+ }
+ }
+ return MPI_SUCCESS;
+}
}
}
} // namespace simgrid
colls::bcast(&id, 1, MPI_INT, 0, this);
XBT_DEBUG("Communicator %p has id %d", this, id);
id_=id;//only set here, as we don't want to change it in the middle of the bcast
- colls::barrier(this);
}
}
recv_messages_[hash_message(src, dst, tag)]++;
}
+unsigned int Comm::get_collectives_count()
+{
+ if (this==MPI_COMM_UNINITIALIZED){
+ return smpi_process()->comm_world()->get_collectives_count();
+ }else if(this == MPI_COMM_WORLD || this == smpi_process()->comm_world()){
+ if (collectives_counts_.empty())
+ collectives_counts_.resize(this->size());
+ return collectives_counts_[this->rank()];
+ }else{
+ return collectives_count_;
+ }
+}
+
+void Comm::increment_collectives_count()
+{
+ if (this==MPI_COMM_UNINITIALIZED){
+ smpi_process()->comm_world()->increment_collectives_count();
+ }else if (this == MPI_COMM_WORLD || this == smpi_process()->comm_world()){
+ if (collectives_counts_.empty())
+ collectives_counts_.resize(this->size());
+ collectives_counts_[this->rank()]++;
+ }else{
+ collectives_count_++;
+ }
+}
+
} // namespace smpi
} // namespace simgrid
delete shared_file_pointer_;
delete[] list_;
}
- delete win_;
+ simgrid::smpi::Win::del(win_);
file_->close();
F2C::free_f(this->f2c_id());
if (info_ != MPI_INFO_NULL)
/* obviously a no-op */
}
-
-#define CREATE_MPI_OP(name, func, types) \
- SMPI_Op _XBT_CONCAT(smpi_MPI_, name)(&(func) /* func */, true, true, types);
+#define CREATE_MPI_OP(name, func, types) \
+ SMPI_Op _XBT_CONCAT(smpi_MPI_, name)(&(func), true, true, types, _XBT_STRINGIFY(MPI_##name));
#define MAX_TYPES DT_FLAG_C_INTEGER|DT_FLAG_F_INTEGER|DT_FLAG_FP|DT_FLAG_MULTILANG
#define LAND_TYPES DT_FLAG_C_INTEGER|DT_FLAG_FP|DT_FLAG_LOGICAL|DT_FLAG_MULTILANG
// this is not a detached send
kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
kernel::actor::ActivityWaitSimcall observer{issuer, (*request)->action_.get(), -1};
- kernel::actor::simcall_blocking(
- [&observer] { observer.get_activity()->wait_for(observer.get_issuer(), observer.get_timeout()); },
- &observer);
+ kernel::actor::simcall_blocking([issuer, &observer] { observer.get_activity()->wait_for(issuer, -1); },
+ &observer);
} catch (const CancelException&) {
XBT_VERB("Request cancelled");
}
colls::allgather(&connected_wins_[rank_], sizeof(MPI_Win), MPI_BYTE, connected_wins_.data(), sizeof(MPI_Win),
MPI_BYTE, comm);
if (MC_is_active() || MC_record_replay_is_active()){
- if (bar_.get() == nullptr) // First to arrive on the barrier
+ s4u::Barrier* bar_ptr;
+ if (rank_ == 0) {
bar_ = s4u::Barrier::create(comm->size());
- bar_->wait();
- }else{
- colls::barrier(comm);
+ bar_ptr = bar_.get();
+ }
+ colls::bcast(&bar_ptr, sizeof(s4u::Barrier*), MPI_BYTE, 0, comm);
+ if (rank_ != 0)
+ bar_ = s4u::BarrierPtr(bar_ptr);
}
this->add_f();
}
-Win::~Win(){
+int Win::del(Win* win){
//As per the standard, perform a barrier to ensure every async comm is finished
if (MC_is_active() || MC_record_replay_is_active())
- bar_->wait();
+ win->bar_->wait();
else
- colls::barrier(comm_);
- flush_local_all();
+ colls::barrier(win->comm_);
+ win->flush_local_all();
- if (info_ != MPI_INFO_NULL)
- simgrid::smpi::Info::unref(info_);
- if (errhandler_ != MPI_ERRHANDLER_NULL)
- simgrid::smpi::Errhandler::unref(errhandler_);
+ if (win->info_ != MPI_INFO_NULL)
+ simgrid::smpi::Info::unref(win->info_);
+ if (win->errhandler_ != MPI_ERRHANDLER_NULL)
+ simgrid::smpi::Errhandler::unref(win->errhandler_);
- comm_->remove_rma_win(this);
+ win->comm_->remove_rma_win(win);
- colls::barrier(comm_);
- Comm::unref(comm_);
+ colls::barrier(win->comm_);
+ Comm::unref(win->comm_);
+ if (!win->lockers_.empty() || win->opened_ < 0){
+ XBT_WARN("Freeing a locked or opened window");
+ return MPI_ERR_WIN;
+ }
+ if (win->allocated_)
+ xbt_free(win->base_);
- if (allocated_)
- xbt_free(base_);
+ F2C::free_f(win->f2c_id());
+ win->cleanup_attr<Win>();
- F2C::free_f(this->f2c_id());
- cleanup_attr<Win>();
+ delete win;
+ return MPI_SUCCESS;
}
int Win::attach(void* /*base*/, MPI_Aint size)
group->ref();
dst_group_ = group;
- opened_++; // we're open for business !
+ opened_--; // we're open for business !
XBT_DEBUG("Leaving MPI_Win_Start");
return MPI_SUCCESS;
}
group->ref();
src_group_ = group;
- opened_++; // we're open for business !
+ opened_--; // we're open for business !
XBT_DEBUG("Leaving MPI_Win_Post");
return MPI_SUCCESS;
}
flush_local_all();
- opened_--; //we're closed for business !
+ opened_++; //we're closed for business !
Group::unref(dst_group_);
dst_group_ = MPI_GROUP_NULL;
return MPI_SUCCESS;
flush_local_all();
- opened_--; //we're closed for business !
+ opened_++; //we're closed for business !
Group::unref(src_group_);
src_group_ = MPI_GROUP_NULL;
return MPI_SUCCESS;
shift 1
;;
"-analyze")
- SIMOPTS="$SIMOPTS --cfg=smpi/display-timing:yes --cfg=smpi/display-allocs:yes --cfg=smpi/list-leaks:50"
+ SIMOPTS="$SIMOPTS --cfg=smpi/display-timing:yes --cfg=smpi/display-allocs:yes --cfg=smpi/list-leaks:50 --cfg=smpi/pedantic:true"
shift 1
;;
"-help" | "--help" | "-h")
************/
void DiskS19::set_read_bandwidth(double value)
{
- read_bw_.peak = value;
-
+ DiskImpl::set_read_bandwidth(value);
if (get_read_constraint()) {
- get_model()->get_maxmin_system()->update_constraint_bound(get_read_constraint(), read_bw_.peak * read_bw_.scale);
+ get_model()->get_maxmin_system()->update_constraint_bound(get_read_constraint(), get_read_bandwidth());
}
}
void DiskS19::set_write_bandwidth(double value)
{
- write_bw_.peak = value;
-
+ DiskImpl::set_write_bandwidth(value);
if (get_write_constraint()) {
- get_model()->get_maxmin_system()->update_constraint_bound(get_write_constraint(), write_bw_.peak * write_bw_.scale);
+ get_model()->get_maxmin_system()->update_constraint_bound(get_write_constraint(), get_write_bandwidth());
}
}
void DiskS19::set_readwrite_bandwidth(double value)
{
- readwrite_bw_ = value;
+ DiskImpl::set_readwrite_bandwidth(value);
if (get_constraint()) {
- get_model()->get_maxmin_system()->update_constraint_bound(get_constraint(), readwrite_bw_);
+ get_model()->get_maxmin_system()->update_constraint_bound(get_constraint(), get_readwrite_bandwidth());
}
}
void DiskS19::apply_event(kernel::profile::Event* triggered, double value)
{
/* Find out which of my iterators was triggered, and react accordingly */
- if (triggered == read_bw_.event) {
+ if (triggered == get_read_event()) {
set_read_bandwidth(value);
- tmgr_trace_event_unref(&read_bw_.event);
-
- } else if (triggered == write_bw_.event) {
+ unref_read_event();
+ } else if (triggered == get_write_event()) {
set_write_bandwidth(value);
- tmgr_trace_event_unref(&write_bw_.event);
-
+ unref_write_event();
} else if (triggered == get_state_event()) {
if (value > 0)
turn_on();
> [ 0.000000] (0:maestro@) *** PROPERTY NOT VALID ***
> [ 0.000000] (0:maestro@) **************************
> [ 0.000000] (0:maestro@) Counter-example execution trace:
-> [ 0.000000] (0:maestro@) Random([0;5] ~> 3)
-> [ 0.000000] (0:maestro@) Random([0;5] ~> 4)
+> [ 0.000000] (0:maestro@) 1: Random([0;5] ~> 3)
+> [ 0.000000] (0:maestro@) 1: Random([0;5] ~> 4)
> [ 0.000000] (0:maestro@) Path = 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@) *** PROPERTY NOT VALID ***
> [ 0.000000] (0:maestro@) **************************
> [ 0.000000] (0:maestro@) Counter-example execution trace:
-> [ 0.000000] (0:maestro@) Random([0;5] ~> 3)
-> [ 0.000000] (0:maestro@) Random([0;5] ~> 4)
+> [ 0.000000] (0:maestro@) 1: Random([0;5] ~> 3)
+> [ 0.000000] (0:maestro@) 1: Random([0;5] ~> 4)
> [ 0.000000] (0:maestro@) Path = 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@) **************************
> [ 0.000000] (0:maestro@) From signal: Aborted
> [ 0.000000] (0:maestro@) Counter-example execution trace:
-> [ 0.000000] (0:maestro@) Random([0;5] ~> 3)
-> [ 0.000000] (0:maestro@) Random([0;5] ~> 4)
+> [ 0.000000] (0:maestro@) 1: Random([0;5] ~> 3)
+> [ 0.000000] (0:maestro@) 1: Random([0;5] ~> 4)
> [ 0.000000] (0:maestro@) Path = 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@) **************************
> [ 0.000000] (0:maestro@) From signal: Segmentation fault
> [ 0.000000] (0:maestro@) Counter-example execution trace:
-> [ 0.000000] (0:maestro@) Random([0;5] ~> 3)
-> [ 0.000000] (0:maestro@) Random([0;5] ~> 4)
+> [ 0.000000] (0:maestro@) 1: Random([0;5] ~> 3)
+> [ 0.000000] (0:maestro@) 1: Random([0;5] ~> 4)
> [ 0.000000] (0:maestro@) Path = 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
assert False, "The impossible just happened (yet again): daemons shall not finish."
-def worker(id):
+def worker(my_id):
global todo
- this_actor.info(f"Worker {id} booting")
- this_actor.on_exit(lambda killed: this_actor.info(f"Worker {id} dying {'forcefully' if killed else 'peacefully'}."))
+ this_actor.info(f"Worker {my_id} booting")
+ this_actor.on_exit(lambda killed: this_actor.info(f"Worker {my_id} dying {'forcefully' if killed else 'peacefully'}."))
while todo > 0:
assert Engine.clock < deadline, f"Failed to run all tasks in less than {deadline} seconds. Is this an infinite loop?"
this_actor.info("Timeouted while getting a task.")
if __name__ == '__main__':
- global mailbox
e = Engine(sys.argv)
assert host_count > 2, "You need at least 2 workers (i.e., 3 hosts) or the master will be auto-killed when the only worker gets killed."
# Only the python scripts are embeeded in the archive, and the C test files are generated at config time using these scripts.
# These python scripts are copied over from the MBI repository with as little changes as possible.
-set(generator_scripts CollMatchingGenerator.py ResleakGenerator.py) # More generators to come
+set(generator_scripts
+ CollArgGenerator.py
+ CollComGenerator.py
+ CollLocalConcurrencyGenerator.py
+ CollMatchingGenerator.py
+ CollP2PMatchingGenerator.py
+ CollP2PMessageRaceGenerator.py
+ CollTopoGenerator.py
+ MissingWaitandStartGenerator.py
+ P2PArgGenerator.py
+ P2PComGenerator.py
+ P2PInvalidComGenerator.py
+ P2PLocalConcurrencyGenerator.py
+ P2PMatchingANYSRCGenerator.py
+ P2PMatchingGenerator.py
+ P2PProbeGenerator.py
+ ResleakGenerator.py
+ RMAArgGenerator.py
+ RMAInvalidArgGenerator.py
+ RMALocalLocalConcurrencyGenerator.py
+ RMAP2PGlobalConcurrencyGenerator.py
+ RMARemoteLocalConcurrencyGenerator.py
+ RMARemoteRemoteConcurrencyGenerator.py
+ RMAReqLifecycleGenerator.py
+ RMAWinBufferGenerator.py)
if (enable_smpi_MBI_testsuite)
if (NOT enable_smpi)
else()
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/MBIutils.py DESTINATION ${CMAKE_BINARY_DIR}/MBI)
endif()
+
+ # The following tests are known to fail 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
+ foreach(localmodif
+ LocalConcurrency_Iallgather_nok LocalConcurrency_Iallgatherv_nok LocalConcurrency_Iallreduce_nok LocalConcurrency_Ialltoall_nok
+ LocalConcurrency_Ialltoallv_nok LocalConcurrency_Ibcast_nok LocalConcurrency_Iexscan_nok LocalConcurrency_Igather_nok
+ LocalConcurrency_Irecv_Isend_nok LocalConcurrency_Irecv_Send_init_nok LocalConcurrency_Irecv_Send_nok LocalConcurrency_Ireduce_nok
+ LocalConcurrency_Iscan_nok LocalConcurrency_Iscatter_nok LocalConcurrency_Recv_Isend_nok LocalConcurrency_Recv_Send_init_nok
+ LocalConcurrency_Recv_init_Isend_nok LocalConcurrency_Recv_init_Send_nok LocalConcurrency_Recv_init_Send_init_nok
+
+ GlobalConcurrency_Get_Isend_Irecv_nok GlobalConcurrency_Get_Isend_Recv_nok GlobalConcurrency_Get_Send_Irecv_nok GlobalConcurrency_Get_Send_Recv_nok
+ GlobalConcurrency_Put_Isend_Irecv_nok GlobalConcurrency_Put_Isend_Recv_nok GlobalConcurrency_Put_Send_Irecv_nok GlobalConcurrency_Put_Send_Recv_nok
+
+ GlobalConcurrency_rl_Win_fence_Get_rload_nok GlobalConcurrency_rl_Win_fence_Get_rstore_nok
+ GlobalConcurrency_rl_Win_fence_Put_rload_nok GlobalConcurrency_rl_Win_fence_Put_rstore_nok
+ GlobalConcurrency_rl_Win_lock_all_Get_rload_nok GlobalConcurrency_rl_Win_lock_all_Get_rstore_nok
+ GlobalConcurrency_rl_Win_lock_all_Put_rload_nok GlobalConcurrency_rl_Win_lock_all_Put_rstore_nok
+ )
+ set_tests_properties(mbi-${localmodif} PROPERTIES WILL_FAIL true)
+ endforeach(localmodif )
endif()
# Add the needed files to the distribution
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: @{collfeature}@
+ COLL!nonblocking: @{icollfeature}@
+ COLL!persistent: Lacking
+ COLL!tools: @{toolfeature}@
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define buff_size 128
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int root = 0;
+ int size = 1, j=0, color=0;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Op op = MPI_SUM;
+ MPI_Datatype type = MPI_INT;
+
+ int dbs = sizeof(int)*nprocs; /* Size of the dynamic buffers for alltoall and friends */
+
+ @{init}@
+ @{start}@
+
+ @{change_arg}@
+ @{operation}@ /* MBIERROR2 */
+ @{fini}@
+ @{free}@
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+#####################################################
+# Generate code with color mismatch in MPI_Comm_split
+#####################################################
+
+for c in tcoll4color:
+ patterns = {}
+ patterns = {'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['collfeature'] = 'Lacking'
+ patterns['icollfeature'] = 'Lacking'
+ patterns['toolfeature'] = 'Yes' if c in tcoll4color else 'Lacking'
+ patterns['c'] = c
+ patterns['init'] = init[c]("1")
+ patterns['start'] = start[c]("1")
+ patterns['operation'] = operation[c]("1")
+ patterns['fini'] = fini[c]("1")
+ patterns['free'] = free[c]("1")
+ patterns['change_arg'] = ''
+
+ # Generate the code with invalid color
+ replace = patterns
+ replace['shortdesc'] = 'Invalid color in @{c}@'
+ replace['longdesc'] = 'invalid color in @{c}@'
+ replace['outcome'] = 'ERROR: InvalidOtherArg'
+ replace['errormsg'] = 'Invalid Argument in collective. @{c}@ at line @{line:MBIERROR2}@ has an invalid color'
+ replace['change_arg'] = 'color=-10; /* MBIERROR1*/'
+ make_file(template, f'InvalidParam_OtherArg_{c}_nok.c', replace)
+
+
+##################################
+# Generate code with root mismatch
+##################################
+
+for c in coll4root + icoll4root:
+ patterns = {}
+ patterns = {'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['collfeature'] = 'Yes' if c in coll4root else 'Lacking'
+ patterns['icollfeature'] = 'Yes' if c in icoll4root else 'Lacking'
+ patterns['toolfeature'] = 'Lacking'
+ patterns['c'] = c
+ patterns['init'] = init[c]("1")
+ patterns['start'] = start[c]("1")
+ patterns['fini'] = fini[c]("1")
+ patterns['free'] = free[c]("1")
+ patterns['operation'] = operation[c]("1")
+ patterns['change_arg'] = ''
+
+ # Generate an incorrect root matching (root mismatch)
+ replace = patterns
+ replace['shortdesc'] = 'Collective @{c}@ with a root mismatch'
+ replace['longdesc'] = f'Odd ranks use 0 as a root while even ranks use 1 as a root'
+ replace['outcome'] = 'ERROR: RootMatching'
+ replace['errormsg'] = 'Collective root mistmatch. @{c}@ at @{filename}@:@{line:MBIERROR2}@ has 0 or 1 as a root.'
+ replace['change_arg'] = 'if (rank % 2)\n root = 1; /* MBIERROR1 */'
+ make_file(template, f'ParamMatching_Root_{c}_nok.c', replace)
+
+ # Generate the call with root=-1 (invalid root)
+ replace = patterns
+ replace['shortdesc'] = f'Collective {c} with root = -1'
+ replace['longdesc'] = f'Collective {c} with root = -1'
+ replace['outcome'] = 'ERROR: InvalidRoot'
+ replace['errormsg'] = 'Invalid collective root. @{c}@ at @{filename}@:@{line:MBIERROR2}@ has -1 as a root while communicator MPI_COMM_WORLD requires ranks in range 0 to 1.'
+ replace['change_arg'] = 'root = -1; /* MBIERROR1 */'
+ make_file(template, f'InvalidParam_RootNeg_{c}_nok.c', replace)
+
+ # Generate the call with root=2 (root not in communicator)
+ replace = patterns
+ replace['shortdesc'] = f'Collective {c} with root out of the communicator'
+ replace['longdesc'] = f'Collective {c} with root = 2 (there is only 2 ranks)'
+ replace['outcome'] = 'ERROR: InvalidRoot'
+ replace['errormsg'] = 'Invalid collective root. @{c}@ at @{filename}@:@{line:MBIERROR2}@ has 2 as a root while communicator MPI_COMM_WORLD requires ranks in range 0 to 1.'
+ replace['change_arg'] = 'root = nprocs; /* MBIERROR1 */'
+ make_file(template, f'InvalidParam_RootTooLarge_{c}_nok.c', replace)
+
+
+##################################
+# Generate code with type mismatch
+##################################
+
+for c in coll + icoll:
+ if c != 'MPI_Barrier': # Barrier has no Data to mismatch or to nullify
+ patterns = {}
+ patterns = {'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['collfeature'] = 'Yes' if c in coll else 'Lacking'
+ patterns['icollfeature'] = 'Yes' if c in icoll + ibarrier else 'Lacking'
+ patterns['toolfeature'] = 'Lacking'
+ patterns['c'] = c
+ patterns['init'] = init[c]("1")
+ patterns['start'] = start[c]("1")
+ patterns['fini'] = fini[c]("1")
+ patterns['operation'] = operation[c]("1")
+ patterns['free'] = free[c]("1")
+ patterns['change_arg'] = ''
+
+ # Generate the incorrect matching (datatype Mmismatch)
+ replace = patterns
+ replace['shortdesc'] = 'Collective @{c}@ with a datatype mismatch'
+ replace['longdesc'] = f'Odd ranks use MPI_INT as the datatype while even ranks use MPI_FLOAT'
+ replace['outcome'] = 'ERROR: DatatypeMatching'
+ replace['errormsg'] = 'Collective datatype mistmatch. @{c}@ at @{filename}@:@{line:MBIERROR2}@ has MPI_INT or MPI_FLOAT as a datatype.'
+ replace['change_arg'] = 'if (rank % 2)\n type = MPI_FLOAT; /* MBIERROR1 */'
+ make_file(template, f'ParamMatching_Data_{c}_nok.c', replace)
+
+ # Generate the call with null type (invalid datatype)
+ replace = patterns
+ replace['shortdesc'] = 'Collective @{c}@ with an invalid datatype '
+ replace['longdesc'] = 'Collective @{c}@ with an invalid datatype '
+ replace['outcome'] = 'ERROR: InvalidDatatype'
+ replace['errormsg'] = 'Invalid Datatype. @{c}@ at @{filename}@:@{line:MBIERROR2}@ has an invalid datatype.'
+ replace['change_arg'] = 'type=MPI_DATATYPE_NULL; /* MBIERROR1 */'
+ make_file(template, f'InvalidParam_DataNull_{c}_nok.c', replace)
+
+
+##################################
+# Generate code with Op mismatch
+##################################
+
+for c in coll4op + icoll4op:
+ patterns = {}
+ patterns = {'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['collfeature'] = 'Yes' if c in coll4op else 'Lacking'
+ patterns['icollfeature'] = 'Yes' if c in icoll4op else 'Lacking'
+ patterns['toolfeature'] = 'Lacking'
+ patterns['c'] = c
+ patterns['init'] = init[c]("1")
+ patterns['start'] = start[c]("1")
+ patterns['fini'] = fini[c]("1")
+ patterns['operation'] = operation[c]("1")
+ patterns['free'] = free[c]("1")
+ patterns['change_arg'] = ''
+
+ # Generate the incorrect matching (op mismatch)
+ replace = patterns
+ replace['shortdesc'] = 'Collective @{c}@ with an operator mismatch'
+ replace['longdesc'] = f'Odd ranks use MPI_SUM as the operator while even ranks use MPI_MAX'
+ replace['outcome'] = 'ERROR: OperatorMatching'
+ replace['errormsg'] = 'Collective operator mistmatch. @{c}@ at @{filename}@:@{line:MBIERROR2}@ has MPI_MAX or MPI_SUM as an operator.'
+ replace['change_arg'] = 'if (rank % 2)\n op = MPI_MAX; /* MBIERROR1 */'
+ make_file(template, f'ParamMatching_Op_{c}_nok.c', replace)
+
+ # Generate the call with Op=MPI_OP_NULL (invalid op)
+ replace = patterns
+ replace['shortdesc'] = 'Collective @{c}@ with an invalid operator '
+ replace['longdesc'] = 'Collective @{c}@ with an invalid operator '
+ replace['outcome'] = 'ERROR: InvalidOperator'
+ replace['errormsg'] = 'Invalid Operator. @{c}@ at @{filename}@:@{line:MBIERROR2}@ has MPI_OP_NULL as an operator.'
+ replace['change_arg'] = 'op = MPI_OP_NULL; /* MBIERROR1 */'
+ make_file(template, f'InvalidParam_OpNull_{c}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: @{collfeature}@
+ COLL!nonblocking: @{icollfeature}@
+ COLL!persistent: Lacking
+ COLL!tools: Yes
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define buff_size 128
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int root = 0;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Op op = MPI_SUM;
+ MPI_Datatype type = MPI_INT;
+ MPI_Comm newcom;
+ MPI_Comm_split(MPI_COMM_WORLD, 0, nprocs - rank, &newcom);
+
+ @{change_com}@
+
+ int dbs = sizeof(int)*nprocs; /* Size of the dynamic buffers for alltoall and friends */
+ @{init}@
+ @{start}@
+ @{operation}@ /* MBIERROR */
+ @{fini}@
+ @{free}@
+
+ if(newcom != MPI_COMM_NULL && newcom != MPI_COMM_WORLD)
+ MPI_Comm_free(&newcom);
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+# Generate code with one collective
+for c in coll + icoll + ibarrier:
+ patterns = {}
+ patterns = {'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['collfeature'] = 'Yes' if c in coll else 'Lacking'
+ patterns['icollfeature'] = 'Yes' if c in icoll + ibarrier else 'Lacking'
+ patterns['c'] = c
+ patterns['init'] = init[c]("1")
+ patterns['start'] = start[c]("1")
+ patterns['fini'] = fini[c]("1")
+ patterns['free'] = free[c]("1")
+ patterns['operation'] = operation[c]("1")
+
+ # Generate the correct code => to remove?
+ replace = patterns
+ replace['shortdesc'] = 'Collective @{c}@ with correct arguments'
+ replace['longdesc'] = f'All ranks in newcom call {c} with correct arguments'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = ''
+ replace['change_com'] = '/* No error injected here */'
+ make_file(template, f'ParamMatching_Com_{c}_ok.c', replace)
+
+ # Generate the incorrect communicator matching
+ replace = patterns
+ replace['shortdesc'] = 'Collective @{c}@ with a communicator mismatch'
+ replace['longdesc'] = f'Odd ranks call the collective on newcom while even ranks call the collective on MPI_COMM_WORLD'
+ replace['outcome'] = 'ERROR: CommunicatorMatching'
+ replace['errormsg'] = 'Communicator mistmatch in collectives. @{c}@ at @{filename}@:@{line:MBIERROR}@ has newcom or MPI_COMM_WORLD as a communicator.'
+ replace['change_com'] = 'if (rank % 2)\n newcom = MPI_COMM_WORLD; /* MBIERROR */'
+ make_file(template, f'ParamMatching_Com_{c}_nok.c', replace)
+
+ # Generate the coll with newcom=MPI_COMM_NULL
+ replace = patterns
+ replace['shortdesc'] = f'Collective @{c}@ with newcom=MPI_COMM_NULL'
+ replace['longdesc'] = f'Collective @{c}@ with newcom=MPI_COMM_NULL'
+ replace['outcome'] = 'ERROR: InvalidCommunicator'
+ replace['errormsg'] = 'Invalid communicator. @{c}@ at @{filename}@:@{line:MBIERROR}@ has MPI_COMM_NULL as a communicator.'
+ replace['change_com'] = 'newcom = MPI_COMM_NULL; /* MBIERROR */'
+ make_file(template, f'InvalidParam_ComNull_{c}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 3, requires MPI 3 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: @{icollfeature}@
+ COLL!persistent: @{pcollfeature}@
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define buff_size 128
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int root = 0;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ int dbs = sizeof(int)*nprocs; /* Size of the dynamic buffers for alltoall and friends */
+ MPI_Op op = MPI_SUM;
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+
+ @{init}@
+ @{start}@
+ @{operation}@
+ @{write}@ /* MBIERROR */
+ @{fini}@
+ @{free}@
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+for c in icoll + pcoll:
+ patterns = {}
+ patterns = {'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['icollfeature'] = 'Yes' if c in icoll else 'Lacking'
+ patterns['pcollfeature'] = 'Yes' if c in pcoll else 'Lacking'
+ patterns['c'] = c
+ patterns['init'] = init[c]("1")
+ patterns['start'] = start[c]("1")
+ patterns['fini'] = fini[c]("1")
+ patterns['operation'] = operation[c]("1")
+ patterns['write'] = write[c]("1")
+ patterns['free'] = free[c]("1")
+
+ replace = patterns
+ replace['shortdesc'] = 'Local concurrency with a collective'
+ replace['longdesc'] = f'The buffer in {c} is modified before the call has been completed.'
+ replace['outcome'] = 'ERROR: LocalConcurrency'
+ replace['errormsg'] = 'Local Concurrency with a collective. The buffer in @{c}@ is modified at @{filename}@:@{line:MBIERROR}@ whereas there is no guarantee the call has been completed.'
+ make_file(template, f'LocalConcurrency_{c}_nok.c', replace)
# Copyright 2021-2022. The MBI project. All rights reserved.
# This program is free software; you can redistribute it and/or modify it under the terms of the license (GNU GPL).
+import os
import sys
from generator_utils import *
Description: @{shortdesc}@
@{longdesc}@
- Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
BEGIN_MPI_FEATURES
- P2P!basic: Lacking
- P2P!nonblocking: Lacking
- P2P!persistent: Lacking
- COLL!basic: @{collfeature}@
- COLL!nonblocking: @{icollfeature}@
- COLL!persistent: Lacking
- COLL!tools: Lacking
- RMA: Lacking
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: @{collfeature}@
+ COLL!nonblocking: @{icollfeature}@
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: Lacking
END_MPI_FEATURES
BEGIN_MBI_TESTS
int main(int argc, char **argv) {
int nprocs = -1;
int rank = -1;
- int root = 0;
+ int root = 0;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
if (nprocs < 2)
printf("MBI ERROR: This test needs at least 2 processes to produce a bug.\\n");
- MPI_Comm newcom = MPI_COMM_WORLD;
- MPI_Datatype type = MPI_INT;
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
MPI_Op op = MPI_SUM;
int dbs = sizeof(int)*nprocs; /* Size of the dynamic buffers for alltoall and friends */
if (@{change_cond}@) {
@{operation1a}@ /* MBIERROR1 */
- @{fini1a}@
+ @{fini1a}@
@{operation2a}@
- @{fini2a}@
+ @{fini2a}@
} else {
@{operation1b}@ /* MBIERROR2 */
- @{fini1b}@
+ @{fini1b}@
@{operation2b}@
- @{fini2b}@
+ @{fini2b}@
}
@{free1}@
@{free2}@
-
+
MPI_Finalize();
printf("Rank %d finished normally\\n", rank);
return 0;
for c2 in coll + icoll + ibarrier:
patterns = {}
patterns = {'c1': c1, 'c2': c2}
- patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {sys.argv[0]}. DO NOT EDIT.'
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
patterns['collfeature'] = 'Yes' if c1 in coll or c2 in coll else 'Lacking'
patterns['icollfeature'] = 'Yes' if c1 in icoll + ibarrier or c2 in icoll + ibarrier else 'Lacking'
patterns['c1'] = c1
replace['fini2a'] = fini[c2]("2")
replace['fini1b'] = fini[c2]("2") # Inversion
replace['fini2b'] = fini[c1]("1")
- replace['free1'] = free[c2]("2")
+ replace['free1'] = free[c2]("2")
replace['free2'] = free[c1]("1")
make_file(template, f'CallOrdering_{c1}_{c2}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: Lacking
+ COLL!basic: @{collfeature}@
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int dest, src;
+ int root = 0;
+ int stag = 0, rtag = 0;
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ int dbs = sizeof(int)*nprocs; /* Size of the dynamic buffers for alltoall and friends */
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+ MPI_Op op = MPI_SUM;
+
+ @{init1}@
+ @{init2}@
+ @{init3}@
+ if (rank == 0) {
+ dest=1;src=1;
+ @{operation3}@ /* MBIERROR1 */
+ @{fini3}@
+ @{operation1}@
+ @{fini1}@
+ }else if (rank==1) {
+ dest=0;src=0;
+ @{operation2}@ /* MBIERROR2 */
+ @{fini2}@
+ @{operation3}@
+ @{fini3}@
+ }
+
+ @{free1}@
+ @{free2}@
+ @{free3}@
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for s in send + isend:
+ for r in recv + irecv:
+ for c in coll:
+ patterns = {}
+ patterns = {'s': s, 'r': r, 'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if s in send or r in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if s in isend or r in irecv else 'Lacking'
+ patterns['collfeature'] = 'Yes' if c in coll else 'Lacking'
+ patterns['s'] = s
+ patterns['r'] = r
+ patterns['c'] = c
+ patterns['init1'] = init[s]("1")
+ patterns['init2'] = init[r]("2")
+ patterns['init3'] = init[c]("3")
+ patterns['fini1'] = fini[s]("1")
+ patterns['fini2'] = fini[r]("2")
+ patterns['fini3'] = fini[c]("3")
+ patterns['free1'] = free[s]("1")
+ patterns['free2'] = free[r]("2")
+ patterns['free3'] = free[c]("3")
+ patterns['operation1'] = operation[s]("1")
+ patterns['operation2'] = operation[r]("2")
+ patterns['operation3'] = operation[c]("3")
+
+ # Generate the incorrect matching because of the conditional
+ replace = patterns
+ replace['shortdesc'] = 'Point to point & collective mismatch'
+ replace['longdesc'] = 'Point to point @{r}@ is matched with @{c}@ which causes a deadlock.'
+ replace['outcome'] = 'ERROR: CallMatching'
+ replace['errormsg'] = 'P2P & Collective mistmatch. @{r}@ at @{filename}@:@{line:MBIERROR2}@ is matched with @{c}@ at @{filename}@:@{line:MBIERROR1}@ wich causes a deadlock.'
+ make_file(template, f'CallOrdering_{r}_{s}_{c}_nok.c', replace)
+
+ # Generate the incorrect code depending on buffering
+ # replace = patterns
+ # replace['shortdesc'] = 'Point to point & collective mismatch'
+ # replace['longdesc'] = 'Point to point @{s}@ is matched with @{c}@ which causes a deadlock depending on the buffering mode.'
+ # replace['outcome'] = 'ERROR: BufferingHazard'
+ # replace['errormsg'] = 'P2P & Collective mistmatch. @{s}@ at @{filename}@:@{line:MBIERROR2}@ is matched with @{c}@ at @{filename}@:@{line:MBIERROR1}@ wich causes a deadlock.'
+ # replace['init1'] = init[s]("1")
+ # replace['init2'] = init[r]("2")
+ # replace['operation1'] = operation[r]("2")
+ # replace['operation2'] = operation[s]("1")
+ # replace['fini1'] = fini[r]("2")
+ # replace['fini2'] = fini[s]("1")
+ # make_file(template, f'CollP2PBuffering_{r}_{s}_{c}_nok.c', replace)
+
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: Lacking
+ COLL!basic: @{collfeature}@
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 4 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int dest, src;
+ int i=0;
+ int root = 0;
+ int stag = 0, rtag = 0;
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs != 4)
+ printf("MBI ERROR: This test needs 4 processes to produce a bug!\\n");
+
+ int dbs = sizeof(int)*nprocs; /* Size of the dynamic buffers for alltoall and friends */
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+ MPI_Op op = MPI_SUM;
+
+
+ @{init1}@
+ @{init2}@
+ @{init3}@
+ @{init4}@
+ if (rank == 0) {
+ dest=1;
+ @{operation1}@
+ @{fini1}@
+ @{operation2}@
+ @{fini2}@
+ }else if (rank==2) {
+ dest=1;
+ @{operation1}@
+ @{fini1}@
+ @{operation2}@
+ @{fini2}@
+ }else if (rank==1) {
+ src = MPI_ANY_SOURCE;
+ rtag = MPI_ANY_TAG;
+ @{operation3}@ /* MBIERROR1 */
+ @{operation1}@
+ @{fini1}@
+ src = 0;
+ @{operation4}@ /* MBIERROR2 */
+ @{fini3}@
+ @{fini4}@
+ }else if (rank==3) {
+ @{operation1}@
+ @{fini1}@
+ }
+
+ @{free1}@
+ @{free2}@
+ @{free3}@
+ @{free4}@
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for s in send + isend:
+ for r in irecv:
+ for c in coll:
+ patterns = {}
+ patterns = {'s': s, 'r': r, 'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if s in send or r in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if s in isend or r in irecv else 'Lacking'
+ patterns['collfeature'] = 'Yes' if c in coll else 'Lacking'
+ patterns['s'] = s
+ patterns['r'] = r
+ patterns['c'] = c
+ patterns['init1'] = init[c]("1")
+ patterns['init2'] = init[s]("2")
+ patterns['init3'] = init[r]("3")
+ patterns['init4'] = init[r]("4")
+ patterns['fini1'] = fini[c]("1")
+ patterns['fini2'] = fini[s]("2")
+ patterns['fini3'] = fini[r]("3")
+ patterns['fini4'] = fini[r]("4")
+ patterns['free1'] = free[c]("1")
+ patterns['free2'] = free[s]("2")
+ patterns['free3'] = free[r]("3")
+ patterns['free4'] = free[r]("4")
+ patterns['operation1'] = operation[c]("1")
+ patterns['operation2'] = operation[s]("2")
+ patterns['operation3'] = operation[r]("3")
+ patterns['operation4'] = operation[r]("4")
+
+ # Generate the incorrect matching because of the conditional
+ replace = patterns
+ replace['shortdesc'] = 'Message race'
+ replace['longdesc'] = 'Message race in @{r}@ with @{c}@.'
+ replace['outcome'] = 'ERROR: MessageRace'
+ replace['errormsg'] = 'Message race. The use of wildcard receive calls (@{r}@ at @{filename}@:@{line:MBIERROR1}@ and @{r}@ at @{filename}@:@{line:MBIERROR2}@) leads to nondeterministic matching.'
+ make_file(template, f'MessageRace_{c}_{s}_{r}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: @{toolfeature}@
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define buff_size 128
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Comm newcom;
+ int dims[2], periods[2], coords[2];
+ int source, dest;
+ dims[0] = 2;
+ dims[1] = 1;
+ periods[0] = 1;
+ periods[1] = 1;
+
+ @{change_dims}@
+
+ MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, 0, &newcom); /* create a cartesian communicator */
+
+ @{change_com}@
+
+ @{init}@
+ @{operation}@ /* MBIERROR2 */
+ @{fini}@
+
+ if (newcom != MPI_COMM_NULL)
+ MPI_Comm_free(&newcom);
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+for c in tcoll4topo:
+ patterns = {}
+ patterns = {'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['toolfeature'] = 'Yes' if c in tcoll4topo else 'Lacking'
+ patterns['c'] = c
+ patterns['init'] = init[c]("1")
+ patterns['fini'] = fini[c]("1")
+ patterns['operation'] = operation[c]("1")
+
+ # Generate the correct code
+ replace = patterns
+ replace['shortdesc'] = 'Function @{c}@ with correct arguments'
+ replace['longdesc'] = f'All ranks in comm call {c} with correct arguments'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = ''
+ replace['change_com'] = '/* No error injected here */'
+ replace['change_dims'] = '/* No error injected here */'
+ make_file(template, f'InvalidParam_{c}_ok.c', replace)
+
+ # Generate the incorrect code
+ replace = patterns
+ replace['shortdesc'] = 'The code tries to get cartesian information of MPI_COMM_WORLD.'
+ replace['longdesc'] = 'The code creates a cartesian communicator, and tries to get cartesian information of MPI_COMM_WORLD.'
+ replace['outcome'] = 'ERROR: InvalidCommunicator'
+ replace['errormsg'] = 'Invalid Communicator in a collective. @{c}@ at @{filename}@:@{line:MBIERROR2}@ tries to get cartesian information of MPI_COMM_WORLD.'
+ replace['change_com'] = 'newcom = MPI_COMM_WORLD; /* MBIERROR1 */'
+ make_file(template, f'InvalidParam_Com_{c}_nok.c', replace)
+
+ # Generate the code with newcom=MPI_COMM_NULL
+ replace = patterns
+ replace['shortdesc'] = 'Function @{c}@ called with comm=MPI_COMM_NULL'
+ replace['longdesc'] = 'Function @{c}@ called with comm=MPI_COMM_NULL'
+ replace['outcome'] = 'ERROR: InvalidCommunicator'
+ replace['errormsg'] = 'Invalid communicator. @{c}@ at @{filename}@:@{line:MBIERROR2}@ has MPI_COMM_NULL as a communicator.'
+ replace['change_com'] = 'newcom = MPI_COMM_NULL; /* MBIERROR1 */'
+ make_file(template, f'InvalidParam_ComNull_{c}_nok.c', replace)
+
+ # Generate the code with invalid dimension
+ replace = patterns
+ replace['shortdesc'] = 'Creates a cartesian communicator with a negative entry in the dims attribute'
+ replace['longdesc'] = 'Creates a cartesian communicator with a negative entry in the dims attribute, which is a usage error'
+ replace['outcome'] = 'ERROR: InvalidOtherArg'
+ replace['errormsg'] = 'Invalid Argument. MPI_Cart_create has invalid dimensions.'
+ replace['change_com'] = ""
+ replace['change_dims'] = 'dims[0] = -2; dims[1] = -1; /* MBIERROR1 */'
+ make_file(template, f'InvalidParam_Dim_MPI_Cart_create_nok.c', replace)
#! /usr/bin/env python3
-# Copyright 2021-2022. The SimGrid Team. All rights reserved.
+# Copyright 2021-2022. The SimGrid Team. All rights reserved.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the license (GNU LGPL) which comes with this package.
-# Copyright 2021-2022. The MBI project. All rights reserved.
+# Copyright 2021-2022. The MBI project. All rights reserved.
# This program is free software; you can redistribute it and/or modify it under the terms of the license (GNU GPL).
import os
import hashlib
class AbstractTool:
- def ensure_image(self, params=""):
+ def ensure_image(self, params="", dockerparams=""):
"""Verify that this is executed from the right docker image, and complain if not."""
if os.path.exists("/MBI") or os.path.exists("trust_the_installation"):
print("This seems to be a MBI docker image. Good.")
else:
print("Please run this script in a MBI docker image. Run these commands:")
print(" docker build -f Dockerfile -t mpi-bugs-initiative:latest . # Only the first time")
- print(f" docker run -it --rm --name MIB --volume $(pwd):/MBI mpi-bugs-initiative /MBI/MBI.py {params}")
+ print(f" docker run -it --rm --name MIB --volume $(pwd):/MBI {dockerparams}mpi-bugs-initiative /MBI/MBI.py {params}")
sys.exit(1)
def build(self, rootdir, cached=True):
Ensure that this tool (previously built) is usable in this environment: setup the PATH, etc.
This is called only once for all tests, from the logs directory.
"""
- pass
+ # pass
- def run(execcmd, filename, binary, id, timeout):
+ def run(execcmd, filename, binary, num_id, timeout):
"""Compile that test code and anaylse it with the Tool if needed (a cache system should be used)"""
- pass
+ # pass
def teardown(self):
"""
Clean the results of all test runs: remove temp files and binaries.
This is called only once for all tests, from the logs directory.
"""
- pass
+ # pass
def parse(self, cachefile):
"""Read the result of a previous run from the cache, and compute the test outcome"""
possible_details = {
# scope limited to one call
'InvalidBuffer':'AInvalidParam', 'InvalidCommunicator':'AInvalidParam', 'InvalidDatatype':'AInvalidParam', 'InvalidRoot':'AInvalidParam', 'InvalidTag':'AInvalidParam', 'InvalidWindow':'AInvalidParam', 'InvalidOperator':'AInvalidParam', 'InvalidOtherArg':'AInvalidParam', 'ActualDatatype':'AInvalidParam',
- 'InvalidSrcDest':'AInvalidParam',
+ 'InvalidSrcDest':'AInvalidParam',
# scope: Process-wide
-# 'OutOfInitFini':'BInitFini',
+# 'OutOfInitFini':'BInitFini',
'CommunicatorLeak':'BResLeak', 'DatatypeLeak':'BResLeak', 'GroupLeak':'BResLeak', 'OperatorLeak':'BResLeak', 'TypeLeak':'BResLeak', 'RequestLeak':'BResLeak',
'MissingStart':'BReqLifecycle', 'MissingWait':'BReqLifecycle',
'LocalConcurrency':'BLocalConcurrency',
# scope: communicator
- 'CallMatching':'DMatch',
+ 'CallMatching':'DMatch',
'CommunicatorMatching':'CMatch', 'DatatypeMatching':'CMatch', 'OperatorMatching':'CMatch', 'RootMatching':'CMatch', 'TagMatching':'CMatch',
- 'MessageRace':'DRace',
-
+ 'MessageRace':'DRace',
+
'GlobalConcurrency':'DGlobalConcurrency',
# larger scope
# 'BufferingHazard':'EBufferingHazard',
"""
res = []
test_num = 0
- with open(filename, "r") as input:
+ with open(filename, "r") as input_file:
state = 0 # 0: before header; 1: in header; 2; after header
line_num = 1
- for line in input:
+ for line in input_file:
if re.match(".*BEGIN_MBI_TESTS.*", line):
if state == 0:
state = 1
if state == 1 and re.match("\s+\$ ?.*", line):
m = re.match('\s+\$ ?(.*)', line)
cmd = m.group(1)
- nextline = next(input)
+ nextline = next(input_file)
detail = 'OK'
if re.match('[ |]*OK *', nextline):
expect = 'OK'
diagnostic = f'hard timeout'
else:
diagnostic = f'timeout after {elapsed} sec'
- elif outcome == 'failure':
+ elif outcome == 'failure' or outcome == 'segfault':
res_category = 'failure'
diagnostic = f'tool error, or test not run'
elif outcome == 'UNIMPLEMENTED':
def run_cmd(buildcmd, execcmd, cachefile, filename, binary, timeout, batchinfo, read_line_lambda=None):
"""
Runs the test on need. Returns True if the test was ran, and False if it was cached.
-
+
The result is cached if possible, and the test is rerun only if the `test.txt` (containing the tool output) or the `test.elapsed` (containing the timing info) do not exist, or if `test.md5sum` (containing the md5sum of the code to compile) does not match.
Parameters:
- - buildcmd and execcmd are shell commands to run. buildcmd can be any shell line (incuding && groups), but execcmd must be a single binary to run.
+ - buildcmd and execcmd are shell commands to run. buildcmd can be any shell line (incuding && groups), but execcmd must be a single binary to run.
- cachefile is the name of the test
- filename is the source file containing the code
- binary the file name in which to compile the code
if olddigest == newdigest:
print(f" (result cached -- digest: {olddigest})")
return False
- else:
- os.remove(f'{cachefile}.txt')
+ os.remove(f'{cachefile}.txt')
print(f"Wait up to {timeout} seconds")
start_time = time.time()
- if buildcmd == None:
+ if buildcmd is None:
output = f"No need to compile {binary}.c (batchinfo:{batchinfo})\n\n"
else:
output = f"Compiling {binary}.c (batchinfo:{batchinfo})\n\n"
for chunk in iter(lambda: sourcefile.read(4096), b""):
hashed.update(chunk)
outfile.write(hashed.hexdigest())
-
+
return True
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: @{persfeature}@
+ COLL!basic: Lacking
+ COLL!nonblocking: @{icollfeature}@
+ COLL!persistent: @{cpersfeature}@
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int root = 0;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+ MPI_Op op = MPI_SUM;
+ int stag = 0, rtag = 0;
+ int buff_size = 1;
+
+ int dbs = sizeof(int)*nprocs; /* Size of the dynamic buffers for alltoall and friends */
+
+ int dest = (rank == nprocs - 1) ? (0) : (rank + 1);
+ int src = (rank == 0) ? (nprocs - 1) : (rank - 1);
+
+ @{init1}@
+ @{init2}@
+
+ @{operation1}@ /* MBIERROR */
+ @{start1}@
+ @{operation2}@
+ @{start2}@
+
+ @{fini1}@
+ @{fini2}@
+
+ @{free1}@
+ @{free2}@
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for s in isend + psend:
+ for r in irecv + precv:
+ patterns = {}
+ patterns = {'s': s, 'r': r}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['persfeature'] = 'Yes' if s in psend or r in precv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if s in isend or r in irecv else 'Lacking'
+ patterns['icollfeature'] = 'Lacking'
+ patterns['cpersfeature'] = 'Lacking'
+ patterns['s'] = s
+ patterns['r'] = r
+ patterns['init1'] = init[s]("1")
+ patterns['init2'] = init[r]("2")
+ patterns['start1'] = start[s]("1")
+ startPers = patterns['start1']
+ patterns['start2'] = start[r]("2")
+ patterns['operation1'] = operation[s]("1")
+ patterns['operation2'] = operation[r]("2")
+ patterns['fini1'] = fini[s]("1")
+ wait = patterns['fini1']
+ patterns['fini2'] = fini[r]("2")
+ patterns['free1'] = free[s]("1")
+ Reqfree = patterns['free1']
+ patterns['free2'] = free[r]("2")
+
+ # Generate the correct code
+ replace = patterns
+ replace['shortdesc'] = 'Correct matching'
+ replace['longdesc'] = f'No error'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = 'OK'
+ make_file(template, f'ReqLifecycle_{s}_{r}_ok.c', replace)
+
+ # Generate the code with a missing wait
+ replace = patterns
+ replace['shortdesc'] = 'Missing wait'
+ replace['longdesc'] = 'Missing Wait. @{s}@ at @{filename}@:@{line:MBIERROR}@ has no completion.'
+ replace['outcome'] = 'ERROR: MissingWait'
+ replace['errormsg'] = 'ERROR: MissingWait'
+ replace['fini1'] = ' /* MBIERROR MISSING: ' + wait + ' */'
+ make_file(template, f'ReqLifecycle_MissingWait_{s}_{r}_nok.c', replace)
+
+ if s in psend:
+ # Generate the code with a missing start - persistent only
+ replace = patterns
+ replace['shortdesc'] = 'Missing start'
+ replace['longdesc'] = 'Missing start. @{s}@ at @{filename}@:@{line:MBIERROR}@ has no start'
+ replace['outcome'] = 'ERROR: MissingStart'
+ replace['errormsg'] = 'ERROR: MissingStart'
+ replace['fini1'] = fini[s]("1")
+ replace['start1'] = ' /* MBIERROR MISSING: ' + startPers + ' */'
+ make_file(template, f'ReqLifecycle_MissingStart_{s}_{r}_nok.c', replace)
+ # Generate the code with a missing free - persistent only
+ replace = patterns
+ replace['shortdesc'] = 'Missing free'
+ replace['longdesc'] = 'Missing free. @{s}@ at @{filename}@:@{line:MBIERROR}@ has no free'
+ replace['outcome'] = 'ERROR: RequestLeak'
+ replace['errormsg'] = 'ERROR: RequestLeak'
+ replace['start1'] = start[s]("1")
+ replace['free1'] = ' /* MBIERROR MISSING: ' + Reqfree + ' */'
+ make_file(template, f'ResLeak_nofree_{s}_{r}_nok.c', replace)
+
+
+# Collectives only
+for c in pcoll + icoll + ibarrier:
+ patterns = {}
+ patterns = {'c': c}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['persfeature'] = 'Lacking'
+ patterns['ip2pfeature'] = 'Lacking'
+ patterns['cpersfeature'] = 'Yes' if c in pcoll else 'Lacking'
+ patterns['icollfeature'] = 'Yes' if c in icoll + ibarrier else 'Lacking'
+ patterns['c'] = c
+ patterns['init1'] = init[c]("1")
+ patterns['operation1'] = operation[c]("1")
+ patterns['start1'] = start[c]("1")
+ patterns['fini1'] = fini[c]("1")
+ patterns['free1'] = free[c]("1")
+ opstart = patterns['start1']
+ opwait = patterns['fini1']
+ opfree = patterns['free1']
+ patterns['init2'] = ""
+ patterns['operation2'] = ""
+ patterns['start2'] = ""
+ patterns['fini2'] = ""
+ patterns['free2'] = ""
+
+ # Generate the code with a missing wait
+ replace = patterns
+ replace['shortdesc'] = 'Missing wait'
+ replace['longdesc'] = 'Missing Wait. @{c}@ at @{filename}@:@{line:MBIERROR}@ has no completion'
+ replace['outcome'] = 'ERROR: MissingWait'
+ replace['errormsg'] = 'ERROR: MissingWait'
+ replace['fini1'] = ' /* MBIERROR MISSING: ' + opwait + ' */'
+ replace['free1'] = ' /* MISSING: ' + replace['free1'] + ' (to not free the buffer before an internal wait */'
+ make_file(template, f'ReqLifecycle_MissingWait_{c}_nok.c', replace)
+
+ if c in pcoll:
+ # Generate the code with a missing start - persistent only
+ replace = patterns
+ replace['shortdesc'] = 'Missing start functio'
+ replace['longdesc'] = 'Missing Start. @{c}@ at @{filename}@:@{line:MBIERROR}@ has no start'
+ replace['outcome'] = 'ERROR: MissingStart'
+ replace['errormsg'] = 'ERROR: MissingStart'
+ replace['fini1'] = fini[c]("1")
+ replace['start1'] = ' /* MBIERROR MISSING: ' + opstart + ' */'
+ make_file(template, f'ReqLifecycle_MissingStart_{c}_nok.c', replace)
+
+ # Generate the code with a resleak (no free) - persistent only
+ replace = patterns
+ replace['shortdesc'] = 'Missing free'
+ replace['longdesc'] = 'Missing free. @{c}@ at @{filename}@:@{line:MBIERROR}@ has no free'
+ replace['outcome'] = 'ERROR: RequestLeak'
+ replace['errormsg'] = 'ERROR: RequestLeak'
+ replace['start1'] = start[c]("1")
+ replace['free1'] = ' /* MBIERROR MISSING: ' + opfree + ' */'
+ make_file(template, f'ResLeak_nofree_{c}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: @{persfeature}@
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int src=0, dest=1;
+ int stag=0, rtag=0;
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+
+ @{change_arg}@
+
+ @{init1}@
+ @{init2}@
+ if (rank == 0) {
+ @{operation1}@ /* MBIERROR1 */
+ @{start1}@
+ @{fini1}@
+ }else if (rank == 1) {
+ @{operation2}@ /* MBIERROR2 */
+ @{start2}@
+ @{fini2}@
+ }
+ @{free1}@
+ @{free2}@
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+##################################
+# Generate code with type mismatch
+##################################
+
+for p1 in allsend:
+ for p2 in allrecv:
+ patterns = {}
+ patterns = {'p1': p1, 'p2': p2}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if p1 in send + ssend + bsend or p2 in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if p1 in isend or p2 in irecv else 'Lacking'
+ patterns['persfeature'] = 'Yes' if p1 in psend or p2 in precv else 'Lacking'
+ patterns['p1'] = p1
+ patterns['p2'] = p2
+ patterns['init1'] = init[p1]("1")
+ patterns['init2'] = init[p2]("2")
+ patterns['start1'] = start[p1]("1")
+ patterns['start2'] = start[p2]("2")
+ patterns['fini1'] = fini[p1]("1")
+ patterns['fini2'] = fini[p2]("2")
+ patterns['operation1'] = operation[p1]("1") #send
+ patterns['operation2'] = operation[p2]("2") #recv
+ patterns['free1'] = free[p1]("1")
+ patterns['free2'] = free[p2]("2")
+
+ # Generate the incorrect matching
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{p1}@ and @{p2}@ have a datatype mismatch'
+ replace['longdesc'] = 'Process 0 uses MPI_FLOAT as the datatype while process 1 uses MPI_INT.'
+ replace['outcome'] = 'ERROR: DatatypeMatching'
+ replace['errormsg'] = 'P2P Datatype mismatch. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ and @{p2}@ at @{filename}@:@{line:MBIERROR2}@ have MPI_INT and MPI_FLOAT as a datatype'
+ replace['change_arg'] = 'if (rank == 0)\n type = MPI_FLOAT; /* MBIERROR3 */'
+ make_file(template, f'ParamMatching_Data_{p1}_{p2}_nok.c', replace)
+
+ # Generate code with a null type
+ replace = patterns
+ replace['shortdesc'] = 'Use of invalid datatype in point-to-point communication'
+ replace['longdesc'] = 'Point to point @{p1}@ and @{p2}@ have MPI_DATATYPE_NULL as a type'
+ replace['outcome'] = 'ERROR: InvalidDatatype'
+ replace['errormsg'] = 'Invalid datatype in P2P. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ and @{p2}@ at @{filename}@:@{line:MBIERROR2}@ have MPI_DATATYPE_NULL as a type'
+ replace['change_arg'] = 'type = MPI_DATATYPE_NULL; /* MBIERROR3 */'
+ make_file(template, f'InvalidParam_DatatypeNull_{p1}_{p2}_nok.c', replace)
+
+ # Generate code with an invalid datatype
+ replace = patterns
+ replace['shortdesc'] = 'Use of invalid datatype in point-to-point communication'
+ replace['longdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid datatype'
+ replace['outcome'] = 'ERROR: InvalidDatatype'
+ replace['errormsg'] = 'Invalid datatype in P2P. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ and @{p2}@ at @{filename}@:@{line:MBIERROR2}@ have an invalid datatype'
+ replace['change_arg'] = 'MPI_Type_contiguous (2, MPI_INT, &type); MPI_Type_commit(&type);MPI_Type_free(&type); /* MBIERROR3 */'
+ make_file(template, f'InvalidParam_Datatype_{p1}_{p2}_nok.c', replace)
+
+#################################
+# Generate code with tag mismatch
+#################################
+
+for p1 in allsend:
+ for p2 in allrecv:
+ patterns = {}
+ patterns = {'p1': p1, 'p2': p2}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if p1 in send + ssend + bsend or p2 in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if p1 in isend or p2 in irecv else 'Lacking'
+ patterns['persfeature'] = 'Yes' if p1 in psend or p2 in precv else 'Lacking'
+ patterns['p1'] = p1
+ patterns['p2'] = p2
+ patterns['init1'] = init[p1]("1")
+ patterns['init2'] = init[p2]("2")
+ patterns['start1'] = start[p1]("1")
+ patterns['start2'] = start[p2]("2")
+ patterns['fini1'] = fini[p1]("1")
+ patterns['fini2'] = fini[p2]("2")
+ patterns['operation1'] = operation[p1]("1") #send
+ patterns['operation2'] = operation[p2]("2") #recv
+ patterns['free1'] = free[p1]("1")
+ patterns['free2'] = free[p2]("2")
+ patterns['change_arg'] = ""
+
+ # Generate the incorrect tag matching
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{p1}@ and @{p2}@ have a tag mismatch'
+ replace['longdesc'] = 'Point to point @{p1}@ and @{p2}@ have a tag mismatch.'
+ replace['outcome'] = 'ERROR: TagMatching'
+ replace['errormsg'] = 'P2P tag mismatch. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ and @{p2}@ at @{filename}@:@{line:MBIERROR2}@ use different tag.'
+ replace['change_arg'] = 'stag=0; rtag=1;/* MBIERROR */'
+ make_file(template, f'ParamMatching_Tag_{p1}_{p2}_nok.c', replace)
+
+ # Generate the code with an invalid tag
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid tag'
+ replace['longdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid tag.'
+ replace['outcome'] = 'ERROR: InvalidTag'
+ replace['errormsg'] = 'Invalid Tag. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ and @{p2}@ at @{filename}@:@{line:MBIERROR2}@ use an invalid tag.'
+ replace['change_arg'] = 'stag=-1; rtag=-2;/* MBIERROR */'
+ make_file(template, f'InvalidParam_Tag_{p1}_{p2}_nok.c', replace)
+
+ # Generate a correct code using MPI_ANY_TAG
+ replace = patterns
+ replace['shortdesc'] = 'Correct code'
+ replace['longdesc'] = 'Correct code'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = 'OK'
+ replace['change_arg'] = 'rtag=MPI_ANY_TAG;'
+ make_file(template, f'ParamMatching_Tag_{p1}_{p2}_ok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: @{origin}@
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: @{persfeature}@
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Yes
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int src=0, dest=1;
+ int stag = 0, rtag = 0;
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Datatype type = MPI_INT;
+ MPI_Comm newcom;
+ MPI_Comm_split(MPI_COMM_WORLD, 0, nprocs - rank, &newcom);
+ @{change_com}@
+ @{change_srcdest}@
+
+ @{init1}@
+ @{init2}@
+ if (rank == 0) {
+ @{operation1}@ /* MBIERROR1 */
+ @{start1}@
+ @{fini1}@
+ }else if (rank == 1) {
+ @{operation2}@ /* MBIERROR2 */
+ @{start2}@
+ @{fini2}@
+ }
+ @{free1}@
+ @{free2}@
+
+ if(newcom != MPI_COMM_NULL && newcom != MPI_COMM_WORLD)
+ MPI_Comm_free(&newcom);
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for p1 in send + isend + psend:
+ for p2 in recv + irecv + precv:
+ patterns = {}
+ patterns = {'p1': p1, 'p2': p2}
+ patterns['origin'] = "MBI"
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if p1 in send or p2 in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if p1 in isend or p2 in irecv else 'Lacking'
+ patterns['persfeature'] = 'Yes' if p1 in psend or p2 in precv else 'Lacking'
+ patterns['p1'] = p1
+ patterns['p2'] = p2
+ patterns['init1'] = init[p1]("1")
+ patterns['init2'] = init[p2]("2")
+ patterns['start1'] = start[p1]("1")
+ patterns['start2'] = start[p2]("2")
+ patterns['fini1'] = fini[p1]("1")
+ patterns['fini2'] = fini[p2]("2")
+ patterns['operation1'] = operation[p1]("1") #send
+ patterns['operation2'] = operation[p2]("2") #recv
+ patterns['free1'] = free[p1]("1")
+ patterns['free2'] = free[p2]("2")
+ patterns['change_srcdest'] = ""
+
+ # Generate the incorrect matching
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{p1}@ and @{p2}@ have a communicator mismatch'
+ replace['longdesc'] = 'Process 1 uses newcom as the communicator while process 0 uses MPI_COMM_WORLD.'
+ replace['outcome'] = 'ERROR: CommunicatorMatching'
+ replace['errormsg'] = 'P2P Communicator mismatch. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ and @{p2}@ at @{filename}@:@{line:MBIERROR2}@ have newcom or MPI_COMM_WORLD as a communicator.'
+ replace['change_com'] = 'if (rank==0)\n newcom = MPI_COMM_WORLD; /* MBIERROR */'
+ make_file(template, f'ParamMatching_Com_{p1}_{p2}_nok.c', replace)
+
+ # Generate the code with an invalid communicator
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid communicator'
+ replace['longdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid communicator.'
+ replace['outcome'] = 'ERROR: InvalidCommunicator'
+ replace['errormsg'] = 'Invalid Communicator. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ and @{p2}@ at @{filename}@:@{line:MBIERROR2}@ use a communicator that is freed line @{line:MBIERROR}@.'
+ replace['change_com'] = 'MPI_Comm_free(&newcom); /* MBIERROR */'
+ make_file(template, f'InvalidParam_Com_{p1}_{p2}_nok.c', replace)
+
+ # Generate the code with an invalid communicator ==> TO CHECK
+ #replace = patterns
+ #replace['shortdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid communicator'
+ # replace['longdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid communicator.'
+ # replace['outcome'] = 'ERROR: InvalidCommunicator'
+ # replace['errormsg'] = 'Invalid Communicator. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ and @{p2}@ at @{filename}@:@{line:MBIERROR2}@ use different communicators'
+ # replace['origin'] = "MPI-Corrbench"
+ # replace['change_com'] = ""
+ # make_file(template, f'InvalidParam_Com_{p1}_{p2}_nok.c', replace)
+
+ # Generate the code with an invalid dest
+ replace = patterns
+ replace['origin'] = "MBI"
+ replace['shortdesc'] = 'Point to point @{p1}@ has an invalid argument'
+ replace['longdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid communicator.'
+ replace['outcome'] = 'ERROR: InvalidSrcDest'
+ replace['errormsg'] = 'InvalidSrcDest. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ performs a send with a dest not in communicator (dest is changed line @{line:MBIERROR}@).'
+ replace['change_com'] = ""
+ replace['change_srcdest'] = 'dest=4; /* MBIERROR */'
+ make_file(template, f'InvalidParam_Dest_{p1}_{p2}_nok.c', replace)
+
+ # Generate the code with an invalid src
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{p2}@ has an invalid argument'
+ replace['longdesc'] = 'Point to point @{p1}@ and @{p2}@ have an invalid communicator.'
+ replace['outcome'] = 'ERROR: InvalidSrcDest'
+ replace['errormsg'] = 'InvalidSrcDest. @{p2}@ at @{filename}@:@{line:MBIERROR2}@ performs a recv with a negative integer as source (src is changed line @{line:MBIERROR}@).'
+ replace['change_srcdest'] = 'src=-1; /* MBIERROR */'
+ make_file(template, f'InvalidParam_Src_{p1}_{p2}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: @{origin}@
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: @{persfeature}@
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Yes
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int src=0, dest=1;
+ int stag = 0, rtag = 0;
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ MPI_Datatype type = MPI_INT;
+ MPI_Comm newcom = MPI_COMM_WORLD;
+
+ @{init1}@
+ @{init2}@
+ if (rank == 0) {
+ @{change_com1}@
+ @{operation1}@ /* MBIERROR1 */
+ @{start1}@
+ @{fini1}@
+ }else if (rank == 1) {
+ @{change_com2}@
+ @{operation2}@ /* MBIERROR2 */
+ @{start2}@
+ @{fini2}@
+ }
+ @{free1}@
+ @{free2}@
+
+ if(newcom != MPI_COMM_NULL && newcom != MPI_COMM_WORLD)
+ MPI_Comm_free(&newcom);
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for p1 in send + isend + psend:
+ for p2 in recv + irecv + precv:
+ patterns = {}
+ patterns = {'p1': p1, 'p2': p2}
+ patterns['origin'] = "MBI"
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if p1 in send or p2 in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if p1 in isend or p2 in irecv else 'Lacking'
+ patterns['persfeature'] = 'Yes' if p1 in psend or p2 in precv else 'Lacking'
+ patterns['p1'] = p1
+ patterns['p2'] = p2
+ patterns['init1'] = init[p1]("1")
+ patterns['init2'] = init[p2]("2")
+ patterns['start1'] = start[p1]("1")
+ patterns['start2'] = start[p2]("2")
+ patterns['fini1'] = fini[p1]("1")
+ patterns['fini2'] = fini[p2]("2")
+ patterns['operation1'] = operation[p1]("1") #send
+ patterns['operation2'] = operation[p2]("2") #recv
+ patterns['free1'] = free[p1]("1")
+ patterns['free2'] = free[p2]("2")
+ patterns['change_com1'] = ""
+ patterns['change_com2'] = ""
+
+ replace = patterns
+ replace['origin'] = "inspired from MPI-Corrbench"
+ replace['shortdesc'] = 'Point to point @{p2}@ has an invalid communicator'
+ replace['longdesc'] = 'MPI_COMM_NULL used in point to point @{p2}@'
+ replace['outcome'] = 'ERROR: InvalidCommunicator'
+ replace['errormsg'] = 'Invalid Communicator. @{p2}@ at @{filename}@:@{line:MBIERROR2}@ uses a null communicator.'
+ replace['change_com2'] = 'newcom = MPI_COMM_NULL;'
+ make_file(template, f'InvalidParam_ComNull_{p2}_{p1}nok.c', replace)
+
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{p2}@ has an invalid communicator'
+ replace['longdesc'] = 'MPI_COMM_NULL used in point to point @{p2}@'
+ replace['outcome'] = 'ERROR: InvalidCommunicator'
+ replace['errormsg'] = 'Invalid Communicator. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ uses a null communicator.'
+ replace['change_com1'] = 'newcom = MPI_COMM_NULL;'
+ replace['change_com2'] = ""
+ make_file(template, f'InvalidParam_ComNull_{p1}_{p2}nok.c', replace)
+
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: @{persfeature}@
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int dest=0, src=0;
+ int stag = 0, rtag = 0;
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+
+ @{init1}@
+ @{init2}@
+ if (rank == 0) {
+ dest = 1; src = 1;
+ @{operation1}@
+ @{start1}@
+ @{write1}@ /* MBIERROR1 */
+ @{fini1}@
+ @{free1}@
+ }else if (rank == 1){
+ dest = 0; src = 0;
+ @{operation2}@
+ @{start2}@
+ @{write2}@ /* MBIERROR2 */
+ @{fini2}@
+ @{free2}@
+ }
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for s in send + isend + psend:
+ for r in irecv + precv + recv:
+ patterns = {}
+ patterns = {'s': s, 'r': r}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if s in send else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if r in irecv else 'Lacking'
+ patterns['persfeature'] = 'Yes' if r in precv else 'Lacking'
+ patterns['s'] = s
+ patterns['r'] = r
+ patterns['init1'] = init[s]("1")
+ patterns['init2'] = init[r]("2")
+ patterns['fini1'] = fini[s]("1")
+ patterns['fini2'] = fini[r]("2")
+ patterns['start1'] = start[s]("1")
+ patterns['start2'] = start[r]("2")
+ patterns['operation1'] = operation[s]("1")
+ patterns['operation2'] = operation[r]("2")
+ patterns['write1'] = write[s]("1")
+ patterns['write2'] = write[r]("2")
+ patterns['free1'] = free[s]("1")
+ patterns['free2'] = free[r]("2")
+
+ # Generate a message race
+ if s in send and r in irecv + precv:
+ replace = patterns
+ replace['shortdesc'] = ' Local Concurrency with a P2P'
+ replace['longdesc'] = f'The message buffer in {r} is modified before the call has been completed.'
+ replace['outcome'] = 'ERROR: LocalConcurrency'
+ replace['errormsg'] = 'Local Concurrency with a P2P. The receive buffer in @{r}@ is modified at @{filename}@:@{line:MBIERROR2}@ whereas there is no guarantee the message has been received.'
+ make_file(template, f'LocalConcurrency_{r}_{s}_nok.c', replace)
+ if s in isend + psend and r in recv:
+ replace = patterns
+ replace['shortdesc'] = ' Local Concurrency with a P2P'
+ replace['longdesc'] = f'The message buffer in {s} is modified before the call has been completed.'
+ replace['outcome'] = 'ERROR: LocalConcurrency'
+ replace['errormsg'] = 'Local Concurrency with a P2P. The send buffer in @{s}@ is modified at @{filename}@:@{line:MBIERROR1}@ whereas there is no guarantee the message has been sent.'
+ make_file(template, f'LocalConcurrency_{r}_{s}_nok.c', replace)
+ if s in isend + psend and r in irecv + precv:
+ replace = patterns
+ replace['shortdesc'] = ' Local Concurrency with a P2P'
+ replace['longdesc'] = f'The message buffer in {s} and {r} are modified before the calls have completed.'
+ replace['outcome'] = 'ERROR: LocalConcurrency'
+ replace['errormsg'] = 'Local Concurrency with a P2P. The message buffers in @{s}@ and @{r}@ are modified at @{filename}@:@{line:MBIERROR1}@ and @{filename}@:@{line:MBIERROR2}@ whereas there is no guarantee the calls have been completed.'
+ make_file(template, f'LocalConcurrency_{r}_{s}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 4 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int src=MPI_ANY_SOURCE, dest=0;
+ int stag = 42, rtag = MPI_ANY_TAG;
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ int send_buffer=rank;
+
+ MPI_Datatype type = MPI_INT;
+ MPI_Comm newcom = MPI_COMM_WORLD;
+
+ @{init1}@
+ @{init2}@
+
+ if (rank == 0) {
+ for (int i = 0; i < nprocs - 1; i++) {
+ @{operation1}@ /* MBIERROR */
+ @{fini1}@
+ }
+ if (@{cond}@ != 3) {
+ printf("MBI_MSG_RACE: The last received message is not 3 but %d!\\n", buf1);
+ fflush(stdout);
+ abort();
+ }
+ }else{
+ @{operation2}@
+ @{fini2}@
+ }
+
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for s in send + isend:
+ for r in recv + irecv:
+ patterns = {}
+ patterns = {'s': s, 'r': r}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if s in send or r in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if s in isend or r in irecv else 'Lacking'
+ patterns['s'] = s
+ patterns['r'] = r
+ patterns['cond'] = 'buf1'
+ patterns['init2'] = init[s]("2")
+ patterns['init1'] = init[r]("1")
+ patterns['fini2'] = fini[s]("2")
+ patterns['fini1'] = fini[r]("1")
+ patterns['operation2'] = operation[s]("2")
+ patterns['operation1'] = operation[r]("1")
+
+ # Generate the incorrect matching
+ replace = patterns
+ replace['shortdesc'] = 'The message ordering is non-deterministic.'
+ replace['longdesc'] = f'The code assumes a fixed order in the reception of messages while the message ordering is non-deterministic.'
+ replace['outcome'] = 'ERROR: MessageRace'
+ replace['errormsg'] = 'P2P message race which can cause a deadlock. @{r}@ at @{filename}@:@{line:MBIERROR}@ is called with ANY_SRC.'
+ make_file(template, f'MessageRace_{r}_{s}_nok.c', replace)
+
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: @{persfeature}0@
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define buff_size 1
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ int its_raining = 0;
+ int src=0, dest=1;
+ int stag=0, rtag=0;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+
+ @{init1}@
+ @{init2}@
+ if (rank == 0) {
+ @{operation1}@ /* MBIERROR1 */
+ @{fini1}@
+ }else if (@{change_cond}@){
+ @{operation2}@ /* MBIERROR2 */
+ @{fini2}@
+ }
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for p in send + ssend + bsend + recv + irecv + isend:
+ patterns = {}
+ patterns = {'p': p}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if p in send + bsend + ssend + recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if p in isend + irecv else 'Lacking'
+ patterns['persfeature'] = 'Lacking'
+ #patterns['persfeature'] = 'Yes' if p in psend + precv else 'Lacking'
+ patterns['p'] = p
+ patterns['init1'] = init[p]("1")
+ patterns['init2'] = '' #init[p2]("2")
+ patterns['fini1'] = fini[p]("1")
+ patterns['fini2'] = '' #fini[p2]("2")
+ patterns['operation1'] = operation[p]("1")
+ patterns['operation2'] = '' #operation[p2]("2")
+ patterns['change_cond'] = 'rank == 1'
+
+ # Generate the incorrect matching with one call
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{p}@ is not matched'
+ replace['longdesc'] = 'Process 0 calls @{p}@ and is not matched'
+ replace['outcome'] = 'ERROR: CallMatching'
+ replace['errormsg'] = 'P2P mistmatch. @{p}@ at @{filename}@:@{line:MBIERROR1}@ is not matched.'
+ make_file(template, f'CallOrdering_{p}_nok.c', replace)
+
+ # Generate the incorrect matching with two calls
+ replace = patterns
+ replace['shortdesc'] = 'Both point to point @{p}@ are not matched'
+ replace['longdesc'] = 'Processes 0 and 1 both call @{p}@ which are not matched'
+ replace['outcome'] = 'ERROR: CallMatching'
+ replace['errormsg'] = 'P2P mismatch. @{p}@ at @{filename}@:@{line:MBIERROR1}@ and @{p}@ at @{filename}@:@{line:MBIERROR2}@ are not matched.'
+ replace['operation2'] = operation[p]("1")
+ replace['fini2'] = fini[p]("1")
+ make_file(template, f'CallOrdering_{p}_{p}_nok.c', replace)
+
+for s in send + isend + ssend + bsend:
+ for r in recv + irecv:
+ patterns = {}
+ patterns = {'s': s, 'r': r}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if s in send or r in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if s in isend or r in irecv else 'Lacking'
+ patterns['s'] = s
+ patterns['r'] = r
+ patterns['init1'] = init[s]("1")
+ patterns['init2'] = init[r]("2")
+ patterns['fini1'] = fini[s]("1")
+ patterns['fini2'] = fini[r]("2")
+ patterns['operation1'] = operation[s]("1")
+ patterns['operation2'] = operation[r]("2")
+ patterns['change_cond'] = '(rank == 1) && (its_raining)'
+
+ # Generate the incorrect matching because of the conditional
+ replace = patterns
+ replace['shortdesc'] = 'Point to point @{r}@ is never called.'
+ replace['longdesc'] = 'Point to point @{r}@ is never executed. Process 1 calls MPI_Finalize and causes a deadlock.'
+ replace['outcome'] = 'ERROR: CallMatching'
+ replace['errormsg'] = 'P2P mistmatch. @{r}@ at @{filename}@:@{line:MBIERROR2}@ is never called because of the conditional (@{change_cond}@).'
+ replace['operation1'] = operation[s]("1")
+ replace['operation2'] = operation[r]("2")
+ make_file(template, f'CallOrdering_{r}_{s}_nok.c', replace)
+
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: Lacking
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ MPI_Status sta;
+ int src,dest;
+ int stag=0, rtag=0;
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+
+ @{init1a}@
+ @{init1b}@
+ @{init1c}@
+ @{init2a}@
+ @{init2b}@
+ @{init2c}@
+
+ if (rank == 0) {
+ dest=1, src=1;
+ @{operation1a}@ /* MBIERROR1 */
+ @{operation1b}@
+ @{operation1c}@
+ @{fini1a}@
+ @{fini1b}@
+ @{fini1c}@
+ }else if (rank == 1){
+ dest=0, src=0;
+ @{operation2a}@ /* MBIERROR2 */
+ @{operation2b}@
+ @{operation2c}@
+ @{fini2a}@
+ @{fini2b}@
+ @{fini2c}@
+ }
+ @{free1a}@
+ @{free1b}@
+ @{free1c}@
+ @{free2a}@
+ @{free2b}@
+ @{free2c}@
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for p in probe:
+ for s in send + isend:
+ for r in recv + irecv:
+ patterns = {}
+ patterns = {'p':p, 's': s, 'r': r}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['p2pfeature'] = 'Yes' if s in send or r in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if s in isend or r in irecv else 'Lacking'
+ patterns['s'] = s
+ patterns['r'] = r
+ patterns['p'] = p
+ patterns['init1a'] = init[p]("1")
+ patterns['init1b'] = init[s]("1")
+ patterns['init1c'] = init[r]("2")
+ patterns['init2a'] = init[p]("1")
+ patterns['init2b'] = init[r]("3")
+ patterns['init2c'] = init[s]("4")
+ patterns['fini1a'] = fini[p]("1")
+ patterns['fini1b'] = fini[s]("1")
+ patterns['fini1c'] = fini[r]("2")
+ patterns['fini2a'] = fini[p]("1")
+ patterns['fini2b'] = fini[r]("3")
+ patterns['fini2c'] = fini[s]("4")
+ patterns['free1a'] = free[p]("1")
+ patterns['free1b'] = free[s]("1")
+ patterns['free1c'] = free[r]("2")
+ patterns['free2a'] = free[p]("1")
+ patterns['free2b'] = free[r]("3")
+ patterns['free2c'] = free[s]("4")
+ patterns['operation1a'] = operation[p]("1")
+ patterns['operation1b'] = operation[s]("1")
+ patterns['operation1c'] = operation[r]("2")
+ patterns['operation2a'] = operation[p]("1")
+ patterns['operation2b'] = operation[r]("3")
+ patterns['operation2c'] = operation[s]("4")
+
+ # Generate the incorrect matching
+ replace = patterns
+ replace['shortdesc'] = 'MPI_Probe is called before MPI_Recv.'
+ replace['longdesc'] = 'MPI_Probe is a blocking call that returns only after a matching message has been found. By calling MPI_Probe before MPI_Recv, a deadlock is created.'
+ replace['outcome'] = 'ERROR: CallMatching'
+ replace['errormsg'] = 'P2P mistmatch. @{p}@ at @{filename}@:@{line:MBIERROR1}@ and @{filename}@:@{line:MBIERROR2}@ are called before @{r}@.'
+ make_file(template, f'CallOrdering_{p}_{r}_{s}_nok.c', replace)
+
+ # Generate a correct matching
+ replace = patterns
+ replace['shortdesc'] = 'Correct use of MPI_Probe.'
+ replace['longdesc'] = 'Correct use of MPI_Probe.'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = 'OK'
+ replace['operation1a'] = operation[s]("1")
+ replace['operation1b'] = operation[p]("1")
+ make_file(template, f'CallOrdering_{p}_{r}_{s}_ok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: @{origin}@
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: @{rmafeature}@
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 10
+
+int main(int argc, char **argv) {
+ int rank, numProcs;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ int *winbuf = malloc(N * sizeof(int));
+
+ MPI_Win win;
+ MPI_Win_create(&winbuf, N * sizeof(int), 1, MPI_INFO_NULL, MPI_COMM_WORLD, &win);
+
+ MPI_Datatype type = MPI_INT;
+ int target = (rank + 1) % numProcs;
+
+ if(rank == 0){
+ @{epoch}@
+ @{change_arg}@
+ @{init}@
+ @{operation}@ /* MBIERROR2 */
+
+ @{finEpoch}@
+ } else {
+ @{epoch}@
+
+ @{finEpoch}@
+ }
+
+ MPI_Win_free(&win);
+
+ free(winbuf);
+
+ MPI_Finalize();
+ return 0;
+}
+"""
+
+
+for e in epoch:
+ for p in rma:
+ patterns = {}
+ patterns = {'e': e, 'p': p}
+ patterns['origin'] = "MBI"
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p'] = p
+ patterns['e'] = e
+ patterns['epoch'] = epoch[e]("1")
+ patterns['finEpoch'] = finEpoch[e]("1")
+ patterns['init'] = init[p]("1")
+ patterns['operation'] = operation[p]("1")
+ patterns['change_arg'] = ""
+
+ # Generate a code with a null type
+ replace = patterns
+ replace['shortdesc'] = 'Invalid argument in one-sided operation.'
+ replace['longdesc'] = 'A one-sided operation has MPI_DATATYPE_NULL as a type.'
+ replace['outcome'] = 'ERROR: InvalidDatatype'
+ replace['change_arg'] = 'type = MPI_DATATYPE_NULL;'
+ replace['errormsg'] = '@{p}@ at @{filename}@:@{line:MBIERROR}@ has MPI_DATATYPE_NULL as a type'
+ make_file(template, f'InvalidParam_BufferNullCond_{e}_{p}_nok.c', replace)
+
+ # Generate a code with an invalid type
+ replace = patterns
+ replace['shortdesc'] = 'Invalid argument in one-sided operation.'
+ replace['longdesc'] = 'Use of an invalid datatype in one-sided operation.'
+ replace['outcome'] = 'ERROR: InvalidDatatype'
+ replace['change_arg'] = 'MPI_Type_contiguous (2, MPI_INT, &type); MPI_Type_commit(&type);MPI_Type_free(&type); /* MBIERROR2 */'
+ replace['errormsg'] = 'Invalid Datatype in @{p}@ at @{filename}@:@{line:MBIERROR}@'
+ make_file(template, f'InvalidParam_DatatypeCond_{e}_{p}_nok.c', replace)
+
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: @{origin}@
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: @{rmafeature}@
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 10
+
+int main(int argc, char **argv) {
+ int nprocs = -1 , rank = -1;
+ MPI_Win win;
+ int *winbuf = @{malloc}@ // Window buffer
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Datatype type = MPI_INT;
+ int target = (rank + 1) % nprocs;
+
+ MPI_Win_create(winbuf, N * sizeof(int), 1, MPI_INFO_NULL, MPI_COMM_WORLD, &win);
+
+
+ @{epoch}@
+
+ @{init}@
+ @{change_arg}@
+ @{operation}@ /* MBIERROR */
+
+ @{finEpoch}@
+
+ MPI_Win_free(&win);
+ free(winbuf);
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for e in epoch:
+ for p in rma:
+ patterns = {}
+ patterns = {'e': e, 'p': p}
+ patterns['origin'] = "MBI"
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p'] = p
+ patterns['e'] = e
+ patterns['epoch'] = epoch[e]("1")
+ patterns['finEpoch'] = finEpoch[e]("1")
+ patterns['init'] = init[p]("1")
+ patterns['operation'] = operation[p]("1")
+ patterns['change_arg'] = ""
+ patterns['malloc'] = "malloc(N * sizeof(int));"
+
+ # Generate a code with a null type
+ replace = patterns
+ replace['shortdesc'] = 'Invalid argument in one-sided operation.'
+ replace['longdesc'] = 'A one-sided operation has MPI_DATATYPE_NULL as a type.'
+ replace['outcome'] = 'ERROR: InvalidDatatype'
+ replace['change_arg'] = 'type = MPI_DATATYPE_NULL;'
+ replace['errormsg'] = '@{p}@ at @{filename}@:@{line:MBIERROR}@ has MPI_DATATYPE_NULL as a type'
+ make_file(template, f'InvalidParam_DatatypeNull_{e}_{p}_nok.c', replace)
+
+ # Generate a code with a null buffer (move to RMAWinBufferGenerator)
+ # replace = patterns
+ # replace['origin'] = 'MPI-Corrbench'
+ # replace['shortdesc'] = 'nullptr is invalid in one-sided operation.'
+ # replace['longdesc'] = 'A one-sided operation has an invalid buffer.'
+ # replace['outcome'] = 'ERROR: InvalidBuffer'
+ # replace['init'] = 'int * localbuf1 = malloc(sizeof(int));'
+ # replace['change_arg'] = 'localbuf1 = NULL;'
+ # replace['operation'] = operation[p]("1").replace('&localbuf1', 'localbuf1')
+ # replace['errormsg'] = '@{p}@ at @{filename}@:@{line:MBIERROR}@ has an invalid buffer'
+ # make_file(template, f'InvalidParam_BufferNull_{e}_{p}_nok.c', replace)
+
+ # Generate a code with an invalid type
+ replace = patterns
+ replace['origin'] = 'MBI'
+ replace['shortdesc'] = 'Invalid argument in one-sided operation.'
+ replace['longdesc'] = 'Use of an invalid datatype in one-sided operation.'
+ replace['outcome'] = 'ERROR: InvalidDatatype'
+ replace['change_arg'] = 'MPI_Type_contiguous (2, MPI_INT, &type); MPI_Type_commit(&type);MPI_Type_free(&type); /* MBIERROR2 */'
+ replace['errormsg'] = 'Invalid Datatype in @{p}@ at @{filename}@:@{line:MBIERROR}@'
+ make_file(template, f'InvalidParam_Datatype_{e}_{p}_nok.c', replace)
+
+ # Generate a code with invalid buffer
+ replace = patterns
+ patterns['origin'] = "MPI-Corrbench"
+ replace['shortdesc'] = 'Invalid invalid buffer (buffer must be allocated)'
+ replace['longdesc'] = 'Use of an invalid buffer in MPI_Win_create.'
+ replace['outcome'] = 'ERROR: InvalidBuffer'
+ patterns['malloc'] = "NULL; /* MBIERROR2 */"
+ patterns['operation'] = ""
+ replace['change_arg'] = ""
+ replace['errormsg'] = 'Invalid buffer in Win_create at @{filename}@:@{line:MBIERROR2}@'
+ make_file(template, f'InvalidParam_InvalidBufferWinCreate_{e}_{p}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 2, requires MPI 3 implementation (for lock_all/unlock_all epochs)
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: @{rmafeature}@
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 1
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ MPI_Win win;
+ int winbuf[100] = {0};
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Datatype type = MPI_INT;
+ int target = 1;
+
+ MPI_Win_create(&winbuf, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win);
+
+ winbuf[0] = 12345;
+ @{init1}@
+
+ @{epoch}@
+
+ if (rank == 0) {
+ @{operation1}@ /* MBIERROR1 */
+ @{operation2}@ /* MBIERROR2 */
+ }
+
+ @{finEpoch}@
+
+ MPI_Win_free(&win);
+
+ MPI_Finalize();
+ return 0;
+}
+"""
+
+
+for e in epoch:
+ for p1 in get:
+ for p2 in put + store + load + get + loadstore:
+ patterns = {}
+ patterns = {'e': e, 'p1': p1, 'p2': p2}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p1'] = p1
+ patterns['p2'] = p2
+ patterns['e'] = e
+ patterns['epoch'] = epoch[e]("1")
+ patterns['finEpoch'] = finEpoch[e]("1")
+ patterns['init1'] = init[p1]("1")
+ patterns['operation1'] = operation[p1]("1")
+ patterns['operation2'] = operation[p2]("1")
+
+ # Generate a data race (Get + Get/load/store/Put)
+ replace = patterns
+ replace['shortdesc'] = 'Local Concurrency error.'
+ replace['longdesc'] = 'Local Concurrency error. @{p2}@ conflicts with @{p1}@'
+ replace['outcome'] = 'ERROR: LocalConcurrency'
+ replace['errormsg'] = 'Local Concurrency error. @{p2}@ at @{filename}@:@{line:MBIERROR2}@ conflicts with @{p1}@ line @{line:MBIERROR1}@'
+ make_file(template, f'LocalConcurrency_lloutwindow_{e}_{p1}_{p2}_nok.c', replace)
+ # Generate a correct code by switching operation1 and operation2
+ if p2 in store + load + loadstore:
+ replace = patterns
+ replace['shortdesc'] = 'Correct code using RMA operations'
+ replace['longdesc'] = 'Correct code using RMA operations'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = 'OK'
+ replace['operation1'] = operation[p2]("1")
+ replace['operation2'] = operation[p1]("1")
+ make_file(template, f'LocalConcurrency_lloutwindow_{e}_{p2}_{p1}_ok.c', replace)
+ # Generate a correct code by removing operation2
+ replace = patterns
+ replace['shortdesc'] = 'Correct code using RMA operations'
+ replace['longdesc'] = 'Correct code using RMA operations'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = 'OK'
+ replace['operation1'] = operation[p1]("1")
+ replace['operation2'] = ''
+ make_file(template, f'LocalConcurrency_{e}_{p1}_ok.c', replace)
+
+
+for e in epoch:
+ for p1 in put:
+ for p2 in store:
+ patterns = {}
+ patterns = {'e': e, 'p1': p1, 'p2': p2}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p1'] = p1
+ patterns['p2'] = p2
+ patterns['e'] = e
+ patterns['epoch'] = epoch[e]("1")
+ patterns['finEpoch'] = finEpoch[e]("1")
+ patterns['init1'] = init[p1]("1")
+ patterns['operation1'] = operation[p1]("1")
+ patterns['operation2'] = operation[p2]("1")
+
+ # Generate a data race (Put + store)
+ replace = patterns
+ replace['shortdesc'] = 'Local Concurrency error.'
+ replace['longdesc'] = 'Local Concurrency error. @{p2}@ conflicts with @{p1}@'
+ replace['outcome'] = 'ERROR: LocalConcurrency'
+ replace['errormsg'] = 'Local Concurrency error. @{p2}@ at @{filename}@:@{line:MBIERROR2}@ conflicts with @{p1}@ line @{line:MBIERROR1}@'
+ make_file(template, f'LocalConcurrency_lloutwindow_{e}_{p1}_{p2}_nok.c', replace)
+ # Generate a correct code by switching operation1 and operation2
+ replace = patterns
+ replace['shortdesc'] = 'Correct code using RMA operations'
+ replace['longdesc'] = 'Correct code using RMA operations'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = 'OK'
+ replace['operation1'] = operation[p2]("1")
+ replace['operation2'] = operation[p1]("1")
+ make_file(template, f'LocalConcurrency_lloutwindow_{e}_{p2}_{p1}_ok.c', replace)
+
+ # Generate a correct code by removing operation2
+ replace = patterns
+ replace['shortdesc'] = 'Correct code using RMA operations'
+ replace['longdesc'] = 'Correct code using RMA operations'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = 'OK'
+ replace['operation1'] = operation[p1]("1")
+ replace['operation2'] = ''
+ make_file(template, f'LocalConcurrency_{e}_{p1}_ok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 2, does not require MPI 3 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: @{p2pfeature}@
+ P2P!nonblocking: @{ip2pfeature}@
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: @{rmafeature}@
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 4 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 1
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ MPI_Win win;
+ int * winbuf = malloc(N * sizeof(int)); // Window buffer
+ int buff_size = 1;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 4)
+ printf("MBI ERROR: This test needs at least 4 processes to produce a bug!\\n");
+
+ MPI_Comm newcom = MPI_COMM_WORLD;
+ MPI_Datatype type = MPI_INT;
+ int stag=0, rtag=0;
+ winbuf[0] = nprocs;
+
+ MPI_Win_create(winbuf, N*sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win);
+
+
+ @{init1}@
+ @{init2}@
+ @{init3}@
+
+ if (rank == 0) {
+ int target=1;
+ MPI_Win_lock(MPI_LOCK_EXCLUSIVE, 1, 0, win);
+ @{operation1}@
+ localbuf1[0] = 12345; /* MBIERROR1 */
+ MPI_Win_unlock(1, win);
+ }else if (rank == 2){
+ int dest=1;
+ @{operation2}@
+ @{fini2}@
+ }else if (rank == 1){
+ int src=2;
+ buf3 = winbuf[0];
+ @{operation3}@
+ winbuf[0] = buf3; /* MBIERROR2 */
+ @{fini3}@
+ }
+
+ MPI_Win_free(&win);
+ free(winbuf);
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for p in put + get:
+ for s in send + isend:
+ for r in recv + irecv:
+ patterns = {}
+ patterns = {'p': p, 's': s, 'r': r}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p2pfeature'] = 'Yes' if s in send or r in recv else 'Lacking'
+ patterns['ip2pfeature'] = 'Yes' if s in isend or r in irecv else 'Lacking'
+ patterns['p'] = p
+ patterns['s'] = s
+ patterns['r'] = r
+ patterns['init1'] = init[p]("1")
+ patterns['init2'] = init[s]("2")
+ patterns['init3'] = init[r]("3")
+ patterns['fini2'] = fini[s]("2")
+ patterns['fini3'] = fini[r]("3")
+ patterns['operation1'] = operation[p]("1") #put or get
+ patterns['operation2'] = operation[s]("2") #send
+ patterns['operation3'] = operation[r]("3") #recv
+
+ replace = patterns
+ replace['shortdesc'] = 'Global Concurrency error.'
+ replace['longdesc'] = 'Global Concurrency error. Concurrent access of variable winbuf by @{p}@ and @{r}@'
+ replace['outcome'] = 'ERROR: GlobalConcurrency'
+ replace['errormsg'] = 'Global Concurrency error. @{p}@ at @{filename}@:@{line:MBIERROR1}@ accesses the window of process 1. Process 1 receives data from process 2 and uses variable winbuf. winbuf in process 1 is then nondeterministic.'
+ make_file(template, f'GlobalConcurrency_{p}_{s}_{r}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 2, requires MPI 3 implementation (for lock_all/unlock_all epochs)
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: @{rmafeature}@
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 1
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ MPI_Win win;
+ int winbuf[100] = {0};
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Datatype type = MPI_INT;
+ int target = 1;
+
+ MPI_Win_create(&winbuf, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win);
+
+ @{init1}@
+
+ @{epoch}@
+
+ if (rank == 0) {
+ @{operation1}@ /* MBIERROR1 */
+ }
+ if(rank == 1){
+ target = 0;
+ @{operation2}@ /* MBIERROR2 */
+ }
+
+ @{finEpoch}@
+
+ MPI_Win_free(&win);
+
+ MPI_Finalize();
+ return 0;
+}
+"""
+
+
+for e in epoch:
+ for p1 in get:
+ for p2 in put + rstore + rload + get :
+ patterns = {}
+ patterns = {'e': e, 'p1': p1, 'p2': p2}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p1'] = p1
+ patterns['p2'] = p2
+ patterns['e'] = e
+ patterns['epoch'] = epoch[e]("1")
+ patterns['finEpoch'] = finEpoch[e]("1")
+ patterns['init1'] = init[p1]("1")
+ patterns['operation1'] = operation[p1]("1")
+ patterns['operation2'] = operation[p2]("1")
+
+ # Generate a data race (Get + Get/load/store/Put)
+ replace = patterns
+ replace['shortdesc'] = 'Global Concurrency error.'
+ replace['longdesc'] = 'Global Concurrency error. @{p2}@ conflicts with @{p1}@'
+ replace['outcome'] = 'ERROR: GlobalConcurrency'
+ replace['errormsg'] = 'Global Concurrency error. @{p2}@ at @{filename}@:@{line:MBIERROR2}@ conflicts with @{p1}@ line @{line:MBIERROR1}@'
+
+ # Replace Put and Get first argument
+ if p2 in put:
+ replace['operation2'] = 'MPI_Put(&winbuf[20], N, MPI_INT, target, 0, N, type, win);'
+ if p2 in get:
+ replace['operation2'] = 'MPI_Get(&winbuf[20], N, MPI_INT, target, 0, N, type, win);'
+
+ make_file(template, f'GlobalConcurrency_rl_{e}_{p1}_{p2}_nok.c', replace)
+
+
+for e in epoch:
+ for p1 in put:
+ for p2 in rstore + rload + put:
+ patterns = {}
+ patterns = {'e': e, 'p1': p1, 'p2': p2}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p1'] = p1
+ patterns['p2'] = p2
+ patterns['e'] = e
+ patterns['epoch'] = epoch[e]("1")
+ patterns['finEpoch'] = finEpoch[e]("1")
+ patterns['init1'] = init[p1]("1")
+ patterns['operation1'] = operation[p1]("1")
+ patterns['operation2'] = operation[p2]("1")
+
+ # Generate a data race (Put + store)
+ replace = patterns
+ replace['shortdesc'] = 'Global Concurrency error.'
+ replace['longdesc'] = 'Global Concurrency error. @{p2}@ conflicts with @{p1}@'
+ replace['outcome'] = 'ERROR: GlobalConcurrency'
+ replace['errormsg'] = 'Global Concurrency error. @{p2}@ at @{filename}@:@{line:MBIERROR2}@ conflicts with @{p1}@ line @{line:MBIERROR1}@'
+
+ # Replace Put first argument
+ if p2 in put:
+ replace['operation2'] = 'MPI_Put(&winbuf[20], N, MPI_INT, target, 0, N, type, win);'
+
+ make_file(template, f'GlobalConcurrency_rl_{e}_{p1}_{p2}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: MBI
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 2, requires MPI 3 implementation (for lock_all/unlock_all epochs)
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: @{rmafeature}@
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 1
+
+int main(int argc, char **argv) {
+ int nprocs = -1;
+ int rank = -1;
+ MPI_Win win;
+ int winbuf[100] = {0};
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (nprocs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Datatype type = MPI_INT;
+ int target = 1;
+
+ MPI_Win_create(&winbuf, 100 * sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win);
+
+ @{init1}@
+
+ @{epoch}@
+
+ if (rank == 0 || rank == 2) {
+ @{operation1}@ /* MBIERROR1 */
+ }
+
+ @{finEpoch}@
+
+ MPI_Win_free(&win);
+
+ MPI_Finalize();
+ return 0;
+}
+"""
+
+
+for e in epoch:
+ for p1 in get + put:
+ patterns = {}
+ patterns = {'e': e, 'p1': p1}
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p1'] = p1
+ patterns['e'] = e
+ patterns['epoch'] = epoch[e]("1")
+ patterns['finEpoch'] = finEpoch[e]("1")
+ patterns['init1'] = init[p1]("1")
+ patterns['operation1'] = operation[p1]("1")
+
+ # Generate a data race (Get + Get/load/store/Put)
+ replace = patterns
+ replace['shortdesc'] = 'Global Concurrency error.'
+ replace['longdesc'] = 'Global Concurrency error. Both processes 0 and 2 access the window in process 1 with @{p1}@'
+ replace['outcome'] = 'ERROR: GlobalConcurrency'
+ replace['errormsg'] = 'Global Concurrency error. @{p1}@ at @{filename}@:@{line:MBIERROR1}@ conflicts in process 1'
+ make_file(template, f'GlobalConcurrency_rr_{e}_{p1}_nok.c', replace)
+
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: @{origin}@
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: @{rmafeature}@
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 20
+
+int main(int argc, char **argv) {
+ int rank, numProcs;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ if (numProcs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ int *winbuf = malloc(N * sizeof(int));
+
+ MPI_Win win;
+ MPI_Win_create(winbuf, N * sizeof(int), 1, MPI_INFO_NULL, MPI_COMM_WORLD, &win);
+
+ MPI_Datatype type = MPI_INT;
+ int target = 1;
+
+ @{epoch}@
+
+ if (rank == 0) {
+ @{epoch2}@
+
+ @{init}@
+ @{operation}@
+
+ @{finEpoch2}@
+ }
+
+ @{finEpoch}@
+
+ MPI_Win_free(&win);
+
+ free(winbuf);
+
+ MPI_Finalize();
+
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+"""
+
+
+for e1 in epoch:
+ for p in rma:
+ patterns = {}
+ patterns = {'e1': e1, 'p': p}
+ patterns['origin'] = "MPI-Corrbench"
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p'] = p
+ patterns['e1'] = e1
+ patterns['epoch'] = epoch[e1]("1")
+ patterns['finEpoch'] = finEpoch[e1]("1")
+ patterns['epoch2'] = ""
+ patterns['finEpoch2'] = ""
+ patterns['init'] = init[p]("1")
+ patterns['operation'] = operation[p]("1")
+
+ # Generate a code correct
+ replace = patterns
+ replace['shortdesc'] = 'Correct code'
+ replace['longdesc'] = 'Correct code'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = 'OK'
+ make_file(template, f'ReqLifecycle_RMA_{e1}_{p}_ok.c', replace)
+
+ # Generate a code with missing open epoch
+ replace = patterns
+ replace['shortdesc'] = f"Request lifecycle, missing open {e1} epoch"
+ replace['longdesc'] = f"Request lifecycle, missing open {e1} epoch"
+ replace['outcome'] = 'ERROR: MissingStart'
+ replace['errormsg'] = '@{e1}@ at @{filename}@:@{line:MBIERROR}@ has missing'
+ replace['epoch'] = f"/* MBIERROR MISSING: {epoch[e1]('1')} */"
+ make_file(template, f'ReqLifecycle_RMA_MissingOpen_{e1}_{p}_nok.c', replace)
+
+ # Generate a code with missing close epoch
+ replace = patterns
+ replace['shortdesc'] = f"Request lifecycle, missing close {e1} epoch"
+ replace['longdesc'] = f"Request lifecycle, missing close {e1} epoch"
+ replace['outcome'] = 'ERROR: MissingWait'
+ replace['errormsg'] = '@{e1}@ at @{filename}@:@{line:MBIERROR}@ has missing'
+ replace['epoch'] = epoch[e1]("1")
+ replace['finEpoch'] = f"/* MBIERROR MISSING: {finEpoch[e1]('1')} */"
+ make_file(template, f'ReqLifecycle_RMA_MissingClose_{e1}_{p}_nok.c', replace)
+
+for e1 in epoch:
+ for e2 in epoch:
+ for p in rma:
+ patterns = {}
+ patterns = {'e1': e1, 'e2': e2, 'p': p}
+ patterns['origin'] = "MPI-Corrbench"
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+ patterns['p'] = p
+ patterns['e1'] = e1
+ patterns['e2'] = e2
+ patterns['epoch'] = epoch[e1]("1")
+ patterns['finEpoch'] = finEpoch[e1]("1")
+ patterns['epoch2'] = epoch[e2]("1") + " /* MBIERROR */"
+ patterns['finEpoch2'] = finEpoch[e2]("1") + " /* MBIERROR */"
+ patterns['init'] = init[p]("1")
+ patterns['operation'] = operation[p]("1")
+
+ # Generate a code with epoch into an epoch
+ replace = patterns
+ replace['shortdesc'] = f"Request lifecycle, {e2} epoch into {e1} epoch"
+ replace['longdesc'] = f"Request lifecycle, {e2} epoch into {e1} epoch"
+ replace['outcome'] = 'ERROR: MissingWait' #FIXME: New type of error
+ replace['errormsg'] = '@{e2}@ at @{filename}@:@{line:MBIERROR}@ has in an other epoch'
+ make_file(template, f'ReqLifecycle_RMA_TwoEpoch_{e1}_{e2}_{p}_nok.c', replace)
--- /dev/null
+#! /usr/bin/python3
+import os
+import sys
+from generator_utils import *
+
+template = """// @{generatedby}@
+/* ///////////////////////// The MPI Bugs Initiative ////////////////////////
+
+ Origin: @{origin}@
+
+ Description: @{shortdesc}@
+ @{longdesc}@
+
+
+BEGIN_MPI_FEATURES
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: Lacking
+ RMA: @{rmafeature}@
+END_MPI_FEATURES
+
+BEGIN_MBI_TESTS
+ $ mpirun -np 2 ${EXE}
+ | @{outcome}@
+ | @{errormsg}@
+END_MBI_TESTS
+////////////////////// End of MBI headers /////////////////// */
+
+#include <mpi.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 10
+
+int * buffer;
+
+void get_win(MPI_Win *win) {
+ @{bufferalloc}@
+
+ MPI_Win_create(@{buffer}@, N * sizeof(int), 1, MPI_INFO_NULL, MPI_COMM_WORLD, win);
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ int rank, numProcs;
+
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ printf("Hello from rank %d \\n", rank);
+
+ if (numProcs < 2)
+ printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
+
+ MPI_Win win;
+
+ get_win(&win);
+
+ MPI_Win_fence(0, win);
+
+ if (rank == 0) {
+ int localbuf[N] = {12345};
+ MPI_Put(&localbuf, N, MPI_INT, 1, 0, N, MPI_INT, win);
+ }
+
+ MPI_Win_fence(0, win);
+
+ MPI_Win_free(&win);
+
+ @{bufferfree}@
+
+ MPI_Finalize();
+ printf("Rank %d finished normally\\n", rank);
+ return 0;
+}
+
+"""
+
+
+for b in ['missing', 'null', 'malloc', 'bufferSize']:
+ patterns = {}
+ patterns = {'b': b}
+ patterns['origin'] = "MPI-CorrBench"
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['rmafeature'] = 'Yes'
+
+ replace = patterns
+ replace['shortdesc'] = 'Invalid buffer in window creation.'
+ replace['longdesc'] = 'Invalid buffer in window creation.'
+ replace['outcome'] = 'ERROR: InvalidBuffer'
+ replace['errormsg'] = '@{b}@ at @{filename}@:@{line:MBIERROR}@ has an invalid buffer'
+ replace['bufferfree'] = ''
+
+ ok = 'nok'
+ replace['buffer'] = 'buffer'
+
+ if b == 'missing':
+ replace['bufferalloc'] = '/* MBIERROR1 */'
+ replace['longdesc'] = 'Uninitialized buffer in window creation.'
+ elif b == 'null':
+ replace['bufferalloc'] = 'buffer = NULL; /* MBIERROR1 */'
+ replace['longdesc'] = 'Use NULL buffer in window creation.'
+ elif b == 'bufferSize':
+ replace['bufferalloc'] = 'buffer = malloc((N/2) * sizeof(int)); /* MBIERROR1 */'
+ replace['bufferfree'] = 'free(buffer);'
+ replace['longdesc'] = 'Unmatched size of buffer in window creation.'
+ else:
+ replace['bufferalloc'] = 'buffer = malloc(N * sizeof(int));'
+ replace['bufferfree'] = 'free(buffer);'
+ replace['longdesc'] = 'Correct initialized buffer in window creation.'
+ replace['outcome'] = 'OK'
+ replace['errormsg'] = ''
+ ok = 'ok'
+
+ make_file(template, f'InvalidParam_WinBuffer_{b}_{ok}.c', replace)
# Copyright 2021-2022. The MBI project. All rights reserved.
# This program is free software; you can redistribute it and/or modify it under the terms of the license (GNU GPL).
+import os
import sys
from generator_utils import *
Description: @{shortdesc}@
@{longdesc}@
- Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
+ Version of MPI: Conforms to MPI 1.1, does not require MPI 2 implementation
BEGIN_MPI_FEATURES
- P2P!basic: Lacking
- P2P!nonblocking: Lacking
- P2P!persistent: Lacking
- COLL!basic: Lacking
- COLL!nonblocking: Lacking
- COLL!persistent: Lacking
- COLL!tools: @{toolfeature}@
- RMA: Lacking
+ P2P!basic: Lacking
+ P2P!nonblocking: Lacking
+ P2P!persistent: Lacking
+ COLL!basic: Lacking
+ COLL!nonblocking: Lacking
+ COLL!persistent: Lacking
+ COLL!tools: @{toolfeature}@
+ RMA: Lacking
END_MPI_FEATURES
BEGIN_MBI_TESTS
#define PARAM_PER_ITERATION 3
#define PARAM_LOST_PER_ITERATION 1
-void myOp(int *invec, int *inoutvec, int *len, MPI_Datatype *dtype) {
+static void myOp(int *invec, int *inoutvec, int *len, MPI_Datatype *dtype) {
for (int i = 0; i < *len; i++)
inoutvec[i] += invec[i];
}
int main(int argc, char **argv) {
int nprocs = -1;
int rank = -1;
- int i=1, j=1, size=1;
- int color =0;
+ int i=1, j=1, size=1;
+ int color =0;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
if (nprocs < 2)
printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
- @{change_size}@
+ @{change_size}@
@{init}@
- @{loop}@
- @{operation}@
- @{cond}@
- @{fini}@
- @{end}@
+ @{loop}@
+ @{operation}@
+ @{cond}@
+ @{fini}@
+ @{end}@
- @{free}@
+ @{free}@
MPI_Finalize();
printf("Rank %d finished normally\\n", rank);
for call in tcoll:
patterns = {}
patterns = {'call': call}
- patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {sys.argv[0]}. DO NOT EDIT.'
- patterns['toolfeature'] = 'Yes'
+ patterns['generatedby'] = f'DO NOT EDIT: this file was generated by {os.path.basename(sys.argv[0])}. DO NOT EDIT.'
+ patterns['toolfeature'] = 'Yes'
patterns['call'] = call
patterns['operation'] = operation[call]("1")
patterns['init'] = init[call]("1")
# Generate the correct code
replace = patterns
- replace['shortdesc'] = '@{call}@ is correctly used'
- replace['longdesc'] = f'{call} correctly used'
+ replace['shortdesc'] = '@{call}@ is correctly used'
+ replace['longdesc'] = f'{call} correctly used'
replace['outcome'] = 'OK'
replace['errormsg'] = ''
make_file(template, f'ResLeak_{call}_ok.c', replace)
replace['outcome'] = f'ERROR: {error[call]}'
replace['errormsg'] = 'Resleak. @{call}@ at @{filename}@:@{line:MBIERROR}@ lacks several free.'
replace['change_size'] = 'size=PARAM_PER_ITERATION;'
- replace['loop'] = 'for (i = 0; i < ITERATIONS; i++) {\n for (j = 0; j < PARAM_PER_ITERATION; j++) {'
- replace['cond'] = ' if (j < PARAM_PER_ITERATION - PARAM_LOST_PER_ITERATION) {'
+ replace['loop'] = 'for (i = 0; i < ITERATIONS; i++) {\n for (j = 0; j < PARAM_PER_ITERATION; j++) {'
+ replace['cond'] = ' if (j < PARAM_PER_ITERATION - PARAM_LOST_PER_ITERATION) {'
replace['fini'] = fini[call]("1") + ' /* MBIERROR */'
- replace['end'] = ' }\n }\n }'
+ replace['end'] = ' }\n }\n }'
make_file(template, f'ResLeak_multiple_{call}_nok.c', replace)
-# Copyright 2021-2022. The MBI project. All rights reserved.
+# Copyright 2021-2022. The MBI project. All rights reserved.
# This program is free software; you can redistribute it and/or modify it under the terms of the license (GNU GPL).
# This is a simple templating system, dedicated to the systematic generation of MPI source code
coll4root = ['MPI_Reduce', 'MPI_Bcast', 'MPI_Gather', 'MPI_Scatter']
icoll4root = ['MPI_Ireduce', 'MPI_Ibcast', 'MPI_Igather', 'MPI_Iscatter']
pcoll = []
-tcoll = ['MPI_Comm_split', 'MPI_Op_create', 'MPI_Comm_group', 'MPI_Comm_dup', 'MPI_Type_contiguous', 'MPI_Comm_create', 'MPI_Group_excl']
-tcoll4color = ['MPI_Comm_split']
+tcoll = ['MPI_Comm_split', 'MPI_Op_create', 'MPI_Comm_dup', 'MPI_Type_contiguous', 'MPI_Comm_create', 'MPI_Group_excl'] # MPI_Comm_dup removed
+tcoll4color = ['MPI_Comm_split']
tcoll4topo = ['MPI_Cart_get']
# P2P
allsend = ['MPI_Send', 'MPI_Isend', 'MPI_Ssend', 'MPI_Bsend','MPI_Send_init']
-allrecv = ['MPI_Recv', 'MPI_Irecv', 'MPI_Recv_init']
+allrecv = ['MPI_Recv', 'MPI_Irecv', 'MPI_Recv_init']
send = ['MPI_Send']
ssend = ['MPI_Ssend']
bsend = ['MPI_Bsend']
isend = ['MPI_Isend']
psend = ['MPI_Send_init']
-recv = ['MPI_Recv']
-irecv = ['MPI_Irecv']
-precv = ['MPI_Recv_init']
+recv = ['MPI_Recv']
+irecv = ['MPI_Irecv']
+precv = ['MPI_Recv_init']
probe = ['MPI_Probe']
# RMA
epoch = ['MPI_Win_fence', 'MPI_Win_lock', 'MPI_Win_lock_all']
rma = ['MPI_Get', 'MPI_Put']
get = ['MPI_Get']
-rget = ['MPI_RGet']
-put = ['MPI_Put']
-rput = ['MPI_RPut']
+put = ['MPI_Put']
store = ['store']
load = ['load']
rstore = ['rstore']
start = {}
operation = {}
fini = {}
-free = {}
+free = {}
write = {}
error = {}
epoch = {}
write['MPI_Exscan'] = lambda n: ""
init['MPI_Allgather'] = lambda n: f"int val{n}=1, *rbuf{n} = (int*)malloc(dbs);"
-start['MPI_Allgather'] = lambda n: ""
+start['MPI_Allgather'] = lambda n: ""
operation['MPI_Allgather'] = lambda n: f"MPI_Allgather(&val{n}, 1, type, rbuf{n}, 1, type, newcom);"
fini['MPI_Allgather'] = lambda n: ""
-free['MPI_Allgather'] = lambda n: f"free(rbuf{n});"
-write['MPI_Allgather'] = lambda n: ""
+free['MPI_Allgather'] = lambda n: f"free(rbuf{n});"
+write['MPI_Allgather'] = lambda n: ""
init['MPI_Alltoallv'] = lambda n: (f"int *sbuf{n}=(int*)malloc(dbs*2), *rbuf{n}=(int*)malloc(dbs*2), *scounts{n}=(int*)malloc(dbs), *rcounts{n}=(int*)malloc(dbs), *sdispls{n}=(int*)malloc(dbs), *rdispls{n}=(int*)malloc(dbs);\n"
+ " for (int i = 0; i < nprocs; i++) {\n"
+ f" sdispls{n}[i] = (nprocs - (i + 1)) * 2;\n"
+ f" rdispls{n}[i] = i * 2;\n"
+ " }")
-start['MPI_Alltoallv'] = lambda n: ""
+start['MPI_Alltoallv'] = lambda n: ""
operation['MPI_Alltoallv'] = lambda n: f"MPI_Alltoallv(sbuf{n}, scounts{n}, sdispls{n}, type, rbuf{n}, rcounts{n}, rdispls{n}, type, newcom);"
-fini['MPI_Alltoallv'] = lambda n: ""
+fini['MPI_Alltoallv'] = lambda n: ""
free['MPI_Alltoallv'] = lambda n: f"free(sbuf{n});free(rbuf{n});free(scounts{n});free(rcounts{n});free(sdispls{n});free(rdispls{n});"
-write['MPI_Alltoallv'] = lambda n: ""
+write['MPI_Alltoallv'] = lambda n: ""
init['MPI_Alltoall'] = lambda n: f"int *sbuf{n} = (int*)malloc(dbs), *rbuf{n} = (int*)malloc(dbs);"
-start['MPI_Alltoall'] = lambda n: ""
+start['MPI_Alltoall'] = lambda n: ""
operation['MPI_Alltoall'] = lambda n: f"MPI_Alltoall(sbuf{n}, 1, type, rbuf{n}, 1, type, newcom);"
-fini['MPI_Alltoall'] = lambda n: ""
+fini['MPI_Alltoall'] = lambda n: ""
free['MPI_Alltoall'] = lambda n: f"free(sbuf{n});free(rbuf{n});"
-write['MPI_Alltoall'] = lambda n: ""
+write['MPI_Alltoall'] = lambda n: ""
-init['MPI_Allgatherv'] = lambda n: (f"int *rbuf{n} = (int*)malloc(dbs*2), *rcounts{n}=(int*)malloc(dbs), *displs{n}=(int*)malloc(dbs);\n"
+init['MPI_Allgatherv'] = lambda n: (f"int *rbuf{n} = (int*)malloc(dbs*2), *rcounts{n}=(int*)malloc(dbs), *displs{n}=(int*)malloc(dbs);\n"
+ " for (int i = 0; i < nprocs; i++) {\n"
+ f" rcounts{n}[i] = 1;\n"
+ f" displs{n}[i] = 2 * (nprocs - (i + 1));\n"
+ " }")
-start['MPI_Allgatherv'] = lambda n: ""
+start['MPI_Allgatherv'] = lambda n: ""
operation['MPI_Allgatherv'] = lambda n: f"MPI_Allgatherv(&rank, 1, type, rbuf{n}, rcounts{n}, displs{n}, type, newcom);"
-fini['MPI_Allgatherv'] = lambda n: ""
+fini['MPI_Allgatherv'] = lambda n: ""
free['MPI_Allgatherv'] = lambda n: f"free(rbuf{n});free(rcounts{n});free(displs{n});"
-write['MPI_Allgatherv'] = lambda n: ""
+write['MPI_Allgatherv'] = lambda n: ""
### COLL:nonblocking
init['MPI_Ireduce'] = lambda n: f"MPI_Request req{n}=MPI_REQUEST_NULL; MPI_Status stat{n}; int sum{n}, val{n} = 1;"
start['MPI_Ireduce'] = lambda n: ""
operation['MPI_Ireduce'] = lambda n: f"MPI_Ireduce(&val{n}, &sum{n}, 1, type, op, root, newcom, &req{n});"
-fini['MPI_Ireduce'] = lambda n: f"MPI_Wait(&req{n}, &stat{n});"
+fini['MPI_Ireduce'] = lambda n: f"MPI_Wait(&req{n}, &stat{n});"
free['MPI_Ireduce'] = lambda n: f'if(req{n} != MPI_REQUEST_NULL) MPI_Request_free(&req{n});'
write['MPI_Ireduce'] = lambda n: f"sum{n}++;"
write['MPI_Ibcast'] = lambda n: f'buf{n}[0]++;'
init['MPI_Igather'] = lambda n: f"int val{n}=1, buf{n}[buff_size];MPI_Request req{n}=MPI_REQUEST_NULL;MPI_Status sta{n};"
-start['MPI_Igather'] = lambda n: ""
+start['MPI_Igather'] = lambda n: ""
operation['MPI_Igather'] = lambda n: f'MPI_Igather(&val{n}, 1, type, &buf{n},1, type, root, newcom, &req{n});'
write['MPI_Igather'] = lambda n: f'val{n}=3;'
fini['MPI_Igather'] = lambda n: f'MPI_Wait(&req{n},&sta{n});'
-free['MPI_Igather'] = lambda n: f'if(req{n} != MPI_REQUEST_NULL) MPI_Request_free(&req{n});'
+free['MPI_Igather'] = lambda n: f'if(req{n} != MPI_REQUEST_NULL) MPI_Request_free(&req{n});'
init['MPI_Iscatter'] = lambda n: f"MPI_Request req{n}=MPI_REQUEST_NULL;MPI_Status sta{n};int val{n}, buf{n}[buff_size];"
start['MPI_Iscatter'] = lambda n: ""
write['MPI_Iexscan'] = lambda n: f'outbuf{n}[0]++;'
init['MPI_Iallgather'] = lambda n: f"MPI_Request req{n}=MPI_REQUEST_NULL;MPI_Status sta{n};int val{n}=1, *rbuf{n} = (int*)malloc(dbs);"
-start['MPI_Iallgather'] = lambda n: ""
+start['MPI_Iallgather'] = lambda n: ""
operation['MPI_Iallgather'] = lambda n: f"MPI_Iallgather(&val{n}, 1, type, rbuf{n}, 1, type, newcom,&req{n});"
fini['MPI_Iallgather'] = lambda n: f"MPI_Wait(&req{n},&sta{n});"
-free['MPI_Iallgather'] = lambda n: f"free(rbuf{n});"
+free['MPI_Iallgather'] = lambda n: f"free(rbuf{n});"
write['MPI_Iallgather'] = lambda n: f'val{n}++;'
-init['MPI_Iallgatherv'] = lambda n: (f"MPI_Request req{n}=MPI_REQUEST_NULL;MPI_Status sta{n};int *rbuf{n} = (int*)malloc(dbs*2), *rcounts{n}=(int*)malloc(dbs), *displs{n}=(int*)malloc(dbs);\n"
+init['MPI_Iallgatherv'] = lambda n: (f"MPI_Request req{n}=MPI_REQUEST_NULL;MPI_Status sta{n};int *rbuf{n} = (int*)malloc(dbs*2), *rcounts{n}=(int*)malloc(dbs), *displs{n}=(int*)malloc(dbs);\n"
+ " for (int i = 0; i < nprocs; i++) {\n"
+ f" rcounts{n}[i] = 1;\n"
+ f" displs{n}[i] = 2 * (nprocs - (i + 1));\n"
+ " }")
-start['MPI_Iallgatherv'] = lambda n: ""
+start['MPI_Iallgatherv'] = lambda n: ""
operation['MPI_Iallgatherv'] = lambda n: f"MPI_Iallgatherv(&rank, 1, type, rbuf{n}, rcounts{n}, displs{n}, type, newcom,&req{n});"
-fini['MPI_Iallgatherv'] = lambda n: f"MPI_Wait(&req{n},&sta{n});"
+fini['MPI_Iallgatherv'] = lambda n: f"MPI_Wait(&req{n},&sta{n});"
free['MPI_Iallgatherv'] = lambda n: f"free(rbuf{n});free(rcounts{n});free(displs{n});"
-write['MPI_Iallgatherv'] = lambda n: f"rbuf{n}[0]++;"
+write['MPI_Iallgatherv'] = lambda n: f"rbuf{n}[0]++;"
init['MPI_Ialltoall'] = lambda n: f"MPI_Request req{n}=MPI_REQUEST_NULL;MPI_Status sta{n};int *sbuf{n} = (int*)malloc(dbs), *rbuf{n} = (int*)malloc(dbs);"
-start['MPI_Ialltoall'] = lambda n: ""
+start['MPI_Ialltoall'] = lambda n: ""
operation['MPI_Ialltoall'] = lambda n: f"MPI_Ialltoall(sbuf{n}, 1, type, rbuf{n}, 1, type, newcom, &req{n});"
fini['MPI_Ialltoall'] = lambda n: f"MPI_Wait(&req{n},&sta{n});"
free['MPI_Ialltoall'] = lambda n: f"free(sbuf{n});free(rbuf{n});"
+ f" sdispls{n}[i] = (nprocs - (i + 1)) * 2;\n"
+ f" rdispls{n}[i] = i * 2;\n"
+ " }")
-start['MPI_Ialltoallv'] = lambda n: ""
+start['MPI_Ialltoallv'] = lambda n: ""
operation['MPI_Ialltoallv'] = lambda n: f"MPI_Ialltoallv(sbuf{n}, scounts{n}, sdispls{n}, type, rbuf{n}, rcounts{n}, rdispls{n}, type, newcom,&req{n});"
fini['MPI_Ialltoallv'] = lambda n: f"MPI_Wait(&req{n},&sta{n});"
free['MPI_Ialltoallv'] = lambda n: f"free(sbuf{n});free(rbuf{n});free(scounts{n});free(rcounts{n});free(sdispls{n});free(rdispls{n});"
operation['MPI_Comm_group'] = lambda n: 'MPI_Comm_group(MPI_COMM_WORLD, &grp[j]);'
error['MPI_Comm_group'] = 'GroupLeak'
fini['MPI_Comm_group'] = lambda n: "MPI_Group_free(&grp[j]);"
-free['MPI_Comm_group'] = lambda n: ""
+free['MPI_Comm_group'] = lambda n: ""
init['MPI_Group_excl'] = lambda n: 'MPI_Group worldgroup, grp[size];\n MPI_Comm_group(MPI_COMM_WORLD, &worldgroup);'
-operation['MPI_Group_excl'] = lambda n: 'MPI_Group_excl(worldgroup, 1, &rank, &grp[j]);'
+operation['MPI_Group_excl'] = lambda n: 'MPI_Group_excl(worldgroup, 1, &rank, &grp[j]);'
error['MPI_Group_excl'] = 'GroupLeak'
fini['MPI_Group_excl'] = lambda n: "MPI_Group_free(&grp[j]);"
free['MPI_Group_excl'] = lambda n: "MPI_Group_free(&worldgroup);"
operation['MPI_Comm_dup'] = lambda n: 'MPI_Comm_dup(MPI_COMM_WORLD, &com[j]);'
error['MPI_Comm_dup'] = 'CommunicatorLeak'
fini['MPI_Comm_dup'] = lambda n: "MPI_Comm_free(&com[j]);"
-free['MPI_Comm_dup'] = lambda n: ""
+free['MPI_Comm_dup'] = lambda n: ""
init['MPI_Type_contiguous'] = lambda n: 'MPI_Datatype type[size];'
operation['MPI_Type_contiguous'] = lambda n: 'MPI_Type_contiguous(2, MPI_DOUBLE, &type[j]);'
error['MPI_Type_contiguous'] = 'TypeLeak'
fini['MPI_Type_contiguous'] = lambda n: "MPI_Type_free(&type[j]);"
-free['MPI_Type_contiguous'] = lambda n: ""
+free['MPI_Type_contiguous'] = lambda n: ""
-### P2P:basic
+### P2P:basic
init['MPI_Send'] = lambda n: f'int buf{n}=rank;'
start['MPI_Send'] = lambda n: ""
write['MPI_Ssend'] = lambda n: ""
init['MPI_Bsend'] = lambda n: (f'int buf{n}=rank;\n'
- + f'int buffer_attached_size{n} = MPI_BSEND_OVERHEAD + sizeof(int);\n'
+ + f'int buffer_attached_size{n} = MPI_BSEND_OVERHEAD + sizeof(int);\n'
+ f'char* buffer_attached{n} = (char*)malloc(buffer_attached_size{n});\n'
+ f'MPI_Buffer_attach(buffer_attached{n}, buffer_attached_size{n});')
start['MPI_Bsend'] = lambda n: ""
### P2P:nonblocking
init['MPI_Isend'] = lambda n: f'int buf{n}=rank; MPI_Request req{n}=MPI_REQUEST_NULL;'
-start['MPI_Isend'] = lambda n: ""
+start['MPI_Isend'] = lambda n: ""
operation['MPI_Isend'] = lambda n: f'MPI_Isend(&buf{n}, buff_size, type, dest, stag, newcom, &req{n});'
fini['MPI_Isend'] = lambda n: f'MPI_Wait(&req{n}, MPI_STATUS_IGNORE);'
free['MPI_Isend'] = lambda n: f'if(req{n} != MPI_REQUEST_NULL) MPI_Request_free(&req{n});'
write['MPI_Isend'] = lambda n: f'buf{n}=4;'
init['MPI_Irecv'] = lambda n: f'int buf{n}=-1; MPI_Request req{n}=MPI_REQUEST_NULL;'
-start['MPI_Irecv'] = lambda n: ""
+start['MPI_Irecv'] = lambda n: ""
operation['MPI_Irecv'] = lambda n: f'MPI_Irecv(&buf{n}, buff_size, type, src, rtag, newcom, &req{n});'
fini['MPI_Irecv'] = lambda n: f' MPI_Wait(&req{n}, MPI_STATUS_IGNORE);'
free['MPI_Irecv'] = lambda n: f'if(req{n} != MPI_REQUEST_NULL) MPI_Request_free(&req{n});'
-write['MPI_Irecv'] = lambda n: f'buf{n}++;'
+write['MPI_Irecv'] = lambda n: f'buf{n}++;'
### P2P:persistent
init['MPI_Send_init'] = lambda n: f'int buf{n}=rank; MPI_Request req{n}=MPI_REQUEST_NULL;'
-operation['MPI_Send_init'] = lambda n: f'MPI_Send_init(&buf{n}, buff_size, type, dest, stag, newcom, &req{n});'
+operation['MPI_Send_init'] = lambda n: f'MPI_Send_init(&buf{n}, buff_size, type, dest, stag, newcom, &req{n});'
start['MPI_Send_init'] = lambda n: f'MPI_Start(&req{n});'
fini['MPI_Send_init'] = lambda n: f'MPI_Wait(&req{n}, MPI_STATUS_IGNORE);'
free['MPI_Send_init'] = lambda n: f'if(req{n} != MPI_REQUEST_NULL) MPI_Request_free(&req{n});'
-write['MPI_Send_init'] = lambda n: f'buf{n}=4;'
+write['MPI_Send_init'] = lambda n: f'buf{n}=4;'
init['MPI_Recv_init'] = lambda n: f'int buf{n}=-1; MPI_Request req{n}=MPI_REQUEST_NULL;'
start['MPI_Recv_init'] = lambda n: f'MPI_Start(&req{n});'
operation['MPI_Recv_init'] = lambda n: f'MPI_Recv_init(&buf{n}, buff_size, type, src, rtag, newcom, &req{n});'
fini['MPI_Recv_init'] = lambda n: f'MPI_Wait(&req{n}, MPI_STATUS_IGNORE);'
free['MPI_Recv_init'] = lambda n: f'if(req{n} != MPI_REQUEST_NULL) MPI_Request_free(&req{n});'
-write['MPI_Recv_init'] = lambda n: f'buf{n}++;'
+write['MPI_Recv_init'] = lambda n: f'buf{n}++;'
### RMA
epoch['MPI_Win_lock_all'] =lambda n: 'MPI_Win_lock_all(0,win);'
finEpoch['MPI_Win_lock_all'] =lambda n: 'MPI_Win_unlock_all(win);'
-init['MPI_Put'] = lambda n: f'int localbuf{n} = 12345;'
+init['MPI_Put'] = lambda n: f'int localbuf{n}[N] = {{12345}};'
operation['MPI_Put'] = lambda n: f'MPI_Put(&localbuf{n}, N, MPI_INT, target, 0, N, type, win);'
-init['MPI_RPut'] = lambda n: ""
-operation['MPI_RPut'] = lambda n: f'MPI_Put(&winbuf[20], N, MPI_INT, target, 0, N, type, win);'
+init['MPI_Get'] = lambda n: f'int localbuf{n}[N] = {{54321}};'
+operation['MPI_Get'] = lambda n: f'MPI_Get(&localbuf{n}, N, MPI_INT, target, 0, N, type, win);'
-init['MPI_Get'] = lambda n: f'int localbuf{n} = 54321;'
-operation['MPI_Get'] = lambda n: f'MPI_Get(&localbuf{n}, N, MPI_INT, target, 0, N, type, win);'
-
-init['MPI_RGet'] = lambda n: ""
-operation['MPI_RGet'] = lambda n: f'MPI_Get(&winbuf[20], N, MPI_INT, target, 0, N, type, win);'
-
-init['store'] = lambda n: f'int localbuf{n} = 0;'
-operation['store'] = lambda n: f'localbuf{n} = 8;'
+init['store'] = lambda n: f'int localbuf{n}[N] = {{0}};'
+operation['store'] = lambda n: f'localbuf{n}[0] = 8;'
init['rstore'] = lambda n: ""
operation['rstore'] = lambda n: f'winbuf[20] = 12346;'
-init['load'] = lambda n: f'int localbuf{n} = 0;'
-operation['load'] = lambda n: f'int load = localbuf{n};'
+init['load'] = lambda n: f'int localbuf{n}[N] = {{0}};'
+operation['load'] = lambda n: f'int load = localbuf{n}[0];'
-init['rload'] = lambda n: ""
+init['rload'] = lambda n: ""
operation['rload'] = lambda n: "int load = winbuf[20];"
-init['loadstore'] = lambda n: f'int localbuf{n} = 0;'
-operation['loadstore'] = lambda n: f'if (localbuf{n} % 2 == 0) localbuf{n}++; '
+init['loadstore'] = lambda n: f'int localbuf{n}[N] = {{0}};'
+operation['loadstore'] = lambda n: f'if (localbuf{n}[0] % 2 == 0) localbuf{n}[0]++; '
-# Copyright 2021-2022. The MBI project. All rights reserved.
+# Copyright 2021-2022. The MBI project. All rights reserved.
# This program is free software; you can redistribute it and/or modify it under the terms of the license (GNU GPL).
import re
os.environ['PATH'] = os.environ['PATH'] + ":" + rootdir + "/builds/SimGrid/bin"
os.environ['VERBOSE'] = '1'
- def run(self, execcmd, filename, binary, id, timeout, batchinfo):
- cachefile = f'{binary}_{id}'
+ def run(self, execcmd, filename, binary, num_id, timeout, batchinfo):
+ cachefile = f'{binary}_{num_id}'
if not os.path.exists("cluster.xml"):
with open('cluster.xml', 'w') as outfile:
outfile.write('</platform>\n')
execcmd = execcmd.replace("mpirun", "smpirun -wrapper simgrid-mc -platform ./cluster.xml -analyze --cfg=smpi/finalization-barrier:on --cfg=smpi/list-leaks:10 --cfg=model-check/max-depth:10000")
- if re.search("Concurrency", binary): # DPOR reduction in simgrid cannot deal with RMA calls as they contain mutexes
- execcmd = execcmd.replace("smpirun", "smpirun --cfg=model-check/reduction:none")
execcmd = execcmd.replace('${EXE}', binary)
execcmd = execcmd.replace('$zero_buffer', "--cfg=smpi/buffering:zero")
execcmd = execcmd.replace('$infty_buffer', "--cfg=smpi/buffering:infty")
timeout=timeout,
batchinfo=batchinfo)
- def teardown(self):
+ def teardown(self):
subprocess.run("find -type f -a -executable | xargs rm -f", shell=True, check=True) # Remove generated cruft (binary files)
- subprocess.run("rm -f smpitmp-* core", shell=True, check=True)
+ subprocess.run("rm -f smpitmp-* core", shell=True, check=True)
def parse(self, cachefile):
if os.path.exists(f'{cachefile}.timeout') or os.path.exists(f'logs/simgrid/{cachefile}.timeout'):
if re.search('MC is currently not supported here', output):
return 'failure'
+ if re.search('Collective communication mismatch', output):
+ return 'Collective mismatch'
+
if re.search('DEADLOCK DETECTED', output):
return 'deadlock'
if re.search('returned MPI_ERR', output):
> [0.000000] [smpi/INFO] [rank 13] -> Ginette
> [0.000000] [smpi/INFO] [rank 14] -> Ginette
> [0.000000] [smpi/INFO] [rank 15] -> Ginette
-> [0.023780] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 32 unfreed MPI handles:
-> [0.023780] [smpi_utils/INFO] 16 leaked handles of type MPI_Comm at coll-allreduce-with-leaks.c:23
-> [0.023780] [smpi_utils/INFO] 16 leaked handles of type MPI_Group at coll-allreduce-with-leaks.c:23
-> [0.023780] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 32 unfreed buffers:
-> [0.023780] [smpi_utils/INFO] coll-allreduce-with-leaks.c:28: leaked allocations of total size 1504, called 16 times, with minimum size 64 and maximum size 124
-> [0.023780] [smpi_utils/INFO] coll-allreduce-with-leaks.c:27: leaked allocations of total size 1024, called 16 times, each with size 64
-> [0.023780] [smpi_utils/INFO] Memory Usage: Simulated application allocated 2528 bytes during its lifetime through malloc/calloc calls.
+> [0.015765] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 32 unfreed MPI handles:
+> [0.015765] [smpi_utils/INFO] 16 leaked handles of type MPI_Comm at coll-allreduce-with-leaks.c:23
+> [0.015765] [smpi_utils/INFO] 16 leaked handles of type MPI_Group at coll-allreduce-with-leaks.c:23
+> [0.015765] [smpi_utils/INFO] Probable memory leaks in your code: SMPI detected 32 unfreed buffers:
+> [0.015765] [smpi_utils/INFO] coll-allreduce-with-leaks.c:28: leaked allocations of total size 1504, called 16 times, with minimum size 64 and maximum size 124
+> [0.015765] [smpi_utils/INFO] coll-allreduce-with-leaks.c:27: leaked allocations of total size 1024, called 16 times, each with size 64
+> [0.015765] [smpi_utils/INFO] Memory Usage: Simulated application allocated 2528 bytes during its lifetime through malloc/calloc calls.
> Largest allocation at once from a single process was 124 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)
> 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
> 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. 73 unique states visited; 18 backtracks (592 transition replays, 502 states visited overall)
+> [0.000000] [mc_dfs/INFO] DFS exploration ended. 33 unique states visited; 7 backtracks (140 transition replays, 101 states visited overall)
elsif (/--?platformfile=(.*)/) { $platformfile = $1; }
elsif (/--?hostfile=(.*)/) { $hostfile = $1; }
elsif (/--?srcdir=(.*)/) { $srcdir = $1;
- $mpiexec="$mpiexec -platform ${srcdir}/$platformfile -hostfile ${srcdir}/$hostfile --log=root.thr:critical --log=smpi_kernel.thr:warning --cfg=smpi/host-speed:1e9f --cfg=smpi/async-small-thresh:65536"; }
+ $mpiexec="$mpiexec -platform ${srcdir}/$platformfile -hostfile ${srcdir}/$hostfile --log=root.thr:critical --log=smpi_kernel.thr:warning --cfg=smpi/host-speed:1e9f --cfg=smpi/async-small-thresh:65536 --cfg=smpi/os:1:0.0000003:0.0000002 --cfg=smpi/ois:1:0.0000003:0.0000002"; }
elsif (/--?verbose/) { $verbose = 1; }
elsif (/--?showprogress/) { $showProgress = 1; }
elsif (/--?debug/) { $debug = 1; }
-Denable_ns3=ON \
-Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=ON -Denable_model-checking=ON \
-Denable_smpi_papi=ON \
- -Denable_memcheck=OFF -Denable_memcheck_xml=OFF -Denable_smpi_MBI_testsuite=OFF \
+ -Denable_memcheck=OFF -Denable_memcheck_xml=OFF -Denable_smpi_MBI_testsuite=ON \
-Denable_coverage=ON -DLTO_EXTRA_FLAG="auto" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON "$WORKSPACE"
#build with sonarqube scanner wrapper
cd "$WORKSPACE"
#convert all gcov reports to xml cobertura reports
- gcovr -r . --xml-pretty -e teshsuite -e examples/smpi/NAS -e examples/smpi/mc -u -o "$BUILDFOLDER"/xml_coverage.xml
+ gcovr -r . --xml-pretty -e teshsuite -e build/MBI -e examples/smpi/NAS -e examples/smpi/mc -u -o "$BUILDFOLDER"/xml_coverage.xml
xsltproc "$WORKSPACE"/tools/jenkins/ctest2junit.xsl build/Testing/"$( head -n 1 < build/Testing/TAG )"/Test.xml > CTestResults_memcheck.xml
#generate sloccount report
# * teshsuite/s4u/monkey-masterworkers: tests synchronous comms and execs (C++ and python)
# * teshsuite/s4u/monkey-semaphore: tests async semaphores (C++ only)
-import multiprocessing as mp
import sys
import os
import argparse
def doit():
prev_time = 0
- test_count = 0
test_todo = 2 * len(timestamps) * (host_count + link_count)
for pos in range(len(timestamps)):
now = timestamps[pos]