From 1747635ae3b07a8d2e0508d3c2e55c5936d64d65 Mon Sep 17 00:00:00 2001
From: Simon Schwitanski <schwitanski@itc.rwth-aachen.de>
Date: Sun, 4 Feb 2024 22:03:35 +0100
Subject: [PATCH 01/18] InstructionBlock: Add get_operations and
 register_operations for lists of operations

---
 scripts/Infrastructure/InstructionBlock.py | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/scripts/Infrastructure/InstructionBlock.py b/scripts/Infrastructure/InstructionBlock.py
index ec5310b92..dfb40d40a 100644
--- a/scripts/Infrastructure/InstructionBlock.py
+++ b/scripts/Infrastructure/InstructionBlock.py
@@ -50,6 +50,20 @@ class InstructionBlock:
                 self.operations[as_int] = []
             self.operations[as_int].append(op)
 
+    def register_operations(self, ops, kind='all'):
+        """
+        Registers a list of operations based on rank.
+
+        Parameters:
+            - ops: The operations to register.
+            - kind: Rank to execute the operation ('all', 'not0', or integer).
+                - all: all Ranks execute this operation
+                - not0: all Ranks but the Root (rank 0) execute
+                - Or the integer of the rank that should execute
+        """
+        for op in ops:
+            self.register_operation(op, kind)
+
     def get_version(self):
         """
         Retrieves the minimum required MPI version.
@@ -114,6 +128,16 @@ class InstructionBlock:
             str: The operation specified by kind and index
         """
         return self.operations[kind][index]
+    
+    def get_operations(self, kind='all'):
+        """
+        Retrieve all operations registered for the given kind.
+        Parameters:
+            - kind ('all','not0' or integer): which ranks should execute the operation
+        Returns:
+            str: List of all operations with given kind
+        """
+        return self.operations[kind]
 
     def replace_operation(self, op, kind='all', index=0):
         """
-- 
GitLab


From f994cc14378b7acaabd074b89b707750e5a87e21 Mon Sep 17 00:00:00 2001
From: Simon Schwitanski <schwitanski@itc.rwth-aachen.de>
Date: Sun, 4 Feb 2024 22:05:41 +0100
Subject: [PATCH 02/18] Add default parameters for RMA calls

---
 scripts/Infrastructure/CorrectParameter.py | 28 ++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/scripts/Infrastructure/CorrectParameter.py b/scripts/Infrastructure/CorrectParameter.py
index 7eea7f606..d4aac6405 100644
--- a/scripts/Infrastructure/CorrectParameter.py
+++ b/scripts/Infrastructure/CorrectParameter.py
@@ -8,8 +8,10 @@ class CorrectParameterFactory:
     # default params
     buf_size = 10
     dtype = ['int', 'MPI_INT']
+    buf_size_bytes = f"{buf_size}*sizeof({dtype[0]})"
     tag = 0
     buf_var_name = "buf"
+    winbuf_var_name = "winbuf"
 
     def __init__(self):
         pass
@@ -21,13 +23,13 @@ class CorrectParameterFactory:
         return get_free(AllocCall(self.dtype[0], self.buf_size, self.buf_var_name, use_malloc=False))
 
     def get(self, param, func=None):
-        if param in ["BUFFER", "buf", "buffer", "sendbuf", "recvbuf"]:
+        if param in ["BUFFER", "buf", "buffer", "sendbuf", "recvbuf", "origin_addr"]:
             return self.buf_var_name
-        if param in ["COUNT", "count", "sendcount", "recvcount"]:
+        if param in ["COUNT", "count", "sendcount", "recvcount", "origin_count", "target_count", "result_count"]:
             return str(self.buf_size)
-        if param in ["DATATYPE", "datatype", "sendtype", "recvtype"]:
+        if param in ["DATATYPE", "datatype", "sendtype", "recvtype", "origin_datatype", "target_datatype", "result_datatype"]:
             return self.dtype[1]
-        if param in ["DEST", "dest"]:
+        if param in ["DEST", "dest", "target_rank"]:
             return "0"
         if param in ["SRC", "source"]:
             return "1"
@@ -71,6 +73,24 @@ class CorrectParameterFactory:
             return "MPI_COMM_WORLD"
         if param in ["remote_leader"]:
             return "0"
+        if param in ["target_disp"]:
+            return "0"
+        if param in ["win"]:
+            return "win"
+        if param in ["baseptr"]:
+            return "&" + self.winbuf_var_name
+        if param in ["base"]:
+            return self.winbuf_var_name
+        if param in ["size"]:
+            return self.buf_size_bytes
+        if param in ["disp_unit"]:
+            return "sizeof(int)"
+        if param in ["info"]:
+            return "MPI_INFO_NULL"
+        if param in ["result_addr"]:
+            return "resultbuf"
+        if param in ["compare_addr"]:
+            return "comparebuf"
         print("Not Implemented: " + param)
         assert False, "Param not known"
 
-- 
GitLab


From 17730c7d8519ee95c6a6517124f907d7a7357c71 Mon Sep 17 00:00:00 2001
From: Simon Schwitanski <schwitanski@itc.rwth-aachen.de>
Date: Sun, 4 Feb 2024 22:06:15 +0100
Subject: [PATCH 03/18] Add templates for window allocations and RMA calls

---
 scripts/Infrastructure/TemplateFactory.py | 68 +++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/scripts/Infrastructure/TemplateFactory.py b/scripts/Infrastructure/TemplateFactory.py
index 1790c08df..47abb7688 100644
--- a/scripts/Infrastructure/TemplateFactory.py
+++ b/scripts/Infrastructure/TemplateFactory.py
@@ -184,6 +184,74 @@ def get_collective_template(collective_func, seperate=True):
     return tm
 
 
+def get_allocated_window(win_alloc_func, name, bufname, ctype, num_elements):
+    """
+    Constructs a window allocation using Win_allocate or Win_create.
+    :param win_alloc_func: The window allocation to use (mpi_win_allocate or mpi_win_create).
+    :param name: name of the window
+    """
+    
+    b = InstructionBlock("win_allocate")
+
+    # declare window
+    b.register_operation(f"MPI_Win {name};")
+
+    # extract C data type and window buffer name
+    # dtype = CorrectParameterFactory().dtype[0]
+    # winbuf_name = CorrectParameterFactory().winbuf_var_name
+    # winbuf_size = CorrectParameterFactory().buf_size_bytes
+    win_allocate_call = None
+
+    if win_alloc_func == "mpi_win_allocate":
+        # MPI allocate, only declaration required
+        b.register_operation(f"{ctype}* {bufname};")
+        win_allocate_call = CorrectMPICallFactory().mpi_win_allocate()
+        win_allocate_call.set_arg("baseptr", "&" + bufname)
+    elif win_alloc_func == "mpi_win_create":
+        # allocate buffer for win_create
+        b.register_operation(AllocCall(ctype, num_elements, bufname))
+        win_allocate_call = CorrectMPICallFactory().mpi_win_create()
+        win_allocate_call.set_arg("base", bufname)
+    else:
+        assert False
+    
+    # set common parameters for both calls
+    win_allocate_call.set_arg("win", "&" + name)
+
+    buf_size_bytes = num_elements + "*sizeof(" + ctype + ")"
+    win_allocate_call.set_arg("size", buf_size_bytes)
+
+    win_allocate_call.set_arg("disp_unit", f"sizeof({ctype})")
+    b.register_operation(win_allocate_call)
+
+    return b
+
+
+
+def get_rma_call(rma_func, rank):
+
+    b = InstructionBlock(rma_func.replace('mpi_',''))
+
+    cf = CorrectParameterFactory()
+    cfmpi = CorrectMPICallFactory()
+
+    # request-based RMA call, add request
+    if rma_func.startswith("mpi_r"):
+        b.register_operation(f"MPI_Request " + cf.get("request")[1:] + ";", kind=rank)
+
+    # some RMA ops require result_addr
+    if rma_func in ["mpi_get_accumulate", "mpi_rget_accumulate", "mpi_fetch_and_op", "mpi_compare_and_swap"]:
+        b.register_operation(AllocCall(cf.dtype[0], cf.buf_size, cf.get("result_addr")), kind=rank)
+
+    # some RMA ops require compare_addr
+    if rma_func in ["mpi_fetch_and_op", "mpi_compare_and_swap"]:
+        b.register_operation(AllocCall(cf.dtype[0], cf.buf_size, cf.get("compare_addr")), kind=rank)
+
+    b.register_operation(getattr(cfmpi, rma_func)(), kind=rank)
+    return b
+
+
+
 def get_communicator(comm_create_func, name):
     """
     :param comm_create_func: teh function used to create the new communicator
-- 
GitLab


From 683de0c2a613e8b6d736a0c70b3046e208fc67cc Mon Sep 17 00:00:00 2001
From: Simon Schwitanski <schwitanski@itc.rwth-aachen.de>
Date: Sun, 4 Feb 2024 22:07:09 +0100
Subject: [PATCH 04/18] Add initial version of LocalConcurrency RMA generator

---
 scripts/errors/rma/LocalConcurrency.py | 146 +++++++++++++++++++++++++
 1 file changed, 146 insertions(+)
 create mode 100644 scripts/errors/rma/LocalConcurrency.py

diff --git a/scripts/errors/rma/LocalConcurrency.py b/scripts/errors/rma/LocalConcurrency.py
new file mode 100644
index 000000000..152203dc6
--- /dev/null
+++ b/scripts/errors/rma/LocalConcurrency.py
@@ -0,0 +1,146 @@
+#! /usr/bin/python3
+
+from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
+from scripts.Infrastructure.InstructionBlock import InstructionBlock
+from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
+from scripts.Infrastructure.CorrectParameter import (
+    CorrectParameterFactory,
+    get_matching_recv,
+)
+from scripts.Infrastructure.Template import TemplateManager
+from scripts.Infrastructure.TemplateFactory import get_allocated_window, get_rma_call
+from scripts.Infrastructure.AllocCall import AllocCall
+from scripts.Infrastructure.MPICall import MPI_Call
+
+import itertools
+
+from scripts.Infrastructure.Variables import ERROR_MARKER_COMMENT
+
+from typing import Tuple, List
+
+class LocalConcurrencyErrorRMA(ErrorGenerator):
+    local_origin_addr_write = ["mpi_get", "mpi_rget"]
+    local_origin_addr_read = [
+        "mpi_put",
+        "mpi_rput",
+        "mpi_accumulate",
+        "mpi_raccumulate",
+        "mpi_get_accumulate",
+        "mpi_rget_accumulate",
+        "mpi_fetch_and_op",
+        "mpi_compare_and_swap",
+    ]
+    functions_to_check = ["mpi_put", "mpi_get", "mpi_rput", "mpi_rget"]
+
+    # recv_funcs = ["mpi_irecv", "mpi_recv_init", "mpi_precv_init"]
+
+    def __init__(self):
+        pass
+
+    def get_feature(self):
+        return ["RMA"]
+
+    def generate(self, generate_full_set):
+
+        cf = CorrectParameterFactory()
+        cfmpi = CorrectMPICallFactory()
+
+        mpi_buf_read = [
+            get_rma_call("mpi_put", 0),
+            get_rma_call("mpi_rput", 0),
+            get_rma_call("mpi_accumulate", 0),
+            get_rma_call("mpi_raccumulate", 0),
+            get_rma_call("mpi_get_accumulate", 0),
+            get_rma_call("mpi_rget_accumulate", 0),
+            get_rma_call("mpi_fetch_and_op", 0),
+            get_rma_call("mpi_compare_and_swap", 0),
+        ]
+        mpi_buf_write = [get_rma_call("mpi_get", 0), get_rma_call("mpi_rget", 0)]
+
+        bufread = InstructionBlock("bufread")
+        bufread.register_operation(f'printf("buf is %d\\n", {cf.buf_var_name}[1]);', 0)
+        bufwrite = InstructionBlock("write")
+        bufwrite.register_operation(f'{cf.buf_var_name}[1] = 42;', 0)
+
+        # 7 possible combinations of local buffer accesses (hasconflict = True | False)
+        local_access_combinations: List[Tuple[List[InstructionBlock], List[InstructionBlock], bool]] = [
+            (mpi_buf_read, [bufread], False),
+            (mpi_buf_read, [bufwrite], True),
+            (mpi_buf_write, [bufread], True),
+            (mpi_buf_write, [bufwrite], True),
+            (mpi_buf_read, mpi_buf_read, False),
+            (mpi_buf_read, mpi_buf_write, True),
+            (mpi_buf_write, mpi_buf_write, True),
+        ]
+
+        for ops1, ops2, hasconflict in local_access_combinations:
+            for (op1, op2) in itertools.product(ops1, ops2):
+                tm = TemplateManager()
+                # window allocation boilerplate
+                b = get_allocated_window("mpi_win_create", "win", "winbuf", "int", "2")
+                tm.register_instruction_block(b)
+
+                # local buffer allocation
+                alloc = InstructionBlock("alloc")
+                alloc.register_operation(
+                    AllocCall(cf.dtype[0], cf.buf_size, cf.buf_var_name)
+                )
+                tm.register_instruction_block(alloc)
+
+                if hasconflict:
+                    if isinstance(op1.get_operation(kind=0, index=-1), MPI_Call):
+                        op1.get_operation(kind=0, index=-1).set_has_error()
+                    else:
+                        op1.replace_operation(op1.get_operation(kind=0, index=-1) + ERROR_MARKER_COMMENT, 0, 0)
+
+                    if isinstance(op2.get_operation(kind=0, index=-1), MPI_Call):
+                        op2.get_operation(kind=0, index=-1).set_has_error()
+                    else:
+                        op2.replace_operation(op2.get_operation(kind=0, index=-1) + ERROR_MARKER_COMMENT, 0, 0)
+
+                # fuse instructions blocks
+                # combined_ops = InstructionBlock("COMBINED")
+                # combined_ops.register_operations(op1.get_operations(kind=0), kind=0)
+                # combined_ops.register_operations(op2.get_operations(kind=0), kind=0)
+                tm.register_instruction_block(op1)
+                tm.register_instruction_block(op2)
+
+                tm.set_description(
+                    ("LocalConcurrency" if hasconflict else "Correct") + 
+                    "-"
+                    + op1.name
+                    + "_"
+                    + op2.name,
+                    "full description",
+                )
+                yield tm
+                
+                # get RMA call
+                # rmaop = get_rma_call(function_to_check, 0)
+
+                # tm.register_instruction_block(rmaop)
+
+                # bufstring = ""
+                # if bufop == "read":  # local buffer access is read
+                #     bufstring = f'printf("buf is %d\\n", {cf.buf_var_name}[1]);'
+                #     # if RMA call performs local buffer write, this is a race, otherwise no race
+                #     if function_to_check in local_origin_addr_write:
+                #         bufstring += ERROR_MARKER_COMMENT
+                #         # mark RMA call as erroneous
+                #         tm.get_block("RMACALL").get_operation(
+                #             kind=0, index=-1
+                #         ).set_has_error()
+
+                # if bufop == "write":
+                #     # a buffer write is always a race
+                #     bufstring = f"{cf.buf_var_name}[1] = 42;" + ERROR_MARKER_COMMENT
+                #     # mark RMA call as erroneous
+                #     tm.get_block("RMACALL").get_operation(
+                #         kind=0, index=-1
+                #     ).set_has_error()
+
+                # # finally register buffer access
+                # tm.get_block("RMACALL").register_operation(bufstring, 0)
+
+            # if not generate_full_set:
+            #     return
-- 
GitLab


From 5e272eefd3b7b8ed898baab4bd8ae798150f5074 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 12:46:14 +0100
Subject: [PATCH 05/18] fix wrong generators

---
 scripts/errors/pt2pt/InvalidRank.py | 1 -
 scripts/errors/pt2pt/InvalidTag.py  | 4 ++--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/scripts/errors/pt2pt/InvalidRank.py b/scripts/errors/pt2pt/InvalidRank.py
index c049e79dc..95f6db52d 100644
--- a/scripts/errors/pt2pt/InvalidRank.py
+++ b/scripts/errors/pt2pt/InvalidRank.py
@@ -13,7 +13,6 @@ from itertools import chain
 class InvalidRankErrorP2P(ErrorGenerator):
     invalid_ranks = ["-1", "nprocs", "MPI_PROC_NULL"]
     send_funcs = ["mpi_send",
-                  "mpi_irecv",
                   "mpi_isend", "mpi_ssend", "mpi_issend", "mpi_rsend", "mpi_irsend", "mpi_bsend", "mpi_ibsend",
                   "mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init", "mpi_psend_init"
                   ]
diff --git a/scripts/errors/pt2pt/InvalidTag.py b/scripts/errors/pt2pt/InvalidTag.py
index e5c360806..74041139b 100644
--- a/scripts/errors/pt2pt/InvalidTag.py
+++ b/scripts/errors/pt2pt/InvalidTag.py
@@ -69,11 +69,11 @@ class InvalidTagErrorP2P(ErrorGenerator):
     def generate(self, generate_full_set):
 
         for send_func in self.send_funcs:
-            yield from self.generate_impl(self, send_func, "mpi_irecv", False)
+            yield from self.generate_impl(send_func, "mpi_irecv", False)
             if not generate_full_set:
                 return
         for recv_func in self.recv_funcs:
-            yield from self.generate_impl(self, "mpi_send", recv_func, True)
+            yield from self.generate_impl("mpi_send", recv_func, True)
 
         for func in self.sendrecv_funcs:
             yield from self.generate_impl(func, func, True)
-- 
GitLab


From 92f7fa9c788d925518ebcb7ab65fa45816700bbc Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 13:00:22 +0100
Subject: [PATCH 06/18] added Instruction class (#6)

---
 scripts/Infrastructure/AllocCall.py   |  7 +++++--
 scripts/Infrastructure/Instruction.py | 13 +++++++++++++
 scripts/Infrastructure/MPICall.py     |  6 +++++-
 3 files changed, 23 insertions(+), 3 deletions(-)
 create mode 100644 scripts/Infrastructure/Instruction.py

diff --git a/scripts/Infrastructure/AllocCall.py b/scripts/Infrastructure/AllocCall.py
index 25dea717c..0e11f2462 100644
--- a/scripts/Infrastructure/AllocCall.py
+++ b/scripts/Infrastructure/AllocCall.py
@@ -1,5 +1,7 @@
 #! /usr/bin/python3
+from typing_extensions import override
 
+from scripts.Infrastructure.Instruction import Instruction
 
 alloc_template = """
 @{TYPE}@* @{NAME}@ = (@{TYPE}@*) @{FUNCTION}@(@{NUM}@ @{SEP}@ sizeof(@{TYPE}@)); 
@@ -20,8 +22,8 @@ alloc_template = """
 """
 
 
-class AllocCall:
-
+class AllocCall (Instruction):
+    @override
     def __init__(self, type, num_elements, name="buf", use_malloc=False):
         """
         Creates a New allocation Call
@@ -37,6 +39,7 @@ class AllocCall:
         self._num_elements = num_elements
         self._name = name
 
+    @override
     def __str__(self):
         if self._use_malloc:
             delim = '*'
diff --git a/scripts/Infrastructure/Instruction.py b/scripts/Infrastructure/Instruction.py
new file mode 100644
index 000000000..16165d5b0
--- /dev/null
+++ b/scripts/Infrastructure/Instruction.py
@@ -0,0 +1,13 @@
+#! /usr/bin/python3
+
+
+class Instruction(object):
+    """
+    Base class to represent an Instruction
+    """
+
+    def __init__(self, str_representation):
+        self._str_representation = str_representation
+
+    def __str__(self):
+        return self._str_representation
diff --git a/scripts/Infrastructure/MPICall.py b/scripts/Infrastructure/MPICall.py
index 02c1cf359..05f525928 100644
--- a/scripts/Infrastructure/MPICall.py
+++ b/scripts/Infrastructure/MPICall.py
@@ -1,16 +1,20 @@
 #! /usr/bin/python3
+from typing_extensions import override
 
+from scripts.Infrastructure.Instruction import Instruction
 from scripts.Infrastructure.Variables import ERROR_MARKER_COMMENT
 
 
-class MPI_Call:
+class MPI_Call (Instruction):
 
+    @override
     def __init__(self, function, args, version):
         self._function = function
         self._args = args
         self._version = version
         self._has_error = False
 
+    @override
     def __str__(self):
         s = self._function + "("
         for k, v in self._args.items():
-- 
GitLab


From 6bf6c24572352416918186f9af51742b91e178a2 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 13:09:50 +0100
Subject: [PATCH 07/18] added Type hints (#7) for the Instruction Classes

---
 scripts/Infrastructure/AllocCall.py   | 22 +++++++++++-----------
 scripts/Infrastructure/Instruction.py |  2 +-
 scripts/Infrastructure/MPICall.py     | 14 +++++++-------
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/scripts/Infrastructure/AllocCall.py b/scripts/Infrastructure/AllocCall.py
index 0e11f2462..26e8a8c3c 100644
--- a/scripts/Infrastructure/AllocCall.py
+++ b/scripts/Infrastructure/AllocCall.py
@@ -22,9 +22,9 @@ alloc_template = """
 """
 
 
-class AllocCall (Instruction):
+class AllocCall(Instruction):
     @override
-    def __init__(self, type, num_elements, name="buf", use_malloc=False):
+    def __init__(self, type: str, num_elements: int, name: str = "buf", use_malloc: bool = False):
         """
         Creates a New allocation Call
 
@@ -55,13 +55,13 @@ class AllocCall (Instruction):
                 .replace("@{NUM}@", str(self._num_elements))
                 .replace("@{SEP}@", delim))
 
-    def set_num_elements(self, num_elements):
+    def set_num_elements(self, num_elements: int):
         self._num_elements = num_elements
 
-    def set_name(self, name):
+    def set_name(self, name: str):
         self._name = name
 
-    def set_type(self, type):
+    def set_type(self, type: str):
         self._type = type
 
     def set_use_malloc(self):
@@ -70,19 +70,19 @@ class AllocCall (Instruction):
     def set_use_calloc(self):
         self._use_malloc = False
 
-    def get_num_elements(self):
+    def get_num_elements(self) -> int:
         return self._num_elements
 
-    def get_name(self):
+    def get_name(self) -> str:
         return self._name
 
-    def get_type(self):
+    def get_type(self) -> str:
         return self._type
 
-    def get_use_malloc(self):
+    def get_use_malloc(self) -> bool:
         return self._use_malloc
 
 
-def get_free(alloc_call):
+def get_free(alloc_call: AllocCall) -> Instruction:
     assert isinstance(alloc_call, AllocCall)
-    return "free(" + alloc_call.get_name() + ");\n"
+    return Instruction("free(" + alloc_call.get_name() + ");")
diff --git a/scripts/Infrastructure/Instruction.py b/scripts/Infrastructure/Instruction.py
index 16165d5b0..17ee42ccf 100644
--- a/scripts/Infrastructure/Instruction.py
+++ b/scripts/Infrastructure/Instruction.py
@@ -10,4 +10,4 @@ class Instruction(object):
         self._str_representation = str_representation
 
     def __str__(self):
-        return self._str_representation
+        return self._str_representation + "\n"
diff --git a/scripts/Infrastructure/MPICall.py b/scripts/Infrastructure/MPICall.py
index 05f525928..0d5386803 100644
--- a/scripts/Infrastructure/MPICall.py
+++ b/scripts/Infrastructure/MPICall.py
@@ -1,14 +1,15 @@
 #! /usr/bin/python3
+import typing
 from typing_extensions import override
 
 from scripts.Infrastructure.Instruction import Instruction
 from scripts.Infrastructure.Variables import ERROR_MARKER_COMMENT
 
 
-class MPI_Call (Instruction):
+class MPI_Call(Instruction):
 
     @override
-    def __init__(self, function, args, version):
+    def __init__(self, function: str, args: typing.OrderedDict[str, str], version: str):
         self._function = function
         self._args = args
         self._version = version
@@ -27,16 +28,15 @@ class MPI_Call (Instruction):
 
         return s
 
-    def set_arg(self, arg, value):
+    def set_arg(self, arg: str, value: str):
         assert self.has_arg(arg)
         self._args[arg] = value
 
-    def has_arg(self, arg):
+    def has_arg(self, arg: str) -> bool:
         return arg in self._args
 
-    def get_version(self):
+    def get_version(self) -> str:
         return self._version
 
-    def set_has_error(self, has_error=True):
+    def set_has_error(self, has_error: bool = True):
         self._has_error = has_error
-
-- 
GitLab


From 54801c07c4f77ffd7004f8d9e4b765176b7979fe Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 13:20:56 +0100
Subject: [PATCH 08/18] added Type hints (#7) for the Template Manager and
 InstructionBlock classes

---
 scripts/Infrastructure/InstructionBlock.py | 56 +++++++++-------------
 scripts/Infrastructure/Template.py         | 18 +++----
 2 files changed, 32 insertions(+), 42 deletions(-)

diff --git a/scripts/Infrastructure/InstructionBlock.py b/scripts/Infrastructure/InstructionBlock.py
index dfb40d40a..a0119fa48 100644
--- a/scripts/Infrastructure/InstructionBlock.py
+++ b/scripts/Infrastructure/InstructionBlock.py
@@ -1,3 +1,8 @@
+from __future__ import annotations
+
+import typing
+
+from scripts.Infrastructure.Instruction import Instruction
 from scripts.Infrastructure.MPICall import MPI_Call
 
 
@@ -16,7 +21,7 @@ class InstructionBlock:
             - `__str__(self)`: Converts the InstructionBlock instance to a string, replacing placeholders.
         """
 
-    def __init__(self, name=None):
+    def __init__(self, name: str = None):
         """
         Initialize an empty InstructionBlock
 
@@ -29,7 +34,7 @@ class InstructionBlock:
         self.name = name
 
     # TODO test if op also can be a list of operations
-    def register_operation(self, op, kind='all'):
+    def register_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all'):
         """
         Registers an operation based on rank.
 
@@ -50,21 +55,9 @@ class InstructionBlock:
                 self.operations[as_int] = []
             self.operations[as_int].append(op)
 
-    def register_operations(self, ops, kind='all'):
-        """
-        Registers a list of operations based on rank.
-
-        Parameters:
-            - ops: The operations to register.
-            - kind: Rank to execute the operation ('all', 'not0', or integer).
-                - all: all Ranks execute this operation
-                - not0: all Ranks but the Root (rank 0) execute
-                - Or the integer of the rank that should execute
-        """
-        for op in ops:
-            self.register_operation(op, kind)
+    # TODO implement list part
 
-    def get_version(self):
+    def get_version(self) -> str:
         """
         Retrieves the minimum required MPI version.
         Returns:
@@ -103,7 +96,7 @@ class InstructionBlock:
 
         return result_str
 
-    def has_operation(self, kind='all', index=0):
+    def has_operation(self, kind: int | str = 'all', index: int = 0) -> bool:
         """
         Checks if the Block has an operation with the given index and kind
         Parameters:
@@ -115,10 +108,10 @@ class InstructionBlock:
         try:
             result = self.operations[kind][index]
             return True
-        except (KeyError,IndexError) as e:
+        except (KeyError, IndexError) as e:
             return False
 
-    def get_operation(self, kind='all', index=0):
+    def get_operation(self, kind: int | str = 'all', index: int = 0) -> Instruction | typing.List[Instruction]:
         """
         Retrieve the operation registered. will Raise IndexError if not present
         Parameters:
@@ -128,18 +121,10 @@ class InstructionBlock:
             str: The operation specified by kind and index
         """
         return self.operations[kind][index]
-    
-    def get_operations(self, kind='all'):
-        """
-        Retrieve all operations registered for the given kind.
-        Parameters:
-            - kind ('all','not0' or integer): which ranks should execute the operation
-        Returns:
-            str: List of all operations with given kind
-        """
-        return self.operations[kind]
 
-    def replace_operation(self, op, kind='all', index=0):
+    # todo implement list case
+
+    def replace_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all', index: int = 0):
         """
         Replace the operation registered. will Raise IndexError if not present
         Parameters:
@@ -151,7 +136,10 @@ class InstructionBlock:
             raise IndexError("Operation Not Found")
         self.operations[kind][index] = op
 
-    def insert_operation(self, op, kind='all', before_index=0):
+    # todo implement list caee
+
+    def insert_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all',
+                         before_index: int = 0):
         """
         Inserts an operation before the specified one. will Raise IndexError if not present
         Parameters:
@@ -161,9 +149,11 @@ class InstructionBlock:
         """
         if len(self.operations[kind]) < before_index:
             raise IndexError("Operation Not Found")
-        self.operations[kind].insert(before_index,op)
+        self.operations[kind].insert(before_index, op)
+
+    # todo implement list caee
 
-    def remove_operation(self, kind='all', index=0):
+    def remove_operation(self, kind: str | int = 'all', index: int = 0):
         """
         Removes the operation registered. will Raise IndexError if not present
         Parameters:
diff --git a/scripts/Infrastructure/Template.py b/scripts/Infrastructure/Template.py
index f54702605..330c671d8 100644
--- a/scripts/Infrastructure/Template.py
+++ b/scripts/Infrastructure/Template.py
@@ -71,7 +71,7 @@ class TemplateManager:
             - `get_short_descr(self)`: Retrieves the short description .
         """
 
-    def __init__(self, min_ranks=2, thread_level=None, has_finalize=True, has_init=True):
+    def __init__(self, min_ranks: int = 2, thread_level: str = None, has_finalize: bool = True, has_init: bool = True):
         """
         Initialize the TemplateManager
 
@@ -117,7 +117,7 @@ class TemplateManager:
                 .replace("@{version}@", version)
                 .replace("@{test_code}@", block_string))
 
-    def register_instruction_block(self, block):
+    def register_instruction_block(self, block: InstructionBlock):
         """
         Registers an instruction block with the template. inserting it at the end, before the mpi finalize
         Parameters:
@@ -125,7 +125,7 @@ class TemplateManager:
         """
         self._blocks.append(block)
 
-    def get_version(self):
+    def get_version(self) -> str:
         """
         Retrieves the minimum required MPI version.
         Returns:
@@ -137,7 +137,7 @@ class TemplateManager:
             max_v = max(block.get_version(), max_v)
         return max_v
 
-    def set_description(self, descr_short, descr_full):
+    def set_description(self, descr_short: str, descr_full: str):
         """
         Sets the short and full descriptions for the template.
         Parameters:
@@ -148,7 +148,7 @@ class TemplateManager:
         self._descr_short = descr_short
         # TODO one could write a function to check if short desc = filename is conforming with the naming sceme
 
-    def get_short_descr(self):
+    def get_short_descr(self) -> str:
         """
         Retrieves the short description to use as a filename.
         Returns:
@@ -157,7 +157,7 @@ class TemplateManager:
         assert self._descr_short != ""
         return self._descr_short
 
-    def get_block(self, block_name=None, idx=None):
+    def get_block(self, block_name: str = None, idx: int = None) -> InstructionBlock:
         """
         Retrieves the given Instruction Block Either by name or by index
         Raises IndexError if the specified block is not found
@@ -187,7 +187,7 @@ class TemplateManager:
 
         raise ValueError("Neither Both block name nor index is given")
 
-    def insert_block(self, new_block, after_block_name=None, after_idx=None):
+    def insert_block(self, new_block: InstructionBlock, after_block_name: str = None, after_idx: int = None):
         """
          inserts the given Instruction Block AFTER the one specified Either by name or by index
          Raises IndexError if the specified block is not found
@@ -217,7 +217,7 @@ class TemplateManager:
 
         raise ValueError("Neither Both block name nor index is given")
 
-    def remove_block(self, block_name=None, idx=None):
+    def remove_block(self, block_name: str = None, idx: int = None):
         """
          Removes the given Instruction Block Either by name or by index
          Raises IndexError if the specified block is not found
@@ -244,7 +244,7 @@ class TemplateManager:
 
         raise ValueError("Neither Both block name nor index is given")
 
-    def replace_block(self, new_block, block_name=None, idx=None):
+    def replace_block(self, new_block: InstructionBlock, block_name: str = None, idx: int = None):
         """
          Removes the given Instruction Block Either by name or by index
          Raises IndexError if the specified block is not found
-- 
GitLab


From b3054538d81d217413dd4a14bbd5f743c1eca85c Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 13:40:01 +0100
Subject: [PATCH 09/18] implemented List cases for managing list of
 Instructions (see !7)

---
 scripts/Infrastructure/InstructionBlock.py | 86 ++++++++++++++--------
 1 file changed, 55 insertions(+), 31 deletions(-)

diff --git a/scripts/Infrastructure/InstructionBlock.py b/scripts/Infrastructure/InstructionBlock.py
index a0119fa48..05b8a16b3 100644
--- a/scripts/Infrastructure/InstructionBlock.py
+++ b/scripts/Infrastructure/InstructionBlock.py
@@ -33,29 +33,35 @@ class InstructionBlock:
         assert not isinstance(name, int)
         self.name = name
 
-    # TODO test if op also can be a list of operations
     def register_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all'):
         """
         Registers an operation based on rank.
 
         Parameters:
-            - op: The operation to register.
+            - op: The operation (or list of Operations) to register.
             - kind: Rank to execute the operation ('all', 'not0', or integer).
                 - all: all Ranks execute this operation
                 - not0: all Ranks but the Root (rank 0) execute
                 - Or the integer of the rank that should execute
         """
         if kind == 'all':
-            self.operations['all'].append(op)
+            if isinstance(op, list):
+                self.operations['all'].extend(op)
+            else:
+                self.operations['all'].append(op)
         elif kind == 'not0':
-            self.operations['not0'].append(op)
+            if isinstance(op, list):
+                self.operations['not0'].extend(op)
+            else:
+                self.operations['not0'].append(op)
         else:
             as_int = int(kind)  # will Raise ValueError if not integer
             if as_int not in self.operations:
                 self.operations[as_int] = []
-            self.operations[as_int].append(op)
-
-    # TODO implement list part
+            if isinstance(op, list):
+                self.operations[as_int].extend(op)
+            else:
+                self.operations[as_int].append(op)
 
     def get_version(self) -> str:
         """
@@ -101,7 +107,7 @@ class InstructionBlock:
         Checks if the Block has an operation with the given index and kind
         Parameters:
             - kind ('all','not0' or integer): which ranks should execute the operation
-            - index (int): the index of the operation within the given kind
+            - index (int ): the index of the operation within the given kind
         Returns:
             boolean
         """
@@ -111,55 +117,73 @@ class InstructionBlock:
         except (KeyError, IndexError) as e:
             return False
 
-    def get_operation(self, kind: int | str = 'all', index: int = 0) -> Instruction | typing.List[Instruction]:
+    def get_operation(self, kind: int | str = 'all', index: str | int = 0) -> Instruction | typing.List[Instruction]:
         """
         Retrieve the operation registered. will Raise IndexError if not present
         Parameters:
             - kind ('all','not0' or integer): which ranks should execute the operation
-            - index (int): the index of the operation within the given kind
+            - index ('all' or int): the index of the operation within the given kind; 'all' means that the list of all operations for the kind is returned
         Returns:
             str: The operation specified by kind and index
         """
-        return self.operations[kind][index]
-
-    # todo implement list case
+        if index == 'all':
+            return self.operations[kind]
+        else:
+            as_int = int(index)  # will Raise ValueError if not integer
+            return self.operations[kind][as_int]
 
-    def replace_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all', index: int = 0):
+    def replace_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all',
+                          index: str | int = 0):
         """
         Replace the operation registered. will Raise IndexError if not present
         Parameters:
-            - op (str or MPICall) the new operation
+            - op the new operation or list of operations
             - kind ('all','not0' or integer): which ranks should execute the operation
-            - index (int): the index of the operation within the given kind
-        """
-        if len(self.operations[kind]) < index:
-            raise IndexError("Operation Not Found")
-        self.operations[kind][index] = op
-
-    # todo implement list caee
+            - index ('all' or int): the index of the operation within the given kind; 'all' means all operations will be replaced with the given list
+        Notes : if one wants to replace all operations one needs to provide a list
+        if one only wants to replace one operation: no list of operations is allowed
+        """
+        if index == 'all':
+            if not isinstance(op, list):
+                raise ValueError('Provide List for replacement')
+            self.operations[kind] = op
+        else:
+            as_int = int(index)  # will Raise ValueError if not integer
+            if not isinstance(op, Instruction):
+                raise ValueError('Provide Instruction')
+            if len(self.operations[kind]) < as_int:
+                raise IndexError("Operation Not Found")
+            self.operations[kind][as_int] = op
 
     def insert_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all',
                          before_index: int = 0):
         """
         Inserts an operation before the specified one. will Raise IndexError if not present
         Parameters:
-            - op (str or MPICall) the new operation
+            - op  the new operation or list of operations
             - kind ('all','not0' or integer): which ranks should execute the operation
             - index (int): the index of the operation within the given kind
         """
+        as_int = int(before_index)  # will Raise ValueError if not integer
         if len(self.operations[kind]) < before_index:
             raise IndexError("Operation Not Found")
-        self.operations[kind].insert(before_index, op)
-
-    # todo implement list caee
+        if isinstance(op, list):
+            self.operations[kind] = (
+                    self.operations[kind][0:before_index - 1] + op + self.operations[kind][before_index:])
+        else:
+            self.operations[kind].insert(before_index, op)
 
-    def remove_operation(self, kind: str | int = 'all', index: int = 0):
+    def remove_operation(self, kind: str | int = 'all', index: str | int = 0):
         """
         Removes the operation registered. will Raise IndexError if not present
         Parameters:
             - kind ('all','not0' or integer): which ranks should execute the operation
-            - index (int): the index of the operation within the given kind
+            - index ('all' or int): the index of the operation within the given kind
         """
-        if len(self.operations[kind]) < index:
-            raise IndexError("Operation Not Found")
-        del self.operations[kind][index]
+        if index == 'all':
+            self.operations[kind] = []
+        else:
+            as_int = int(index)  # will Raise ValueError if not integer
+            if len(self.operations[kind]) < index:
+                raise IndexError("Operation Not Found")
+            del self.operations[kind][index]
-- 
GitLab


From 8fb974512cc238c8eef98a3ad896be8353f91603 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 13:42:46 +0100
Subject: [PATCH 10/18] added more type hints

---
 scripts/Infrastructure/CorrectParameter.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/scripts/Infrastructure/CorrectParameter.py b/scripts/Infrastructure/CorrectParameter.py
index d4aac6405..7304b0484 100644
--- a/scripts/Infrastructure/CorrectParameter.py
+++ b/scripts/Infrastructure/CorrectParameter.py
@@ -1,4 +1,6 @@
 #! /usr/bin/python3
+from scripts.Infrastructure import MPICall
+from scripts.Infrastructure.Instruction import Instruction
 from scripts.Infrastructure.MPICallFactory import MPICallFactory
 from scripts.Infrastructure.Template import InstructionBlock
 from scripts.Infrastructure.AllocCall import AllocCall, get_free
@@ -16,13 +18,13 @@ class CorrectParameterFactory:
     def __init__(self):
         pass
 
-    def get_buffer_alloc(self):
+    def get_buffer_alloc(self)-> AllocCall:
         return AllocCall(self.dtype[0], self.buf_size, self.buf_var_name, use_malloc=False)
 
-    def get_buffer_free(self):
+    def get_buffer_free(self)->Instruction:
         return get_free(AllocCall(self.dtype[0], self.buf_size, self.buf_var_name, use_malloc=False))
 
-    def get(self, param, func=None):
+    def get(self, param:str)->str:
         if param in ["BUFFER", "buf", "buffer", "sendbuf", "recvbuf", "origin_addr"]:
             return self.buf_var_name
         if param in ["COUNT", "count", "sendcount", "recvcount", "origin_count", "target_count", "result_count"]:
@@ -96,7 +98,7 @@ class CorrectParameterFactory:
 
 
 # todo also for send and non default args
-def get_matching_recv(call):
+def get_matching_recv(call:MPICall)->MPICall:
     correct_params = CorrectParameterFactory()
     recv = MPICallFactory().mpi_recv(
         correct_params.get("BUFFER"),
-- 
GitLab


From f8da17157ed80b5f2c18d661bb3f418488b99744 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 13:53:50 +0100
Subject: [PATCH 11/18] Refactoring: set_has_error into base class

---
 scripts/Infrastructure/AllocCall.py   | 19 +++++++++++++------
 scripts/Infrastructure/Instruction.py | 10 +++++++++-
 scripts/Infrastructure/MPICall.py     |  4 +---
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/scripts/Infrastructure/AllocCall.py b/scripts/Infrastructure/AllocCall.py
index 26e8a8c3c..983993fba 100644
--- a/scripts/Infrastructure/AllocCall.py
+++ b/scripts/Infrastructure/AllocCall.py
@@ -2,6 +2,7 @@
 from typing_extensions import override
 
 from scripts.Infrastructure.Instruction import Instruction
+from scripts.Infrastructure.Variables import ERROR_MARKER_COMMENT
 
 alloc_template = """
 @{TYPE}@* @{NAME}@ = (@{TYPE}@*) @{FUNCTION}@(@{NUM}@ @{SEP}@ sizeof(@{TYPE}@)); 
@@ -34,6 +35,7 @@ class AllocCall(Instruction):
             name: name of buffer variable
             use_malloc: True: use Malloc, False: use calloc for allocation
         """
+        super().__init__("")
         self._use_malloc = use_malloc
         self._type = type
         self._num_elements = num_elements
@@ -48,12 +50,17 @@ class AllocCall(Instruction):
             delim = ','
             func = "calloc"
 
-        return (alloc_template
-                .replace("@{NAME}@", self._name)
-                .replace("@{TYPE}@", self._type)
-                .replace("@{FUNCTION}@", func)
-                .replace("@{NUM}@", str(self._num_elements))
-                .replace("@{SEP}@", delim))
+        s = (alloc_template
+             .replace("@{NAME}@", self._name)
+             .replace("@{TYPE}@", self._type)
+             .replace("@{FUNCTION}@", func)
+             .replace("@{NUM}@", str(self._num_elements))
+             .replace("@{SEP}@", delim))
+
+        if self._has_error:
+            s += ERROR_MARKER_COMMENT
+
+        return s
 
     def set_num_elements(self, num_elements: int):
         self._num_elements = num_elements
diff --git a/scripts/Infrastructure/Instruction.py b/scripts/Infrastructure/Instruction.py
index 17ee42ccf..475c19823 100644
--- a/scripts/Infrastructure/Instruction.py
+++ b/scripts/Infrastructure/Instruction.py
@@ -1,4 +1,5 @@
 #! /usr/bin/python3
+from scripts.Infrastructure.Variables import ERROR_MARKER_COMMENT
 
 
 class Instruction(object):
@@ -8,6 +9,13 @@ class Instruction(object):
 
     def __init__(self, str_representation):
         self._str_representation = str_representation
+        self._has_error = False
+
+    def set_has_error(self, has_error: bool = True):
+        self._has_error = has_error
 
     def __str__(self):
-        return self._str_representation + "\n"
+        if self._has_error:
+            return self._str_representation + ERROR_MARKER_COMMENT
+        else:
+            return self._str_representation
diff --git a/scripts/Infrastructure/MPICall.py b/scripts/Infrastructure/MPICall.py
index 0d5386803..f86987744 100644
--- a/scripts/Infrastructure/MPICall.py
+++ b/scripts/Infrastructure/MPICall.py
@@ -10,6 +10,7 @@ class MPI_Call(Instruction):
 
     @override
     def __init__(self, function: str, args: typing.OrderedDict[str, str], version: str):
+        super().__init__("")
         self._function = function
         self._args = args
         self._version = version
@@ -37,6 +38,3 @@ class MPI_Call(Instruction):
 
     def get_version(self) -> str:
         return self._version
-
-    def set_has_error(self, has_error: bool = True):
-        self._has_error = has_error
-- 
GitLab


From 15c33d89c17a3f6eb9d3d65e3a118ab424516494 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 14:02:45 +0100
Subject: [PATCH 12/18] Allowed the Instruction block to create instructions in
 place from srings for convenience

---
 scripts/Infrastructure/InstructionBlock.py | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/scripts/Infrastructure/InstructionBlock.py b/scripts/Infrastructure/InstructionBlock.py
index 05b8a16b3..ebc3d1ba3 100644
--- a/scripts/Infrastructure/InstructionBlock.py
+++ b/scripts/Infrastructure/InstructionBlock.py
@@ -33,7 +33,7 @@ class InstructionBlock:
         assert not isinstance(name, int)
         self.name = name
 
-    def register_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all'):
+    def register_operation(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all'):
         """
         Registers an operation based on rank.
 
@@ -43,7 +43,11 @@ class InstructionBlock:
                 - all: all Ranks execute this operation
                 - not0: all Ranks but the Root (rank 0) execute
                 - Or the integer of the rank that should execute
+            Note: if a str is passed as the operation, it will create a new Instruction from the given string
         """
+        if isinstance(op, str):
+            op = Instruction(op)
+
         if kind == 'all':
             if isinstance(op, list):
                 self.operations['all'].extend(op)
@@ -132,7 +136,7 @@ class InstructionBlock:
             as_int = int(index)  # will Raise ValueError if not integer
             return self.operations[kind][as_int]
 
-    def replace_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all',
+    def replace_operation(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all',
                           index: str | int = 0):
         """
         Replace the operation registered. will Raise IndexError if not present
@@ -142,20 +146,25 @@ class InstructionBlock:
             - index ('all' or int): the index of the operation within the given kind; 'all' means all operations will be replaced with the given list
         Notes : if one wants to replace all operations one needs to provide a list
         if one only wants to replace one operation: no list of operations is allowed
+        if a string is passed as the operation, it will create a new Instruction
         """
+        if isinstance(op, str):
+            op = Instruction(op)
+
         if index == 'all':
             if not isinstance(op, list):
                 raise ValueError('Provide List for replacement')
             self.operations[kind] = op
         else:
             as_int = int(index)  # will Raise ValueError if not integer
+            print(op)
             if not isinstance(op, Instruction):
                 raise ValueError('Provide Instruction')
             if len(self.operations[kind]) < as_int:
                 raise IndexError("Operation Not Found")
             self.operations[kind][as_int] = op
 
-    def insert_operation(self, op: Instruction | typing.List[Instruction], kind: str | int = 'all',
+    def insert_operation(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all',
                          before_index: int = 0):
         """
         Inserts an operation before the specified one. will Raise IndexError if not present
@@ -163,7 +172,10 @@ class InstructionBlock:
             - op  the new operation or list of operations
             - kind ('all','not0' or integer): which ranks should execute the operation
             - index (int): the index of the operation within the given kind
+        note: if str is passed as the operation, it will Create a New Instruction
         """
+        if isinstance(op, str):
+            op = Instruction(op)
         as_int = int(before_index)  # will Raise ValueError if not integer
         if len(self.operations[kind]) < before_index:
             raise IndexError("Operation Not Found")
-- 
GitLab


From e19da0fce8858221cd0f5950db7b0d9a042d4b5b Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 14:03:47 +0100
Subject: [PATCH 13/18] Simplified Local Concurrency RMA testcase

---
 scripts/errors/rma/LocalConcurrency.py | 16 +++++-----------
 1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/scripts/errors/rma/LocalConcurrency.py b/scripts/errors/rma/LocalConcurrency.py
index 152203dc6..a047c1cb8 100644
--- a/scripts/errors/rma/LocalConcurrency.py
+++ b/scripts/errors/rma/LocalConcurrency.py
@@ -18,6 +18,7 @@ from scripts.Infrastructure.Variables import ERROR_MARKER_COMMENT
 
 from typing import Tuple, List
 
+
 class LocalConcurrencyErrorRMA(ErrorGenerator):
     local_origin_addr_write = ["mpi_get", "mpi_rget"]
     local_origin_addr_read = [
@@ -88,15 +89,8 @@ class LocalConcurrencyErrorRMA(ErrorGenerator):
                 tm.register_instruction_block(alloc)
 
                 if hasconflict:
-                    if isinstance(op1.get_operation(kind=0, index=-1), MPI_Call):
-                        op1.get_operation(kind=0, index=-1).set_has_error()
-                    else:
-                        op1.replace_operation(op1.get_operation(kind=0, index=-1) + ERROR_MARKER_COMMENT, 0, 0)
-
-                    if isinstance(op2.get_operation(kind=0, index=-1), MPI_Call):
-                        op2.get_operation(kind=0, index=-1).set_has_error()
-                    else:
-                        op2.replace_operation(op2.get_operation(kind=0, index=-1) + ERROR_MARKER_COMMENT, 0, 0)
+                    op1.get_operation(kind=0, index=-1).set_has_error()
+                    op2.get_operation(kind=0, index=-1).set_has_error()
 
                 # fuse instructions blocks
                 # combined_ops = InstructionBlock("COMBINED")
@@ -106,7 +100,7 @@ class LocalConcurrencyErrorRMA(ErrorGenerator):
                 tm.register_instruction_block(op2)
 
                 tm.set_description(
-                    ("LocalConcurrency" if hasconflict else "Correct") + 
+                    ("LocalConcurrency" if hasconflict else "Correct") +
                     "-"
                     + op1.name
                     + "_"
@@ -114,7 +108,7 @@ class LocalConcurrencyErrorRMA(ErrorGenerator):
                     "full description",
                 )
                 yield tm
-                
+
                 # get RMA call
                 # rmaop = get_rma_call(function_to_check, 0)
 
-- 
GitLab


From 2e9823d8af7a4433c1558d7a78f3e193af5d90d4 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 14:05:42 +0100
Subject: [PATCH 14/18] fix wrong type hint

---
 scripts/Infrastructure/AllocCall.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/scripts/Infrastructure/AllocCall.py b/scripts/Infrastructure/AllocCall.py
index 983993fba..69303b699 100644
--- a/scripts/Infrastructure/AllocCall.py
+++ b/scripts/Infrastructure/AllocCall.py
@@ -25,7 +25,7 @@ alloc_template = """
 
 class AllocCall(Instruction):
     @override
-    def __init__(self, type: str, num_elements: int, name: str = "buf", use_malloc: bool = False):
+    def __init__(self, type: str, num_elements: str, name: str = "buf", use_malloc: bool = False):
         """
         Creates a New allocation Call
 
@@ -62,7 +62,7 @@ class AllocCall(Instruction):
 
         return s
 
-    def set_num_elements(self, num_elements: int):
+    def set_num_elements(self, num_elements: str):
         self._num_elements = num_elements
 
     def set_name(self, name: str):
@@ -77,7 +77,7 @@ class AllocCall(Instruction):
     def set_use_calloc(self):
         self._use_malloc = False
 
-    def get_num_elements(self) -> int:
+    def get_num_elements(self) -> str:
         return self._num_elements
 
     def get_name(self) -> str:
-- 
GitLab


From 1eb914fbd6bc23f48b25f845881d2c9fc5b93496 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 14:18:29 +0100
Subject: [PATCH 15/18] fix warnings about unexpected types

---
 scripts/Infrastructure/CorrectParameter.py | 2 +-
 scripts/Infrastructure/GeneratorManager.py | 8 ++++++--
 scripts/Infrastructure/InstructionBlock.py | 2 +-
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/scripts/Infrastructure/CorrectParameter.py b/scripts/Infrastructure/CorrectParameter.py
index 7304b0484..c202cb8ff 100644
--- a/scripts/Infrastructure/CorrectParameter.py
+++ b/scripts/Infrastructure/CorrectParameter.py
@@ -8,7 +8,7 @@ from scripts.Infrastructure.AllocCall import AllocCall, get_free
 
 class CorrectParameterFactory:
     # default params
-    buf_size = 10
+    buf_size = "10"
     dtype = ['int', 'MPI_INT']
     buf_size_bytes = f"{buf_size}*sizeof({dtype[0]})"
     tag = 0
diff --git a/scripts/Infrastructure/GeneratorManager.py b/scripts/Infrastructure/GeneratorManager.py
index 4752d1b33..dad021d97 100644
--- a/scripts/Infrastructure/GeneratorManager.py
+++ b/scripts/Infrastructure/GeneratorManager.py
@@ -1,9 +1,13 @@
 #! /usr/bin/python3
+from __future__ import annotations
+
 import inspect
 import os
 import importlib
 import importlib.util
 import subprocess
+import typing
+from pathlib import Path
 
 # for printing a nice progress bar
 import tqdm
@@ -65,8 +69,8 @@ class GeneratorManager:
 
         return case_name + "-" + str(num).zfill(digits_to_use) + suffix
 
-    def generate(self, outpath, filterlist_=None, print_progress_bar=True, overwrite=True, generate_full_set=False,
-                 try_compile=False, max_mpi_version=4.0, use_clang_format=True):
+    def generate(self, outpath: str | Path | os.PathLike[str], filterlist_:typing.Sequence[str]=None, print_progress_bar:bool=True, overwrite:bool=True, generate_full_set:bool=False,
+                 try_compile:bool=False, max_mpi_version:str="4.0", use_clang_format:bool=True):
         """
         Generates test cases based on the specified parameters.
         Parameters:
diff --git a/scripts/Infrastructure/InstructionBlock.py b/scripts/Infrastructure/InstructionBlock.py
index ebc3d1ba3..e6b7d28a3 100644
--- a/scripts/Infrastructure/InstructionBlock.py
+++ b/scripts/Infrastructure/InstructionBlock.py
@@ -43,7 +43,7 @@ class InstructionBlock:
                 - all: all Ranks execute this operation
                 - not0: all Ranks but the Root (rank 0) execute
                 - Or the integer of the rank that should execute
-            Note: if a str is passed as the operation, it will create a new Instruction from the given string
+        Note: if a str is passed as the operation, it will create a new Instruction from the given string
         """
         if isinstance(op, str):
             op = Instruction(op)
-- 
GitLab


From 135dbf4afbc370afb4eb13162673b5bb123894c9 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 14:27:04 +0100
Subject: [PATCH 16/18] removed the testcases to develop them in extra branches

---
 scripts/errors/coll/InvalidRank.py       |  35 ------
 scripts/errors/coll/__init__.py          |   0
 scripts/errors/pt2pt/InvalidBuf.py       |  96 ----------------
 scripts/errors/pt2pt/InvalidComm.py      | 107 -----------------
 scripts/errors/pt2pt/InvalidRank.py      |  58 ----------
 scripts/errors/pt2pt/InvalidRequest.py   |  67 -----------
 scripts/errors/pt2pt/InvalidTag.py       |  80 -------------
 scripts/errors/pt2pt/LocalConcurrency.py |  59 ----------
 scripts/errors/pt2pt/MessageRace.py      | 100 ----------------
 scripts/errors/pt2pt/__init__.py         |   0
 scripts/errors/rma/LocalConcurrency.py   | 140 -----------------------
 11 files changed, 742 deletions(-)
 delete mode 100644 scripts/errors/coll/InvalidRank.py
 delete mode 100644 scripts/errors/coll/__init__.py
 delete mode 100644 scripts/errors/pt2pt/InvalidBuf.py
 delete mode 100644 scripts/errors/pt2pt/InvalidComm.py
 delete mode 100644 scripts/errors/pt2pt/InvalidRank.py
 delete mode 100644 scripts/errors/pt2pt/InvalidRequest.py
 delete mode 100644 scripts/errors/pt2pt/InvalidTag.py
 delete mode 100644 scripts/errors/pt2pt/LocalConcurrency.py
 delete mode 100644 scripts/errors/pt2pt/MessageRace.py
 delete mode 100644 scripts/errors/pt2pt/__init__.py
 delete mode 100644 scripts/errors/rma/LocalConcurrency.py

diff --git a/scripts/errors/coll/InvalidRank.py b/scripts/errors/coll/InvalidRank.py
deleted file mode 100644
index 3033e1bfa..000000000
--- a/scripts/errors/coll/InvalidRank.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_send_recv_template, get_collective_template
-
-class InvalidRankErrorColl(ErrorGenerator):
-    invalid_ranks = ["-1", "nprocs", "MPI_PROC_NULL"]
-    functions_to_use = ["mpi_reduce", "mpi_bcast"]
-
-    def __init__(self):
-        pass
-
-
-    def get_feature(self):
-        return ["COLL"]
-
-    def generate(self, generate_full_set):
-
-        for func_to_use in self.functions_to_use:
-            for rank_to_use in self.invalid_ranks:
-                tm = get_collective_template(func_to_use, seperate=False)
-                arg_to_replace = "root"
-
-                tm.set_description("InvalidParam-Rank-"+func_to_use, "Invalid Rank: %s" % rank_to_use)
-
-                tm.get_block("MPICALL").get_operation(kind='all', index=0).set_arg(arg_to_replace, rank_to_use)
-                tm.get_block("MPICALL").get_operation(kind='all', index=0).set_has_error()
-
-                yield tm
-            if not generate_full_set:
-                return
diff --git a/scripts/errors/coll/__init__.py b/scripts/errors/coll/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/scripts/errors/pt2pt/InvalidBuf.py b/scripts/errors/pt2pt/InvalidBuf.py
deleted file mode 100644
index f4ba60378..000000000
--- a/scripts/errors/pt2pt/InvalidBuf.py
+++ /dev/null
@@ -1,96 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_send_recv_template
-
-from itertools import chain
-
-
-class InvalidBufErrorP2P(ErrorGenerator):
-    invalid_bufs = [CorrectParameterFactory().buf_var_name, "NULL"]
-    send_funcs = ["mpi_send",
-                  "mpi_isend", "mpi_ssend", "mpi_issend", "mpi_rsend", "mpi_irsend", "mpi_bsend", "mpi_ibsend",
-                  "mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init", "mpi_psend_init",
-                  ]
-
-    recv_funcs = ["mpi_recv", "mpi_irecv", "mpi_recv_init", "mpi_precv_init"]
-
-    sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate_impl(self, send_func, recv_func, check_receive):
-
-        for buf_to_use in self.invalid_bufs:
-            tm = get_send_recv_template(send_func, recv_func)
-
-            if buf_to_use == CorrectParameterFactory().buf_var_name:
-                if tm.get_block("alloc").has_operation(kind='all', index=1) and check_receive:
-                    name = tm.get_block("alloc").get_operation(kind='all', index=1).get_name()
-                    type = tm.get_block("alloc").get_operation(kind='all', index=1).get_type()
-                    tm.get_block("alloc").replace_operation(
-                        CorrectParameterFactory.dtype[0] + "* " + name + ";", kind='all', index=1)
-                else:
-                    tm.get_block("alloc").replace_operation(
-                        CorrectParameterFactory.dtype[0] + "* " + CorrectParameterFactory.buf_var_name + ";")
-                # without allocation: usage is undefined behaviour
-
-            if check_receive:
-                tm.set_description("InvalidParam-Buffer-" + recv_func, "Invalid Buffer: %s" % buf_to_use)
-            else:
-                tm.set_description("InvalidParam-Buffer-" + send_func, "Invalid Buffer: %s" % buf_to_use)
-
-            if check_receive:
-                if tm.get_block("MPICALL").get_operation(kind=0, index=0).has_arg("buf"):
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_arg("buf", buf_to_use)
-                else:
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_arg("recvbuf", buf_to_use)
-                tm.get_block("MPICALL").get_operation(kind=0, index=0).set_has_error()
-            else:
-                if tm.get_block("MPICALL").get_operation(kind=1, index=0).has_arg("buf"):
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_arg("buf", buf_to_use)
-                else:
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_arg("recvbuf", buf_to_use)
-                tm.get_block("MPICALL").get_operation(kind=1, index=0).set_has_error()
-
-            yield tm
-
-    def generate(self, generate_full_set):
-        for func in self.send_funcs:
-            yield from self.generate_impl(func, 'mpi_irecv', False)
-            if not generate_full_set:
-                return
-        for func in self.recv_funcs:
-            yield from self.generate_impl("mpi_send", func, True)
-
-        yield from self.generate_impl("mpi_sendrecv", "mpi_sendrecv", True)
-        yield from self.generate_impl("mpi_sendrecv", "mpi_sendrecv", False)
-        yield from self.generate_impl("mpi_sendrecv_replace", "mpi_sendrecv_replace", True)
-
-
-class MessageRaceErrorSendRecv(ErrorGenerator):
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate(self, generate_full_set):
-
-        for buf_to_use in ["buf", "MPI_IN_PLACE"]:
-            tm = get_send_recv_template("mpi_sendrecv", "mpi_sendrecv")
-            tm.set_description("InvalidParam-Buffer-mpi_sendrecv", "send and recv buffer must be disjoint in sendrecv")
-
-            for k in [0, 1]:
-                tm.get_block("MPICALL").get_operation(kind=k, index=0).set_arg("recvbuf", buf_to_use)
-                tm.get_block("MPICALL").get_operation(kind=k, index=0).set_has_error()
-            yield tm
diff --git a/scripts/errors/pt2pt/InvalidComm.py b/scripts/errors/pt2pt/InvalidComm.py
deleted file mode 100644
index 24a41046a..000000000
--- a/scripts/errors/pt2pt/InvalidComm.py
+++ /dev/null
@@ -1,107 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_send_recv_template, get_communicator, get_intercomm
-
-from itertools import chain
-
-sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
-
-
-class InvalidCommErrorP2P(ErrorGenerator):
-    invalid_comm = ["MPI_COMM_NULL", "NULL"]
-
-    missmatching_comms = ["MPI_COMM_SELF", "mpi_comm_dup", "mpi_comm_dup_with_info", "mpi_comm_idup",
-                          "mpi_comm_idup_with_info", "mpi_comm_create", "mpi_comm_create_group", "mpi_comm_split",
-                          "mpi_comm_split_type", "mpi_comm_create_from_group"
-                          ]
-    intercomms = ["mpi_intercomm_create", "mpi_intercomm_merge", "mpi_intercomm_create_from_groups"]
-
-    # as extended testcases
-
-    comms_to_check = invalid_comm + missmatching_comms + intercomms
-
-    functions_to_check = ["mpi_send",
-                          "mpi_recv", "mpi_irecv",
-                          "mpi_isend", "mpi_ssend", "mpi_issend", "mpi_rsend", "mpi_irsend", "mpi_bsend", "mpi_ibsend",
-                          "mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init", "mpi_psend_init",
-                          "mpi_precv_init", "mpi_recv_init"
-                          ] + sendrecv_funcs
-
-    recv_funcs = ["mpi_recv", "mpi_irecv", "mpi_recv_init", "mpi_precv_init"] + sendrecv_funcs
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate(self, generate_full_set):
-
-        for send_func in self.functions_to_check:
-            for comm_to_use in self.comms_to_check:
-
-                check_receive = False
-                recv_func = "mpi_irecv"
-                if send_func in self.recv_funcs:
-                    check_receive = True
-                    recv_func = send_func
-                    send_func = "mpi_send"
-                    if recv_func in sendrecv_funcs:
-                        send_func = recv_func
-
-                tm = get_send_recv_template(send_func, recv_func)
-
-                if comm_to_use in self.missmatching_comms and comm_to_use != "MPI_COMM_SELF":
-                    b = get_communicator(comm_to_use, comm_to_use)
-                    tm.insert_block(b, after_block_name="alloc")
-                if comm_to_use in self.intercomms:
-                    b = get_intercomm(comm_to_use, comm_to_use)
-                    tm.insert_block(b, after_block_name="alloc")
-
-                error_string = "ParamMatching"
-                if comm_to_use in self.invalid_comm:
-                    error_string = "InvalidParam"
-
-                if check_receive:
-                    if comm_to_use in self.missmatching_comms and recv_func == "mpi_irecv":
-                        # combination repeated
-                        continue
-                    tm.set_description(error_string + "-Comm-" + recv_func, "Invalid Rank: %s" % comm_to_use)
-                else:
-                    tm.set_description(error_string + "-Comm-" + send_func, "Invalid Rank: %s" % comm_to_use)
-
-                if check_receive:
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_arg("comm", comm_to_use)
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_has_error()
-                    if comm_to_use in self.missmatching_comms:
-                        # missmatch is between both
-                        tm.get_block("MPICALL").get_operation(kind=1, index=0).set_has_error()
-                else:
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_arg("comm", comm_to_use)
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_has_error()
-                    if comm_to_use in self.missmatching_comms:
-                        # missmatch is between both
-                        tm.get_block("MPICALL").get_operation(kind=0, index=0).set_has_error()
-
-                # an intercomm has only one rank (the other group)
-                if comm_to_use in self.intercomms and not comm_to_use == "mpi_intercomm_merge":
-                    # intercomm merge results in an equivalent comm again
-                    if tm.get_block("MPICALL").get_operation(kind=0, index=0).has_arg("source"):
-                        tm.get_block("MPICALL").get_operation(kind=0, index=0).set_arg("source", "0")
-                    if tm.get_block("MPICALL").get_operation(kind=1, index=0).has_arg("source"):
-                        tm.get_block("MPICALL").get_operation(kind=1, index=0).set_arg("source", "0")
-
-                if comm_to_use in self.missmatching_comms + self.intercomms and comm_to_use != "MPI_COMM_SELF":
-                    b = InstructionBlock("comm_free")
-                    b.register_operation(MPICallFactory().mpi_comm_free("&" + comm_to_use))
-                    tm.register_instruction_block(b)
-
-                yield tm
-            # end for comm to check
-            if not generate_full_set:
-                return
diff --git a/scripts/errors/pt2pt/InvalidRank.py b/scripts/errors/pt2pt/InvalidRank.py
deleted file mode 100644
index 95f6db52d..000000000
--- a/scripts/errors/pt2pt/InvalidRank.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_send_recv_template
-
-from itertools import chain
-
-
-class InvalidRankErrorP2P(ErrorGenerator):
-    invalid_ranks = ["-1", "nprocs", "MPI_PROC_NULL"]
-    send_funcs = ["mpi_send",
-                  "mpi_isend", "mpi_ssend", "mpi_issend", "mpi_rsend", "mpi_irsend", "mpi_bsend", "mpi_ibsend",
-                  "mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init", "mpi_psend_init"
-                  ]
-    recv_funcs = ["mpi_recv", "mpi_irecv", "mpi_recv_init", "mpi_precv_init"]
-
-    sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate_impl(self, send_func, recv_func, check_receive):
-        for rank_to_use in self.invalid_ranks:
-            tm = get_send_recv_template(send_func, recv_func)
-
-            if check_receive:
-                tm.set_description("InvalidParam-Rank-" + recv_func, "Invalid Rank: %s" % rank_to_use)
-            else:
-                tm.set_description("InvalidParam-Rank-" + send_func, "Invalid Rank: %s" % rank_to_use)
-
-            if check_receive:
-                tm.get_block("MPICALL").get_operation(kind=0, index=0).set_arg("source", rank_to_use)
-                tm.get_block("MPICALL").get_operation(kind=0, index=0).set_has_error()
-            else:
-                tm.get_block("MPICALL").get_operation(kind=1, index=0).set_arg("dest", rank_to_use)
-                tm.get_block("MPICALL").get_operation(kind=1, index=0).set_has_error()
-
-            yield tm
-
-    def generate(self, generate_full_set):
-
-        for send_func in self.send_funcs:
-            yield from self.generate_impl(send_func, "mpi_irecv", False)
-            if not generate_full_set:
-                return
-        for func in self.recv_funcs:
-            yield from self.generate_impl("mpi_send", func, True)
-
-        for func in self.sendrecv_funcs:
-            yield from self.generate_impl(func, func, True)
-            yield from self.generate_impl(func, func, False)
diff --git a/scripts/errors/pt2pt/InvalidRequest.py b/scripts/errors/pt2pt/InvalidRequest.py
deleted file mode 100644
index d18888778..000000000
--- a/scripts/errors/pt2pt/InvalidRequest.py
+++ /dev/null
@@ -1,67 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_send_recv_template
-
-from itertools import chain
-
-
-class InvalidRequestErrorP2P(ErrorGenerator):
-    invalid_requests = ["MPI_REQUEST_NULL",  # probably triggers compiler warning
-                        "NULL"]
-    functions_to_check = ["mpi_irecv", "mpi_isend",
-                          "mpi_issend", "mpi_irsend", "mpi_ibsend",
-                          "mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init", "mpi_psend_init",
-                          "mpi_precv_init", "mpi_recv_init"
-                          ]
-
-    recv_funcs = ["mpi_irecv", "mpi_recv_init", "mpi_precv_init"]
-
-    def __init__(self):
-        pass
-
-    def get_num_errors(self):
-        # send + receive = only check the first two functions
-        return len(self.invalid_requests) * 2
-
-    # the number of errors to produce in the extended mode (all possible combinations)
-    def get_num_errors_extended(self):
-        return len(self.invalid_requests) * len(self.functions_to_check)
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate(self, generate_full_set):
-
-        for send_func in self.functions_to_check:
-            for req_to_use in self.invalid_requests:
-
-                check_receive = False
-                recv_func = "mpi_irecv"
-                if send_func in self.recv_funcs:
-                    check_receive = True
-                    recv_func = send_func
-                    send_func = "mpi_isend"
-
-                tm = get_send_recv_template(send_func, recv_func)
-
-                if check_receive:
-                    tm.set_description("InvalidParam-Request-" + recv_func, "Invalid Request: %s" % req_to_use)
-                else:
-                    tm.set_description("InvalidParam-Request-" + send_func, "Invalid Request: %s" % req_to_use)
-
-                if check_receive:
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_arg("request", req_to_use)
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_has_error()
-                else:
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_arg("request", req_to_use)
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_has_error()
-
-                yield tm
-
-            if not generate_full_set:
-                return
diff --git a/scripts/errors/pt2pt/InvalidTag.py b/scripts/errors/pt2pt/InvalidTag.py
deleted file mode 100644
index 74041139b..000000000
--- a/scripts/errors/pt2pt/InvalidTag.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_send_recv_template
-
-from itertools import chain
-
-
-class InvalidTagErrorP2P(ErrorGenerator):
-    invalid_tags = ["-1", "MPI_TAG_UB+1", CorrectParameterFactory.tag * 2, "MPI_ANY_TAG"]
-    send_funcs = ["mpi_send",
-                  "mpi_isend", "mpi_ssend", "mpi_issend", "mpi_rsend", "mpi_irsend", "mpi_bsend", "mpi_ibsend",
-                  "mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init", "mpi_psend_init",
-                  ]
-
-    recv_funcs = ["mpi_recv", "mpi_irecv", "mpi_recv_init", "mpi_precv_init"]
-    sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate_impl(self, send_func, recv_func, check_receive):
-        for tag_to_use in self.invalid_tags:
-            tm = get_send_recv_template(send_func, recv_func)
-
-            error_string = "InvalidParam"
-            if tag_to_use == CorrectParameterFactory.tag * 2:
-                error_string = "ParamMatching"
-
-            if check_receive:
-                if tag_to_use == "MPI_ANY_TAG":
-                    # correct case
-                    continue
-                if tag_to_use == CorrectParameterFactory().tag * 2 and recv_func == "mpi_irecv":
-                    # combination repeated
-                    continue
-                tm.set_description(error_string + "-Tag-" + recv_func, "Invalid Rank: %s" % tag_to_use)
-            else:
-                tm.set_description(error_string + "-Tag-" + send_func, "Invalid Rank: %s" % tag_to_use)
-
-            if check_receive:
-                if tm.get_block("MPICALL").get_operation(kind=0, index=0).has_arg("tag"):
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_arg("tag", tag_to_use)
-                else:
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_arg("recvtag", tag_to_use)
-                tm.get_block("MPICALL").get_operation(kind=0, index=0).set_has_error()
-                if tag_to_use == CorrectParameterFactory.tag * 2:
-                    # missmatch is between both
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_has_error()
-            else:
-                if tm.get_block("MPICALL").get_operation(kind=1, index=0).has_arg("tag"):
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_arg("tag", tag_to_use)
-                else:
-                    tm.get_block("MPICALL").get_operation(kind=1, index=0).set_arg("sendtag", tag_to_use)
-                tm.get_block("MPICALL").get_operation(kind=1, index=0).set_has_error()
-                if tag_to_use == CorrectParameterFactory.tag * 2:
-                    # missmatch is between both
-                    tm.get_block("MPICALL").get_operation(kind=0, index=0).set_has_error()
-
-            yield tm
-
-    def generate(self, generate_full_set):
-
-        for send_func in self.send_funcs:
-            yield from self.generate_impl(send_func, "mpi_irecv", False)
-            if not generate_full_set:
-                return
-        for recv_func in self.recv_funcs:
-            yield from self.generate_impl("mpi_send", recv_func, True)
-
-        for func in self.sendrecv_funcs:
-            yield from self.generate_impl(func, func, True)
-            yield from self.generate_impl(func, func, False)
diff --git a/scripts/errors/pt2pt/LocalConcurrency.py b/scripts/errors/pt2pt/LocalConcurrency.py
deleted file mode 100644
index a12ca70e5..000000000
--- a/scripts/errors/pt2pt/LocalConcurrency.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_send_recv_template
-
-from itertools import chain
-
-from scripts.Infrastructure.Variables import ERROR_MARKER_COMMENT
-
-sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
-
-
-class LocalConcurrencyErrorP2P(ErrorGenerator):
-    functions_to_check = ["mpi_irecv",
-                          "mpi_isend", "mpi_issend", "mpi_irsend", "mpi_ibsend",
-                          "mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init", "mpi_psend_init",
-                          "mpi_precv_init", "mpi_recv_init"
-                          ]
-    recv_funcs = ["mpi_irecv", "mpi_recv_init", "mpi_precv_init"]
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate(self, generate_full_set):
-        for send_func in self.functions_to_check:
-
-            check_receive = False
-            recv_func = "mpi_irecv"
-            if send_func in self.recv_funcs:
-                check_receive = True
-                recv_func = send_func
-                send_func = "mpi_isend"
-
-            tm = get_send_recv_template(send_func, recv_func)
-
-            if check_receive:
-                tm.set_description("LocalConcurrency-receive-" + recv_func,
-                                   "usage of receive buffer before operation is completed")
-            else:
-                tm.set_description("LocalConcurrency-send-" + send_func,
-                                   "usage of send buffer before operation is completed")
-
-            if check_receive:
-                tm.get_block("MPICALL").get_operation(kind=0, index=0).set_has_error()
-                tm.get_block("MPICALL").register_operation("buf[2]=1;" + ERROR_MARKER_COMMENT, kind=1)
-            else:
-                tm.get_block("MPICALL").get_operation(kind=1, index=0).set_has_error()
-                tm.get_block("MPICALL").register_operation("buf[2]=1;" + ERROR_MARKER_COMMENT, kind=1)
-
-            yield tm
-            if not generate_full_set:
-                return
diff --git a/scripts/errors/pt2pt/MessageRace.py b/scripts/errors/pt2pt/MessageRace.py
deleted file mode 100644
index e102fe09c..000000000
--- a/scripts/errors/pt2pt/MessageRace.py
+++ /dev/null
@@ -1,100 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_send_recv_template
-
-from itertools import chain
-
-
-class MessageRaceErrorAnyTag(ErrorGenerator):
-    # TODO do we need to generate it for all combinations of send and recv?
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate(self, generate_full_set):
-        tm = TemplateManager()
-        tm.set_description("MsgRace-ANY_TAG", "order of messages is indeterministic, may lead to a deadlock")
-
-        b = InstructionBlock("alloc")
-        b.register_operation(CorrectParameterFactory().get_buffer_alloc())
-        tm.register_instruction_block(b)
-
-        b = InstructionBlock("MPICALL")
-        # send part
-        b.register_operation("for(int i =0; i < 10; ++i) {", kind=1)
-        b.register_operation("buf[0]=i;", kind=1)
-        send_call = CorrectMPICallFactory().mpi_send()
-        send_call.set_arg("tag", "i")
-        b.register_operation(send_call, kind=1)
-        b.register_operation("}", kind=1)
-        # recv part
-        b.register_operation("for(int i =0; i < 10; ++i) {", kind=0)
-        recv_call = CorrectMPICallFactory().mpi_recv()
-        recv_call.set_arg("tag", "MPI_ANY_TAG")
-        b.register_operation(recv_call, kind=0)
-        b.register_operation("if(buf[0]!=i){", kind=0)
-        additional_recv = CorrectMPICallFactory().mpi_recv()
-        additional_recv.set_has_error()  # additional recv leads to deadlock
-        b.register_operation(additional_recv, kind=0)
-        b.register_operation(" }", kind=0)  # end if
-        b.register_operation("}", kind=0)  # end for
-
-        tm.register_instruction_block(b)
-
-        b = InstructionBlock("free")
-        b.register_operation(CorrectParameterFactory().get_buffer_free())
-        tm.register_instruction_block(b)
-
-        yield tm
-
-
-class MessageRaceErrorAnysource(ErrorGenerator):
-    # TODO do we need to generate it for all combinations of send and recv?
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["P2P"]
-
-    def generate(self, generate_full_set):
-        tm = TemplateManager(min_ranks=3)
-        tm.set_description("MsgRace-ANY_SOURCE", "order of messages is indeterministic, may lead to a deadlock")
-
-        b = InstructionBlock("alloc")
-        b.register_operation(CorrectParameterFactory().get_buffer_alloc())
-        tm.register_instruction_block(b)
-
-        b = InstructionBlock("MPICALL")
-        # send part
-        b.register_operation("buf[0]=rank;", kind='not0')
-        send_call = CorrectMPICallFactory().mpi_send()
-        b.register_operation(send_call, kind='not0')
-
-        # recv part
-        b.register_operation("for(int i =1; i < nprocs; ++i) {", kind=0)
-        recv_call = CorrectMPICallFactory().mpi_recv()
-        recv_call.set_arg("source", "MPI_ANY_SOURCE")
-        b.register_operation(recv_call, kind=0)
-        b.register_operation("if(buf[0]!=i){", kind=0)
-        additional_recv = CorrectMPICallFactory().mpi_recv()
-        additional_recv.set_has_error()  # additional recv leads to deadlock
-        b.register_operation(additional_recv, kind=0)
-        b.register_operation(" }", kind=0)  # end if
-        b.register_operation("}", kind=0)  # end for
-
-        tm.register_instruction_block(b)
-
-        b = InstructionBlock("free")
-        b.register_operation(CorrectParameterFactory().get_buffer_free())
-        tm.register_instruction_block(b)
-
-        yield tm
diff --git a/scripts/errors/pt2pt/__init__.py b/scripts/errors/pt2pt/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/scripts/errors/rma/LocalConcurrency.py b/scripts/errors/rma/LocalConcurrency.py
deleted file mode 100644
index a047c1cb8..000000000
--- a/scripts/errors/rma/LocalConcurrency.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#! /usr/bin/python3
-
-from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
-from scripts.Infrastructure.InstructionBlock import InstructionBlock
-from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
-from scripts.Infrastructure.CorrectParameter import (
-    CorrectParameterFactory,
-    get_matching_recv,
-)
-from scripts.Infrastructure.Template import TemplateManager
-from scripts.Infrastructure.TemplateFactory import get_allocated_window, get_rma_call
-from scripts.Infrastructure.AllocCall import AllocCall
-from scripts.Infrastructure.MPICall import MPI_Call
-
-import itertools
-
-from scripts.Infrastructure.Variables import ERROR_MARKER_COMMENT
-
-from typing import Tuple, List
-
-
-class LocalConcurrencyErrorRMA(ErrorGenerator):
-    local_origin_addr_write = ["mpi_get", "mpi_rget"]
-    local_origin_addr_read = [
-        "mpi_put",
-        "mpi_rput",
-        "mpi_accumulate",
-        "mpi_raccumulate",
-        "mpi_get_accumulate",
-        "mpi_rget_accumulate",
-        "mpi_fetch_and_op",
-        "mpi_compare_and_swap",
-    ]
-    functions_to_check = ["mpi_put", "mpi_get", "mpi_rput", "mpi_rget"]
-
-    # recv_funcs = ["mpi_irecv", "mpi_recv_init", "mpi_precv_init"]
-
-    def __init__(self):
-        pass
-
-    def get_feature(self):
-        return ["RMA"]
-
-    def generate(self, generate_full_set):
-
-        cf = CorrectParameterFactory()
-        cfmpi = CorrectMPICallFactory()
-
-        mpi_buf_read = [
-            get_rma_call("mpi_put", 0),
-            get_rma_call("mpi_rput", 0),
-            get_rma_call("mpi_accumulate", 0),
-            get_rma_call("mpi_raccumulate", 0),
-            get_rma_call("mpi_get_accumulate", 0),
-            get_rma_call("mpi_rget_accumulate", 0),
-            get_rma_call("mpi_fetch_and_op", 0),
-            get_rma_call("mpi_compare_and_swap", 0),
-        ]
-        mpi_buf_write = [get_rma_call("mpi_get", 0), get_rma_call("mpi_rget", 0)]
-
-        bufread = InstructionBlock("bufread")
-        bufread.register_operation(f'printf("buf is %d\\n", {cf.buf_var_name}[1]);', 0)
-        bufwrite = InstructionBlock("write")
-        bufwrite.register_operation(f'{cf.buf_var_name}[1] = 42;', 0)
-
-        # 7 possible combinations of local buffer accesses (hasconflict = True | False)
-        local_access_combinations: List[Tuple[List[InstructionBlock], List[InstructionBlock], bool]] = [
-            (mpi_buf_read, [bufread], False),
-            (mpi_buf_read, [bufwrite], True),
-            (mpi_buf_write, [bufread], True),
-            (mpi_buf_write, [bufwrite], True),
-            (mpi_buf_read, mpi_buf_read, False),
-            (mpi_buf_read, mpi_buf_write, True),
-            (mpi_buf_write, mpi_buf_write, True),
-        ]
-
-        for ops1, ops2, hasconflict in local_access_combinations:
-            for (op1, op2) in itertools.product(ops1, ops2):
-                tm = TemplateManager()
-                # window allocation boilerplate
-                b = get_allocated_window("mpi_win_create", "win", "winbuf", "int", "2")
-                tm.register_instruction_block(b)
-
-                # local buffer allocation
-                alloc = InstructionBlock("alloc")
-                alloc.register_operation(
-                    AllocCall(cf.dtype[0], cf.buf_size, cf.buf_var_name)
-                )
-                tm.register_instruction_block(alloc)
-
-                if hasconflict:
-                    op1.get_operation(kind=0, index=-1).set_has_error()
-                    op2.get_operation(kind=0, index=-1).set_has_error()
-
-                # fuse instructions blocks
-                # combined_ops = InstructionBlock("COMBINED")
-                # combined_ops.register_operations(op1.get_operations(kind=0), kind=0)
-                # combined_ops.register_operations(op2.get_operations(kind=0), kind=0)
-                tm.register_instruction_block(op1)
-                tm.register_instruction_block(op2)
-
-                tm.set_description(
-                    ("LocalConcurrency" if hasconflict else "Correct") +
-                    "-"
-                    + op1.name
-                    + "_"
-                    + op2.name,
-                    "full description",
-                )
-                yield tm
-
-                # get RMA call
-                # rmaop = get_rma_call(function_to_check, 0)
-
-                # tm.register_instruction_block(rmaop)
-
-                # bufstring = ""
-                # if bufop == "read":  # local buffer access is read
-                #     bufstring = f'printf("buf is %d\\n", {cf.buf_var_name}[1]);'
-                #     # if RMA call performs local buffer write, this is a race, otherwise no race
-                #     if function_to_check in local_origin_addr_write:
-                #         bufstring += ERROR_MARKER_COMMENT
-                #         # mark RMA call as erroneous
-                #         tm.get_block("RMACALL").get_operation(
-                #             kind=0, index=-1
-                #         ).set_has_error()
-
-                # if bufop == "write":
-                #     # a buffer write is always a race
-                #     bufstring = f"{cf.buf_var_name}[1] = 42;" + ERROR_MARKER_COMMENT
-                #     # mark RMA call as erroneous
-                #     tm.get_block("RMACALL").get_operation(
-                #         kind=0, index=-1
-                #     ).set_has_error()
-
-                # # finally register buffer access
-                # tm.get_block("RMACALL").register_operation(bufstring, 0)
-
-            # if not generate_full_set:
-            #     return
-- 
GitLab


From 636ff42fad4c6efd6b06f714a5fc9c23bd9e5f0f Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 16:00:56 +0100
Subject: [PATCH 17/18] added get method to MPI call factory, so that one can
 get an MPI call from a string (basically a wrapper for getattr)

---
 scripts/Infrastructure/MPIAPIInfo/GenerateCallFactory.py | 8 ++++++++
 scripts/Infrastructure/MPICallFactory.py                 | 7 +++++++
 2 files changed, 15 insertions(+)

diff --git a/scripts/Infrastructure/MPIAPIInfo/GenerateCallFactory.py b/scripts/Infrastructure/MPIAPIInfo/GenerateCallFactory.py
index 3618e8b0c..f519427be 100644
--- a/scripts/Infrastructure/MPIAPIInfo/GenerateCallFactory.py
+++ b/scripts/Infrastructure/MPIAPIInfo/GenerateCallFactory.py
@@ -18,6 +18,10 @@ from scripts.Infrastructure.MPICall import MPI_Call
 
 class MPICallFactory:
 
+    def get(self, func: str, *args):
+        f_to_call = getattr(self, func)
+        return f_to_call(*args)
+
 """
 
 correct_call_factory_header="""
@@ -26,6 +30,10 @@ from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory
 
 class CorrectMPICallFactory:
 
+    def get(self, func: str, *args):
+        f_to_call = getattr(self, func)
+        return f_to_call(*args)
+
 """
 template_correct = """
     def @{FUNC_KEY}@(self):
diff --git a/scripts/Infrastructure/MPICallFactory.py b/scripts/Infrastructure/MPICallFactory.py
index 474919f1f..442192c9c 100644
--- a/scripts/Infrastructure/MPICallFactory.py
+++ b/scripts/Infrastructure/MPICallFactory.py
@@ -6,6 +6,10 @@ from scripts.Infrastructure.MPICall import MPI_Call
 
 class MPICallFactory:
 
+    def get(self, func: str, *args):
+        f_to_call = getattr(self, func)
+        return f_to_call(*args)
+
     def mpi_abort(self, *args):
         return MPI_Call("MPI_Abort", OrderedDict([("comm", args[0]), ("errorcode", args[1]), ]), "1.0")
 
@@ -2174,6 +2178,9 @@ from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory
 
 class CorrectMPICallFactory:
 
+    def get(self, func: str, *args):
+        f_to_call = getattr(self, func)
+        return f_to_call(*args)
 
     def mpi_abort(self):
         correct_params = CorrectParameterFactory()
-- 
GitLab


From eb6b0e3c2123cd550280ebb8d4997d2a2a3b87c0 Mon Sep 17 00:00:00 2001
From: Tim Jammer <tim.jammer@tu-darmstadt.de>
Date: Mon, 5 Feb 2024 16:39:44 +0100
Subject: [PATCH 18/18] Renamed operation with instruction (#6)

---
 scripts/ExampleUsage.py                    |   6 +-
 scripts/Infrastructure/InstructionBlock.py |  16 +-
 scripts/Infrastructure/TemplateFactory.py  | 235 ++++++++++++---------
 3 files changed, 143 insertions(+), 114 deletions(-)

diff --git a/scripts/ExampleUsage.py b/scripts/ExampleUsage.py
index 02146e85f..12c0122f1 100644
--- a/scripts/ExampleUsage.py
+++ b/scripts/ExampleUsage.py
@@ -18,7 +18,7 @@ class Invalid_negative_rank_error:
 
         # include the buffer allocation in the template (all ranks execute it)
         alloc_block = InstructionBlock("alloc")
-        alloc_block.register_operation(correct_params.get_buffer_alloc())
+        alloc_block.register_instruction(correct_params.get_buffer_alloc())
         tm.register_instruction_block(alloc_block)
 
         send = MPI_Call_Factory().mpi_send(
@@ -33,9 +33,9 @@ class Invalid_negative_rank_error:
 
         b = InstructionBlock()
         # only rank 0 execute the send
-        b.register_operation(send, 0)
+        b.register_instruction(send, 0)
         # only rank 1 execute the recv
-        b.register_operation(get_matching_recv(send), 1)
+        b.register_instruction(get_matching_recv(send), 1)
         tm.register_instruction_block(b)
 
         return tm
diff --git a/scripts/Infrastructure/InstructionBlock.py b/scripts/Infrastructure/InstructionBlock.py
index e6b7d28a3..f30545dea 100644
--- a/scripts/Infrastructure/InstructionBlock.py
+++ b/scripts/Infrastructure/InstructionBlock.py
@@ -33,7 +33,7 @@ class InstructionBlock:
         assert not isinstance(name, int)
         self.name = name
 
-    def register_operation(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all'):
+    def register_instruction(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all'):
         """
         Registers an operation based on rank.
 
@@ -106,7 +106,7 @@ class InstructionBlock:
 
         return result_str
 
-    def has_operation(self, kind: int | str = 'all', index: int = 0) -> bool:
+    def has_instruction(self, kind: int | str = 'all', index: int = 0) -> bool:
         """
         Checks if the Block has an operation with the given index and kind
         Parameters:
@@ -121,7 +121,7 @@ class InstructionBlock:
         except (KeyError, IndexError) as e:
             return False
 
-    def get_operation(self, kind: int | str = 'all', index: str | int = 0) -> Instruction | typing.List[Instruction]:
+    def get_instruction(self, kind: int | str = 'all', index: str | int = 0) -> Instruction | typing.List[Instruction]:
         """
         Retrieve the operation registered. will Raise IndexError if not present
         Parameters:
@@ -136,8 +136,8 @@ class InstructionBlock:
             as_int = int(index)  # will Raise ValueError if not integer
             return self.operations[kind][as_int]
 
-    def replace_operation(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all',
-                          index: str | int = 0):
+    def replace_instruction(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all',
+                            index: str | int = 0):
         """
         Replace the operation registered. will Raise IndexError if not present
         Parameters:
@@ -164,8 +164,8 @@ class InstructionBlock:
                 raise IndexError("Operation Not Found")
             self.operations[kind][as_int] = op
 
-    def insert_operation(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all',
-                         before_index: int = 0):
+    def insert_instruction(self, op: str | Instruction | typing.List[Instruction], kind: str | int = 'all',
+                           before_index: int = 0):
         """
         Inserts an operation before the specified one. will Raise IndexError if not present
         Parameters:
@@ -185,7 +185,7 @@ class InstructionBlock:
         else:
             self.operations[kind].insert(before_index, op)
 
-    def remove_operation(self, kind: str | int = 'all', index: str | int = 0):
+    def remove_instruction(self, kind: str | int = 'all', index: str | int = 0):
         """
         Removes the operation registered. will Raise IndexError if not present
         Parameters:
diff --git a/scripts/Infrastructure/TemplateFactory.py b/scripts/Infrastructure/TemplateFactory.py
index 47abb7688..4c595ea17 100644
--- a/scripts/Infrastructure/TemplateFactory.py
+++ b/scripts/Infrastructure/TemplateFactory.py
@@ -1,4 +1,8 @@
 #! /usr/bin/python3
+from __future__ import annotations
+
+import typing
+
 from scripts.Infrastructure.AllocCall import AllocCall
 from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory
 from scripts.Infrastructure.InstructionBlock import InstructionBlock
@@ -18,7 +22,7 @@ def get_default_template(mpi_func):
     pass
 
 
-def get_send_recv_template(send_func="mpi_isend", recv_func="mpi_irecv"):
+def get_send_recv_template(send_func: str = "mpi_isend", recv_func: str | typing.Tuple[str, str] = "mpi_irecv"):
     """
     Contructs a default template for the given mpi send recv function pair
     Returns:
@@ -27,50 +31,75 @@ def get_send_recv_template(send_func="mpi_isend", recv_func="mpi_irecv"):
     """
 
     # currently supported:
-    assert send_func in ["mpi_send", "mpi_ssend", "mpi_isend", "mpi_issend", "mpi_sendrecv", "mpi_rsend", "mpi_irsend",
-                         "mpi_bsend", "mpi_ibsend", "mpi_sendrecv", "mpi_sendrecv_replace", "mpi_isendrecv",
-                         "mpi_isendrecv_replace", "mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init",
-                         "mpi_psend_init"]
-    assert recv_func in ["mpi_recv", "mpi_irecv", "mpi_sendrecv", "mpi_sendrecv_replace", "mpi_isendrecv",
-                         "mpi_isendrecv_replace", "mpi_recv_init", "mpi_precv_init"]
+
+    # mprobe and mrecv combinations allowed
+    probe_pairs = [["mpi_mprobe", "mpi_mrecv"], ["mpi_mprobe", "mpi_imrecv"], ["mpi_improbe", "mpi_mrecv"],
+                   ["mpi_improbe", "mpi_imrecv"]]
 
     sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
 
     persistent_send_funcs = ["mpi_send_init", "mpi_ssend_init", "mpi_bsend_init", "mpi_rsend_init", "mpi_psend_init"]
     persistent_recv_funcs = ["mpi_recv_init", "mpi_precv_init"]
 
+    isend_funcs = ["mpi_isend", "mpi_issend", "mpi_irsend", "mpi_ibsend"]
+    irecv_funcs = ["mpi_irecv"]
+
+    assert (send_func in ["mpi_send", "mpi_ssend", "mpi_rsend", "mpi_bsend"]
+            + sendrecv_funcs + isend_funcs + persistent_send_funcs)
+    assert recv_func in ["mpi_recv"] + sendrecv_funcs + irecv_funcs + persistent_recv_funcs + probe_pairs
+
     if send_func in sendrecv_funcs or recv_func == sendrecv_funcs:
         assert recv_func == send_func
         # default template generation only supports if both use same mechanism
 
     if send_func in ["mpi_rsend", "mpi_irsend", "mpi_rsend_init"]:
-        assert recv_func in ["mpi_irecv", "mpi_recv_init"]  # else: deadlock
+        assert recv_func in ["mpi_irecv", "mpi_recv_init", "mpi_precv_init"]  # else: deadlock
 
     tm = TemplateManager()
     cf = CorrectParameterFactory()
 
     alloc_block = InstructionBlock("alloc")
-    alloc_block.register_operation(cf.get_buffer_alloc())
+    alloc_block.register_instruction(cf.get_buffer_alloc())
     if send_func in sendrecv_funcs:
         # spilt send and recv buf
         alloc = cf.get_buffer_alloc()
         alloc.set_name("recv_buf")
-        alloc_block.register_operation(alloc)
-    tm.register_instruction_block(alloc_block)
+        alloc_block.register_instruction(alloc)
+    if recv_func in probe_pairs:
+        alloc_block.register_instruction("MPI_Message msg;")
 
     if send_func in ["mpi_bsend", "mpi_ibsend", "mpi_bsend_init"]:
-        b = InstructionBlock("buf_attach")
         buf_size = "sizeof(int)*10 + MPI_BSEND_OVERHEAD"
-        b.register_operation(AllocCall("char", buf_size, "mpi_buf"))
-        b.register_operation(MPICallFactory().mpi_buffer_attach("mpi_buf", buf_size))
+        alloc_block.register_instruction(AllocCall("char", buf_size, "mpi_buf"))
+        alloc_block.register_instruction(MPICallFactory().mpi_buffer_attach("mpi_buf", buf_size))
+
+    if (send_func in isend_funcs + persistent_send_funcs or
+            recv_func in persistent_recv_funcs + irecv_funcs + probe_pairs):
+        alloc_block.register_instruction("MPI_Request request;", 'all')
+    if recv_func in probe_pairs:
+        alloc_block.register_instruction("int flag=0;")
+
+    tm.register_instruction_block(alloc_block)
+    # end preperation of all local variables
+
+    # before the send/recv block
+    if send_func in ["mpi_rsend", "mpi_irsend", "mpi_rsend_init"]:
+        b = InstructionBlock("SYNC")
+        # sender needs to wait until recv is started
+        b.register_instruction(CorrectMPICallFactory().mpi_barrier(), 1)
         tm.register_instruction_block(b)
 
     cmpicf = CorrectMPICallFactory()
-    send_func_creator_function = getattr(cmpicf, send_func)
-    s = send_func_creator_function()
 
-    recv_func_creator_function = getattr(cmpicf, recv_func)
-    r = recv_func_creator_function()
+    # get the send and recv block
+
+    recv_to_use = recv_func
+
+    if recv_func in probe_pairs:
+        recv_to_use = recv_func[0]
+
+    s = cmpicf.get(send_func)
+    r = cmpicf.get(recv_to_use)
 
     if send_func in sendrecv_funcs:
         # sending the second msg
@@ -81,65 +110,68 @@ def get_send_recv_template(send_func="mpi_isend", recv_func="mpi_irecv"):
         if r.has_arg("recvbuf"):
             r.set_arg("recvbuf", "recv_buf")
 
-    if (send_func.startswith("mpi_i") or recv_func.startswith("mpi_i")
-            or send_func in persistent_send_funcs or recv_func in persistent_recv_funcs):
-        b = InstructionBlock("MPI_REQUEST")
-        b.register_operation("MPI_Request request;", 'all')
-        tm.register_instruction_block(b)
+    b = InstructionBlock("MPICALL")
+    b.register_instruction(s, 1)
+    b.register_instruction(r, 0)
 
-    if send_func in ["mpi_rsend", "mpi_irsend", "mpi_rsend_init"]:
-        b = InstructionBlock("SYNC")
-        b.register_operation(CorrectMPICallFactory().mpi_barrier(), 1)
-        tm.register_instruction_block(b)
+    if recv_func in probe_pairs:
+        if recv_func in [["mpi_improbe", "mpi_mrecv"],
+                         ["mpi_improbe", "mpi_imrecv"]]:
+            b.insert_instruction("while (!flag){", 0, 0)
+            # insertion before the improbe call
+            b.register_instruction("}", 0)  # end while
+        b.register_instruction(CorrectMPICallFactory().get(recv_func[1]), 0)
 
-    b = InstructionBlock("MPICALL")
-    b.register_operation(s, 1)
-    b.register_operation(r, 0)
     if send_func in persistent_send_funcs:
-        b.register_operation(cmpicf.mpi_start(), 1)
+        b.register_instruction(cmpicf.mpi_start(), 1)
         if send_func == "mpi_psend_init":
             # the pready takes a Request NOt a request*
-            b.register_operation(MPICallFactory().mpi_pready("0", cf.get("request")[1:]), 1)
+            b.register_instruction(MPICallFactory().mpi_pready("0", cf.get("request")[1:]), 1)
     if recv_func in persistent_recv_funcs:
-        b.register_operation(cmpicf.mpi_start(), 0)  #
+        b.register_instruction(cmpicf.mpi_start(), 0)  #
         # parrived is not necessary
 
     tm.register_instruction_block(b)
 
+    # after send/recv
+
     if send_func in ["mpi_rsend", "mpi_irsend", "mpi_rsend_init"]:
         b = InstructionBlock("SYNC")
-        b.register_operation(CorrectMPICallFactory().mpi_barrier(), 1)
+        # barrier indicating recv has started
+        b.register_instruction(CorrectMPICallFactory().mpi_barrier(), 0)
         tm.register_instruction_block(b)
 
-    if send_func.startswith("mpi_i") or send_func in persistent_send_funcs:
+    # wait for op to complete
+    if send_func in isend_funcs + persistent_send_funcs:
         b = InstructionBlock("WAIT")
-        b.register_operation(CorrectMPICallFactory().mpi_wait(), 1)
+        b.register_instruction(CorrectMPICallFactory().mpi_wait(), 1)
         tm.register_instruction_block(b)
 
-    if recv_func.startswith("mpi_i") or recv_func in persistent_recv_funcs:
+    if recv_func in irecv_funcs + persistent_recv_funcs + [["mpi_mprobe", "mpi_imrecv"],
+                                                           ["mpi_improbe", "mpi_imrecv"]]:
         b = InstructionBlock("WAIT")
-        b.register_operation(CorrectMPICallFactory().mpi_wait(), 0)
+        b.register_instruction(CorrectMPICallFactory().mpi_wait(), 0)
         tm.register_instruction_block(b)
 
+    # end MPI operation
+    # cleanup
+    free_block = InstructionBlock("buf_free")
     if send_func in ["mpi_bsend", "mpi_ibsend", "mpi_bsend_init"]:
-        b = InstructionBlock("buf_detach")
-        b.register_operation("int freed_size;")
-        b.register_operation(MPICallFactory().mpi_buffer_detach("mpi_buf", "&freed_size"))
-        b.register_operation("free(mpi_buf);")
-        tm.register_instruction_block(b)
+        free_block = InstructionBlock("buf_detach")
+        free_block.register_instruction("int freed_size;")
+        free_block.register_instruction(MPICallFactory().mpi_buffer_detach("mpi_buf", "&freed_size"))
+        free_block.register_instruction("free(mpi_buf);")
+
+    free_block.register_instruction(cf.get_buffer_free())
 
-    free_block = InstructionBlock("buf_free")
-    free_block.register_operation(cf.get_buffer_free())
     if send_func in sendrecv_funcs:
         # spilt send and recv buf
-        b.register_operation("free(recv_buf);")
-    tm.register_instruction_block(free_block)
+        free_block.register_instruction("free(recv_buf);")
 
     if send_func in persistent_send_funcs:
-        # spilt send and recv buf
-        b = InstructionBlock("req_free")
-        b.register_operation(cmpicf.mpi_request_free())
-        tm.register_instruction_block(b)
+        free_block.register_instruction(cmpicf.mpi_request_free())
+
+    tm.register_instruction_block(free_block)
 
     return tm
 
@@ -156,12 +188,12 @@ def get_collective_template(collective_func, seperate=True):
     cf = CorrectParameterFactory()
 
     alloc_block = InstructionBlock("alloc")
-    alloc_block.register_operation(cf.get_buffer_alloc())
+    alloc_block.register_instruction(cf.get_buffer_alloc())
     if False:
         # spilt send and recv buf
         alloc = cf.get_buffer_alloc()
         alloc.set_name("recv_buf")
-        alloc_block.register_operation(alloc)
+        alloc_block.register_instruction(alloc)
     tm.register_instruction_block(alloc_block)
 
     cmpicf = CorrectMPICallFactory()
@@ -170,15 +202,15 @@ def get_collective_template(collective_func, seperate=True):
 
     b = InstructionBlock("MPICALL")
     if seperate:
-        b.register_operation(c, 1)
-        b.register_operation(c, 0)
+        b.register_instruction(c, 1)
+        b.register_instruction(c, 0)
     else:
-        b.register_operation(c, 'all')
+        b.register_instruction(c, 'all')
 
     tm.register_instruction_block(b)
 
     free_block = InstructionBlock("buf_free")
-    free_block.register_operation(cf.get_buffer_free())
+    free_block.register_instruction(cf.get_buffer_free())
     tm.register_instruction_block(free_block)
 
     return tm
@@ -190,11 +222,11 @@ def get_allocated_window(win_alloc_func, name, bufname, ctype, num_elements):
     :param win_alloc_func: The window allocation to use (mpi_win_allocate or mpi_win_create).
     :param name: name of the window
     """
-    
+
     b = InstructionBlock("win_allocate")
 
     # declare window
-    b.register_operation(f"MPI_Win {name};")
+    b.register_instruction(f"MPI_Win {name};")
 
     # extract C data type and window buffer name
     # dtype = CorrectParameterFactory().dtype[0]
@@ -204,17 +236,17 @@ def get_allocated_window(win_alloc_func, name, bufname, ctype, num_elements):
 
     if win_alloc_func == "mpi_win_allocate":
         # MPI allocate, only declaration required
-        b.register_operation(f"{ctype}* {bufname};")
+        b.register_instruction(f"{ctype}* {bufname};")
         win_allocate_call = CorrectMPICallFactory().mpi_win_allocate()
         win_allocate_call.set_arg("baseptr", "&" + bufname)
     elif win_alloc_func == "mpi_win_create":
         # allocate buffer for win_create
-        b.register_operation(AllocCall(ctype, num_elements, bufname))
+        b.register_instruction(AllocCall(ctype, num_elements, bufname))
         win_allocate_call = CorrectMPICallFactory().mpi_win_create()
         win_allocate_call.set_arg("base", bufname)
     else:
         assert False
-    
+
     # set common parameters for both calls
     win_allocate_call.set_arg("win", "&" + name)
 
@@ -222,36 +254,33 @@ def get_allocated_window(win_alloc_func, name, bufname, ctype, num_elements):
     win_allocate_call.set_arg("size", buf_size_bytes)
 
     win_allocate_call.set_arg("disp_unit", f"sizeof({ctype})")
-    b.register_operation(win_allocate_call)
+    b.register_instruction(win_allocate_call)
 
     return b
 
 
-
 def get_rma_call(rma_func, rank):
-
-    b = InstructionBlock(rma_func.replace('mpi_',''))
+    b = InstructionBlock(rma_func.replace('mpi_', ''))
 
     cf = CorrectParameterFactory()
     cfmpi = CorrectMPICallFactory()
 
     # request-based RMA call, add request
     if rma_func.startswith("mpi_r"):
-        b.register_operation(f"MPI_Request " + cf.get("request")[1:] + ";", kind=rank)
+        b.register_instruction(f"MPI_Request " + cf.get("request")[1:] + ";", kind=rank)
 
     # some RMA ops require result_addr
     if rma_func in ["mpi_get_accumulate", "mpi_rget_accumulate", "mpi_fetch_and_op", "mpi_compare_and_swap"]:
-        b.register_operation(AllocCall(cf.dtype[0], cf.buf_size, cf.get("result_addr")), kind=rank)
+        b.register_instruction(AllocCall(cf.dtype[0], cf.buf_size, cf.get("result_addr")), kind=rank)
 
     # some RMA ops require compare_addr
     if rma_func in ["mpi_fetch_and_op", "mpi_compare_and_swap"]:
-        b.register_operation(AllocCall(cf.dtype[0], cf.buf_size, cf.get("compare_addr")), kind=rank)
+        b.register_instruction(AllocCall(cf.dtype[0], cf.buf_size, cf.get("compare_addr")), kind=rank)
 
-    b.register_operation(getattr(cfmpi, rma_func)(), kind=rank)
+    b.register_instruction(getattr(cfmpi, rma_func)(), kind=rank)
     return b
 
 
-
 def get_communicator(comm_create_func, name):
     """
     :param comm_create_func: teh function used to create the new communicator
@@ -262,12 +291,12 @@ def get_communicator(comm_create_func, name):
                                 "mpi_comm_idup_with_info", "mpi_comm_create", "mpi_comm_create_group", "mpi_comm_split",
                                 "mpi_comm_split_type", "mpi_comm_create_from_group"]
     b = InstructionBlock("comm_create")
-    b.register_operation("MPI_Comm " + name + ";")
+    b.register_instruction("MPI_Comm " + name + ";")
     if comm_create_func.startswith("mpi_comm_i"):
-        b.register_operation("MPI_Request comm_create_req;")
+        b.register_instruction("MPI_Request comm_create_req;")
     if comm_create_func in ["mpi_comm_create", "mpi_comm_create_group"]:
-        b.register_operation("MPI_Group group;")
-        b.register_operation(CorrectMPICallFactory().mpi_comm_group())
+        b.register_instruction("MPI_Group group;")
+        b.register_instruction(CorrectMPICallFactory().mpi_comm_group())
     cmpicf = CorrectMPICallFactory()
     call_creator_function = getattr(cmpicf, comm_create_func)
     call = call_creator_function()
@@ -276,11 +305,11 @@ def get_communicator(comm_create_func, name):
         call.set_arg("request", "&comm_create_req")
     if comm_create_func in ["mpi_comm_create", "mpi_comm_create_group"]:
         call.set_arg("group", "group")  # not &group
-    b.register_operation(call)
+    b.register_instruction(call)
     if comm_create_func.startswith("mpi_comm_i"):
-        b.register_operation(MPICallFactory().mpi_wait("&comm_create_req", "MPI_STATUS_IGNORE"))
+        b.register_instruction(MPICallFactory().mpi_wait("&comm_create_req", "MPI_STATUS_IGNORE"))
     if comm_create_func in ["mpi_comm_create", "mpi_comm_create_group"]:
-        b.register_operation(cmpicf.mpi_group_free())
+        b.register_instruction(cmpicf.mpi_group_free())
     return b
 
 
@@ -297,31 +326,31 @@ def get_intercomm(comm_create_func, name):
     assert name != "intercomm_base_comm"
     if comm_create_func == "mpi_intercomm_create":
         b = InstructionBlock("comm_create")
-        b.register_operation("MPI_Comm intercomm_base_comm;")
-        b.register_operation(
+        b.register_instruction("MPI_Comm intercomm_base_comm;")
+        b.register_instruction(
             MPICallFactory().mpi_comm_split("MPI_COMM_WORLD", "rank % 2", "rank", "&intercomm_base_comm"))
-        b.register_operation("MPI_Comm " + name + ";")
-        b.register_operation(
+        b.register_instruction("MPI_Comm " + name + ";")
+        b.register_instruction(
             MPICallFactory().mpi_intercomm_create("intercomm_base_comm", "0", "MPI_COMM_WORLD", "!(rank %2)",
                                                   CorrectParameterFactory().get("tag"), "&" + name))
-        b.register_operation(MPICallFactory().mpi_comm_free("&intercomm_base_comm"))
+        b.register_instruction(MPICallFactory().mpi_comm_free("&intercomm_base_comm"))
         return b
     if comm_create_func == "mpi_intercomm_create_from_groups":
         b = InstructionBlock("comm_create")
 
-        b.register_operation("MPI_Group world_group,even_group,odd_group;")
-        b.register_operation(MPICallFactory().mpi_comm_group("MPI_COMM_WORLD", "&world_group"))
-        b.register_operation(
+        b.register_instruction("MPI_Group world_group,even_group,odd_group;")
+        b.register_instruction(MPICallFactory().mpi_comm_group("MPI_COMM_WORLD", "&world_group"))
+        b.register_instruction(
             MPICallFactory().mpi_comm_group("intercomm_base_comm", "&intercomm_base_comm_group"))
-        b.register_operation("int[3] triplet;")
-        b.register_operation("triplet[0] =0;")
-        b.register_operation("triplet[1] =size;")
-        b.register_operation("triplet[2] =2;")
-        b.register_operation(MPICallFactory().mpi_group_incl("world_group", "1","&triplet", "even_group"))
-        b.register_operation("triplet[0] =1;")
-        b.register_operation(MPICallFactory().mpi_group_incl("world_group", "1","&triplet", "odd_group"))
-        b.register_operation("MPI_Comm " + name + ";")
-        b.register_operation(
+        b.register_instruction("int[3] triplet;")
+        b.register_instruction("triplet[0] =0;")
+        b.register_instruction("triplet[1] =size;")
+        b.register_instruction("triplet[2] =2;")
+        b.register_instruction(MPICallFactory().mpi_group_incl("world_group", "1", "&triplet", "even_group"))
+        b.register_instruction("triplet[0] =1;")
+        b.register_instruction(MPICallFactory().mpi_group_incl("world_group", "1", "&triplet", "odd_group"))
+        b.register_instruction("MPI_Comm " + name + ";")
+        b.register_instruction(
             MPICallFactory().mpi_intercomm_create_from_groups("(rank % 2 ? even_group:odd_group)", "0",
                                                               "(!(rank % 2) ? even_group:odd_group)", "0",
                                                               CorrectParameterFactory().get("stringtag"),
@@ -331,18 +360,18 @@ def get_intercomm(comm_create_func, name):
         return b
     if comm_create_func == "mpi_intercomm_merge":
         b = InstructionBlock("comm_create")
-        b.register_operation("MPI_Comm intercomm_base_comm;")
-        b.register_operation("MPI_Comm to_merge_intercomm_comm;")
-        b.register_operation(
+        b.register_instruction("MPI_Comm intercomm_base_comm;")
+        b.register_instruction("MPI_Comm to_merge_intercomm_comm;")
+        b.register_instruction(
             MPICallFactory().mpi_comm_split("MPI_COMM_WORLD", "rank % 2", "rank", "&intercomm_base_comm"))
-        b.register_operation("MPI_Comm " + name + ";")
-        b.register_operation(
+        b.register_instruction("MPI_Comm " + name + ";")
+        b.register_instruction(
             MPICallFactory().mpi_intercomm_create("intercomm_base_comm", "0", "MPI_COMM_WORLD", "!(rank %2)",
                                                   CorrectParameterFactory().get("tag"), "&to_merge_intercomm_comm"))
-        b.register_operation(MPICallFactory().mpi_intercomm_merge("to_merge_intercomm_comm", "rank %2", "&" + name))
+        b.register_instruction(MPICallFactory().mpi_intercomm_merge("to_merge_intercomm_comm", "rank %2", "&" + name))
 
-        b.register_operation(MPICallFactory().mpi_comm_free("&to_merge_intercomm_comm"))
-        b.register_operation(MPICallFactory().mpi_comm_free("&intercomm_base_comm"))
+        b.register_instruction(MPICallFactory().mpi_comm_free("&to_merge_intercomm_comm"))
+        b.register_instruction(MPICallFactory().mpi_comm_free("&intercomm_base_comm"))
         return b
 
     return None
-- 
GitLab