Skip to content
Snippets Groups Projects
Commit e22aad47 authored by Jammer, Tim's avatar Jammer, Tim
Browse files

Merge branch 'devel-TJ' into 'main'

more work on infrastructure III

See merge request !5
parents f603dbf4 34bb037a
Branches
No related tags found
1 merge request!5more work on infrastructure III
......@@ -17,7 +17,9 @@ class Invalid_negative_rank_error:
tm.set_description("Invalid Rank: %s" % self.invalid_ranks[self.rank_to_use])
# include the buffer allocation in the template (all ranks execute it)
tm.register_instruction_block(correct_params.get_buffer_alloc())
alloc_block = InstructionBlock("alloc")
alloc_block.register_operation(correct_params.get_buffer_alloc())
tm.register_instruction_block(alloc_block)
send = MPI_Call_Factory().mpi_send(
correct_params.get("BUFFER"),
......
......@@ -15,15 +15,10 @@ class CorrectParameterFactory:
pass
def get_buffer_alloc(self):
b = InstructionBlock("alloc")
b.register_operation(AllocCall(self.dtype[0], self.buf_size, self.buf_var_name, use_malloc=False), kind='all')
return b
return AllocCall(self.dtype[0], self.buf_size, self.buf_var_name, use_malloc=False)
def get_buffer_free(self):
b = InstructionBlock("free")
b.register_operation(get_free(AllocCall(self.dtype[0], self.buf_size, self.buf_var_name, use_malloc=False)),
kind='all')
return b
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"]:
......@@ -42,10 +37,18 @@ class CorrectParameterFactory:
return str(self.tag)
if param in ["COMM", "comm"]:
return "MPI_COMM_WORLD"
if param in ["newcomm"]:
return "newcomm"
if param in ["STATUS", "status"]:
return "MPI_STATUS_IGNORE"
if param in ["OPERATION", "op"]:
return "MPI_SUM"
if param in ["INFO", "info"]:
return "MPI_INFO_NULL"
if param in ["PARTITIONS", "partitions"]:
return "1"
if param in ["PARTITION", "partition"]:
return "0"
if param in ["REQUEST", "request"]:
return "&request"
......
......@@ -3,6 +3,7 @@
# ABC in python is abstract Base Class
from abc import ABC, abstractmethod
class ErrorGenerator(ABC):
"""
Abstract Class Overview:
......@@ -15,6 +16,7 @@ class ErrorGenerator(ABC):
- `get_num_errors_extended(self)`: Abstract method to get the number of errors in extended mode.
- `generate(self, i)`: Abstract method to generate error number i, returning a TemplateManager instance.
"""
@abstractmethod
def __init__(self):
pass
......@@ -51,12 +53,13 @@ class ErrorGenerator(ABC):
"""
pass
@abstractmethod
def generate(self, i):
"""
Abstract method to generate error number i.
may raise CorrectTestcase if the specified case is actually correct
Parameters:
- i: Error number.
......@@ -64,3 +67,8 @@ class ErrorGenerator(ABC):
TemplateManager: An instantiated and set up TemplateManager with the error case.
"""
pass
class CorrectTestcase (BaseException):
# exception class to be raised by generators if they generate a correct case
pass
......@@ -8,7 +8,7 @@ import subprocess
# for printing a nice progress bar
import tqdm
from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
from scripts.Infrastructure.ErrorGenerator import ErrorGenerator, CorrectTestcase
from scripts.Infrastructure.Variables import featurelist
# number of digits to use numbering filenames
......@@ -16,6 +16,9 @@ digits_to_use = 3
def import_module(root, file):
"""
Private function: imports a python module from a file
"""
full_fname = os.path.join(root, file)
name = file[:-3] # name without .py suffix
spec = importlib.util.spec_from_file_location(name, full_fname)
......@@ -25,14 +28,34 @@ def import_module(root, file):
class GeneratorManager:
def __init__(self, path):
def __init__(self, path, print_discovery=True, skip_invalid=False):
"""
Instantiates an GeneratorManager and discovers ErrorGenerator classes from Python files in the specified path.
Parameters:
- `path` (str): The path to search for Python files containing ErrorGenerator classes.
- `print_discovery` (bool, optional): Whether to print the discovered generators. Defaults to True.
- `skip_invalid` (bool, optional): Whether to skip invalid generators. Defaults to False.
Returns:
None
Raises:
AssertionError: If an ErrorGenerator class is found with unknown features and `skip_invalid` is False.
Note:
- Discovers the generators in Python files with the '.py' extension in the specified path and its subdirectories.
"""
self.generators = []
self.discover_generators(path)
self.discover_generators(path, print_discovery, skip_invalid)
self.case_names = {}
# discover all Error Generators
pass
def get_filename(self, case_name, suffix=".c"):
"""
Private Function: Helps to generate filenames for the generated testcases
"""
num = 0
if case_name in self.case_names:
num = self.case_names[case_name]
......@@ -42,7 +65,32 @@ 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):
try_compile=False, max_mpi_version=4.0, use_clang_format=True):
"""
Generates test cases based on the specified parameters.
Parameters:
- `outpath` (str): The path where the generated test cases will be saved.
- `filterlist_` (list, optional): A list of features to filter the generators. Defaults to None (no filters).
- `print_progress_bar` (bool, optional): Whether to print a progress bar. Defaults to True.
- `overwrite` (bool, optional): Whether to overwrite existing files. Defaults to True.
- `generate_full_set` (bool, optional): Whether to generate the full (extended) set of errors. Defaults to False.
- `try_compile` (bool, optional): Whether to try compiling the generated test cases. Defaults to False.
- `use_clang_format` (bool, optional): Whether to format the generated test cases. Defaults to True.
- `max_mpi_version` (float, optional): The maximum MPI version allowed for generated test cases. Defaults to 4.0.
Returns:
None
Raises:
AssertionError: If the environment variable 'MPICC' is not set when `try_compile` is True.
CalledProcessError: If compilation fails during the try_compile process or clang-formart fails.
Note:
- The progress bar is printed using the tqdm module.
- If `try_compile` is True, it uses the compiler specified via 'MPICC' environment variable to attempt compilation.
- the Features and if a test belongs to the base of frull test set is defined by the respective generators
- Generators can Raise CorrectTestcase, therefore the number of discovered testcases may not match the number of generated cases
"""
filterlist = filterlist_
if filterlist is None:
filterlist = featurelist
......@@ -79,29 +127,45 @@ class GeneratorManager:
num_errors_in_generator = generator.get_num_errors()
for i in range(num_errors_in_generator):
try:
result_error = generator.generate(i)
if not float(result_error.get_version()) > float(max_mpi_version):
case_name = result_error.get_short_descr()
fname = self.get_filename(case_name)
full_name = os.path.join(outpath, fname)
if not overwrite and os.path.isfile(full_name):
assert False and "File Already exists"
result_str = str(result_error)
if use_clang_format:
result_str = subprocess.check_output(["clang-format"], text=True,
input=result_str)
with open(full_name, "w") as text_file:
text_file.write(str(result_error))
text_file.write(result_str)
cases_generated += 1
if try_compile:
subprocess.check_call([mpicc, full_name])
# raises CalledProcessError if code does not compile
except CorrectTestcase:
# ignore a correct case
pass
++cases_generated
if print_progress_bar:
progress_bar.update(1)
if print_progress_bar:
progress_bar.close()
print("Finished. Generated %i cases" % cases_generated)
pass
def discover_generators(self, path, print_discovery=True, skip_invalid=False):
"""
Private Function. see Documentation for __init__()
"""
if print_discovery:
print("Discover Generators:")
for root, dirs, files in os.walk(path):
......@@ -109,7 +173,7 @@ class GeneratorManager:
if file.endswith('.py'):
module = import_module(root, file)
for name, obj in inspect.getmembers(module):
# if it is a class derived from ErrorGenerator (and not the interface class itself)
# if it is a class derived from ErrorGenerator (and is not the interface class itself)
if inspect.isclass(obj) and issubclass(obj, ErrorGenerator) and not obj is ErrorGenerator:
if print_discovery:
print("Found Generator %s" % name)
......
......@@ -89,7 +89,22 @@ class InstructionBlock:
return result_str
def get_operation(self, kind=all, index=0):
def has_operation(self, kind='all', index=0):
"""
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
Returns:
boolean
"""
try:
result = self.operations[kind][index]
return True
except (KeyError,IndexError) as e:
return False
def get_operation(self, kind='all', index=0):
"""
Retrieve the operation registered. will Raise IndexError if not present
Parameters:
......@@ -100,7 +115,7 @@ class InstructionBlock:
"""
return self.operations[kind][index]
def replace_operation(self, op, kind=all, index=0):
def replace_operation(self, op, kind='all', index=0):
"""
Replace the operation registered. will Raise IndexError if not present
Parameters:
......@@ -108,17 +123,17 @@ class InstructionBlock:
- 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:
if len(self.operations[kind]) < index:
raise IndexError("Operation Not Found")
self.operations[kind][index] = op
def remove_operation(self, kind=all, index=0):
def remove_operation(self, kind='all', index=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
"""
if len(self.operations[kind]) >= index:
if len(self.operations[kind]) < index:
raise IndexError("Operation Not Found")
del self.operations[kind][index]
......@@ -9,6 +9,7 @@ template = """// @{generatedby}@
Version of MPI: @{version}@
THIS BLOCK IS CURRENTLY NOT USED:
BEGIN_MPI_FEATURES
P2P!basic: @{p2pfeature}@
P2P!nonblocking: @{ip2pfeature}@
......@@ -20,11 +21,11 @@ BEGIN_MPI_FEATURES
RMA: Lacking
END_MPI_FEATURES
BEGIN_MBI_TESTS
BEGIN_MBB_TESTS
$ mpirun -np @{min_num_ranks}@ ${EXE}
| @{outcome}@
| @{errormsg}@
END_MBI_TESTS
END_MBB_TESTS
////////////////////// End of MBI headers /////////////////// */
#include <mpi.h>
......@@ -39,7 +40,7 @@ int main(int argc, char **argv) {
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (nprocs < @{min_num_ranks}@)
printf("MBI ERROR: This test needs at least 2 processes to produce a bug!\\n");
printf("MBB ERROR: This test needs at least 2 processes to produce a bug!\\n");
@{test_code}@
......@@ -118,7 +119,7 @@ class TemplateManager:
def register_instruction_block(self, block):
"""
Registers an instruction block with the template.
Registers an instruction block with the template. inserting it at the end, before the mpi finalize
Parameters:
- block: The instruction block to register.
"""
......@@ -159,7 +160,7 @@ class TemplateManager:
def get_block(self, block_name=None, idx=None):
"""
Retrieves the given Instruction Block Either by name or by index
Raises IndexError if not the specified block is not found
Raises IndexError if the specified block is not found
Raises IndexError if multiple Blocks with the given name are found
Raises ValueError if Both a block name and index are given (or none is given)
Args:
......@@ -186,10 +187,40 @@ class TemplateManager:
raise ValueError("Neither Both block name nor index is given")
def insert_block(self, new_block, block_name=None, idx=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
Raises IndexError if multiple Blocks with the given name are found
Raises ValueError if Both a block name and index are given (or none is given)
Args:
new_block (InstructionBlock): the block to insert
block_name (str): The name of the InstructionBlock to receive
idx (int): index of the InstructionBlock to retrieve
"""
if block_name is not None:
if idx is not None:
raise ValueError("Both block name and index are given")
to_return = [b for b in self._blocks if b.name == block_name]
if len(to_return) == 0:
raise IndexError("Block Not Found")
if len(to_return) > 1:
raise IndexError("Multiple Blocks Found")
self._blocks.insert(self._blocks.index(to_return[0]) + 1, new_block)
return
if idx is not None:
if block_name is not None:
raise ValueError("Both block name and index are given")
self._blocks.insert(idx + 1, new_block)
return
raise ValueError("Neither Both block name nor index is given")
def remove_block(self, block_name=None, idx=None):
"""
Removes the given Instruction Block Either by name or by index
Raises IndexError if not the specified block is not found
Raises IndexError if the specified block is not found
Raises IndexError if multiple Blocks with the given name are found
Raises ValueError if Both a block name and index are given (or none is given)
Args:
......@@ -202,7 +233,7 @@ class TemplateManager:
to_return = [b for b in self._blocks if b.name == block_name]
if len(to_return) == 0:
raise IndexError("Block Not Found")
if len(to_return) > 0:
if len(to_return) > 1:
raise IndexError("Multiple Blocks Found")
self._blocks.remove(to_return[0])
......@@ -216,7 +247,7 @@ class TemplateManager:
def replace_block(self, new_block, block_name=None, idx=None):
"""
Removes the given Instruction Block Either by name or by index
Raises IndexError if not the specified block is not found
Raises IndexError if the specified block is not found
Raises IndexError if multiple Blocks with the given name are found
Raises ValueError if Both a block name and index are given (or none is given)
Args:
......@@ -231,7 +262,7 @@ class TemplateManager:
to_return = [b for b in self._blocks if b.name == block_name]
if len(to_return) == 0:
raise IndexError("Block Not Found")
if len(to_return) > 0:
if len(to_return) > 1:
raise IndexError("Multiple Blocks Found")
self._blocks[self._blocks.index(to_return[0])] = new_block
......
......@@ -18,7 +18,7 @@ def get_default_template(mpi_func):
pass
def get_send_recv_template(send_func, recv_func):
def get_send_recv_template(send_func="mpi_isend", recv_func="mpi_irecv"):
"""
Contructs a default template for the given mpi send recv function pair
Returns:
......@@ -29,37 +29,42 @@ def get_send_recv_template(send_func, recv_func):
# 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_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_isendrecv_replace","mpi_recv_init","mpi_precv_init"]
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"]
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"]:
assert recv_func == "mpi_irecv" # else: deadlock
if send_func in ["mpi_rsend", "mpi_irsend", "mpi_rsend_init"]:
assert recv_func in ["mpi_irecv", "mpi_recv_init"] # else: deadlock
tm = TemplateManager()
cf = CorrectParameterFactory()
tm.register_instruction_block(cf.get_buffer_alloc())
alloc_block = InstructionBlock("alloc")
alloc_block.register_operation(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)
if send_func in ["mpi_bsend", "mpi_ibsend"]:
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))
tm.register_instruction_block(b)
if send_func in sendrecv_funcs:
# spilt send and recv buf
b = cf.get_buffer_alloc()
b.get_operation('all',0).set_name("recv_buf")
tm.register_instruction_block(b)
cmpicf = CorrectMPICallFactory()
send_func_creator_function = getattr(cmpicf, send_func)
s = send_func_creator_function()
......@@ -76,12 +81,13 @@ def get_send_recv_template(send_func, recv_func):
if r.has_arg("recvbuf"):
r.set_arg("recvbuf", "recv_buf")
if send_func.startswith("mpi_i") or recv_func.startswith("mpi_i"):
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)
if send_func in ["mpi_rsend", "mpi_irsend"]:
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)
......@@ -89,38 +95,57 @@ def get_send_recv_template(send_func, recv_func):
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)
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)
if recv_func in persistent_recv_funcs:
b.register_operation(cmpicf.mpi_start(),1)#
#parrived is not necessary
tm.register_instruction_block(b)
if send_func in ["mpi_rsend", "mpi_irsend"]:
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 send_func.startswith("mpi_i"):
if send_func.startswith("mpi_i") or send_func in persistent_send_funcs:
b = InstructionBlock("WAIT")
b.register_operation(CorrectMPICallFactory().mpi_wait(), 1)
tm.register_instruction_block(b)
if recv_func.startswith("mpi_i"):
if recv_func.startswith("mpi_i") or recv_func in persistent_recv_funcs:
b = InstructionBlock("WAIT")
b.register_operation(CorrectMPICallFactory().mpi_wait(), 0)
tm.register_instruction_block(b)
b.register_operation(cf.get_buffer_free())
if send_func in ["mpi_bsend", "mpi_ibsend"]:
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_free")
free_block.register_operation(cf.get_buffer_free())
if send_func in sendrecv_funcs:
# spilt send and recv buf
b = InstructionBlock("buf_free")
b.register_operation("free(recv_buf);")
tm.register_instruction_block(free_block)
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)
return tm
......@@ -135,7 +160,14 @@ def get_collective_template(collective_func, seperate=True):
tm = TemplateManager()
cf = CorrectParameterFactory()
tm.register_instruction_block(cf.get_buffer_alloc())
alloc_block = InstructionBlock("alloc")
alloc_block.register_operation(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)
tm.register_instruction_block(alloc_block)
cmpicf = CorrectMPICallFactory()
call_creator_function = getattr(cmpicf, collective_func)
......@@ -150,6 +182,8 @@ def get_collective_template(collective_func, seperate=True):
tm.register_instruction_block(b)
b.register_operation(cf.get_buffer_free())
free_block = InstructionBlock("buf_free")
free_block.register_operation(cf.get_buffer_free())
tm.register_instruction_block(free_block)
return tm
#! /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
sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
class InvalidBufErrorP2P(ErrorGenerator):
invalid_bufs = [CorrectParameterFactory().buf_var_name, "NULL"]
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 + sendrecv_funcs
# chekc sendrecv funcs two times: the send and recv part
recv_funcs = ["mpi_recv", "mpi_irecv", "mpi_recv_init", "mpi_precv_init"] + sendrecv_funcs
def __init__(self):
pass
def get_num_errors(self):
# send + receive = only check the first two functions
return len(self.invalid_bufs) * 2
# the number of errors to produce in the extended mode (all possible combinations)
def get_num_errors_extended(self):
return len(self.invalid_bufs) * len(self.functions_to_check)
def get_feature(self):
return ["P2P"]
def generate(self, i):
buf_to_use = self.invalid_bufs[i % len(self.invalid_bufs)]
send_func = self.functions_to_check[i // len(self.invalid_bufs)]
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
if i % len(self.functions_to_check) >= len(self.functions_to_check) - len(sendrecv_funcs):
# check the send part of sendrecv
check_receive = False
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 Rank: %s" % buf_to_use)
else:
tm.set_description("InvalidParam-Buffer-" + send_func, "Invalid Rank: %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()
return tm
#! /usr/bin/python3
from scripts.Infrastructure.ErrorGenerator import ErrorGenerator, CorrectTestcase
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
sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
class InvalidCommErrorP2P(ErrorGenerator):
invalid_comm = ["MPI_COMM_NULL", "NULL"]
missmatching_comms = ["MPI_COMM_SELF","mpi_comm_dup"]
#TODO test with:
#'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',
#'MPI_Intercomm_create',
#'MPI_Intercomm_create_from_groups',
#'MPI_Intercomm_merge'
# as extended testcases
comms_to_check = invalid_comm + missmatching_comms
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_num_errors(self):
# send + receive = only check the first two functions
return len(self.comms_to_check) * 2
# the number of errors to produce in the extended mode (all possible combinations)
def get_num_errors_extended(self):
return len(self.comms_to_check) * len(self.functions_to_check)
def get_feature(self):
return ["P2P"]
def generate(self, i):
comm_to_use = self.comms_to_check[i % len(self.comms_to_check)]
send_func = self.functions_to_check[i // len(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
if i % len(self.functions_to_check) >= len(self.functions_to_check) - len(sendrecv_funcs):
# check the send part of sendrecv
check_receive = False
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 = InstructionBlock("comm_create")
b.register_operation("MPI_Comm "+comm_to_use + ";")
cmpicf = CorrectMPICallFactory()
cmpicf = CorrectMPICallFactory()
call_creator_function = getattr(cmpicf, comm_to_use)
call = call_creator_function()
call.set_arg("newcomm","&"+comm_to_use)
b.register_operation(call)
tm.insert_block(b,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
raise CorrectTestcase
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()
if comm_to_use in self.missmatching_comms 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)
return tm
......@@ -16,10 +16,11 @@ class InvalidRankErrorP2P(ErrorGenerator):
invalid_ranks = ["-1", "nprocs", "MPI_PROC_NULL"]
functions_to_check = ["mpi_send",
"mpi_recv", "mpi_irecv",
"mpi_isend", "mpi_ssend", "mpi_issend", "mpi_rsend", "mpi_irsend", "mpi_bsend", "mpi_ibsend"
"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 + sendrecv_funcs
# chekc sendrecv funcs two times: the send and recv part
recv_funcs = ["mpi_recv", "mpi_irecv"] + sendrecv_funcs
recv_funcs = ["mpi_recv", "mpi_irecv","mpi_recv_init","mpi_precv_init"] + sendrecv_funcs
def __init__(self):
pass
......@@ -36,8 +37,8 @@ class InvalidRankErrorP2P(ErrorGenerator):
return ["P2P"]
def generate(self, i):
rank_to_use = self.invalid_ranks[i // len(self.functions_to_check)]
send_func = self.functions_to_check[i % len(self.functions_to_check)]
rank_to_use = self.invalid_ranks[i % len(self.invalid_ranks)]
send_func = self.functions_to_check[i // len(self.invalid_ranks)]
check_receive = False
recv_func = "mpi_irecv"
......
#! /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, i):
req_to_use = self.invalid_requests[i % len(self.invalid_requests)]
send_func = self.functions_to_check[i // len(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()
return tm
#! /usr/bin/python3
from scripts.Infrastructure.ErrorGenerator import ErrorGenerator
from scripts.Infrastructure.ErrorGenerator import ErrorGenerator, CorrectTestcase
from scripts.Infrastructure.InstructionBlock import InstructionBlock
from scripts.Infrastructure.MPICallFactory import MPICallFactory, CorrectMPICallFactory
from scripts.Infrastructure.CorrectParameter import CorrectParameterFactory, get_matching_recv
......@@ -13,13 +13,15 @@ sendrecv_funcs = ["mpi_sendrecv", "mpi_sendrecv_replace"]
class InvalidTagErrorP2P(ErrorGenerator):
invalid_tags = ["-1", "MPI_TAG_UB+1"]
invalid_tags = ["-1", "MPI_TAG_UB+1", CorrectParameterFactory.tag * 2, "MPI_ANY_TAG"]
functions_to_check = ["mpi_send",
"mpi_recv", "mpi_irecv",
"mpi_isend", "mpi_ssend", "mpi_issend", "mpi_rsend", "mpi_irsend", "mpi_bsend", "mpi_ibsend"
"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 + sendrecv_funcs
# chekc sendrecv funcs two times: the send and recv part
recv_funcs = ["mpi_recv", "mpi_irecv"] + sendrecv_funcs
recv_funcs = ["mpi_recv", "mpi_irecv", "mpi_recv_init", "mpi_precv_init"] + sendrecv_funcs
def __init__(self):
pass
......@@ -36,8 +38,8 @@ class InvalidTagErrorP2P(ErrorGenerator):
return ["P2P"]
def generate(self, i):
tag_to_use = self.invalid_tags[i // len(self.functions_to_check)]
send_func = self.functions_to_check[i % len(self.functions_to_check)]
tag_to_use = self.invalid_tags[i % len(self.invalid_tags)]
send_func = self.functions_to_check[i // len(self.invalid_tags)]
check_receive = False
recv_func = "mpi_irecv"
......@@ -53,10 +55,20 @@ class InvalidTagErrorP2P(ErrorGenerator):
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:
tm.set_description("InvalidParam-Tag-" + recv_func, "Invalid Rank: %s" % tag_to_use)
if tag_to_use == "MPI_ANY_TAG":
# correct case
raise CorrectTestcase
if tag_to_use == CorrectParameterFactory().tag * 2 and recv_func == "mpi_irecv":
# combination repeated
raise CorrectTestcase
tm.set_description(error_string + "-Tag-" + recv_func, "Invalid Rank: %s" % tag_to_use)
else:
tm.set_description("InvalidParam-Tag-" + send_func, "Invalid Rank: %s" % tag_to_use)
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"):
......@@ -64,11 +76,17 @@ class InvalidTagErrorP2P(ErrorGenerator):
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()
return tm
......@@ -3,6 +3,7 @@ from scripts.Infrastructure.GeneratorManager import GeneratorManager
if __name__ == "__main__":
gm = GeneratorManager("./errors")
gm.generate("../gencodes", try_compile=True, generate_full_set=True)
gm.generate("../gencodes", try_compile=True, generate_full_set=False) # default
# gm.generate("../gencodes", try_compile=True, generate_full_set=True, max_mpi_version="3.1") #all cases that can compile for my local mpi installation
pass
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment