Commits (194)
......@@ -9,7 +9,7 @@ variables:
OS: "ubuntu"
OS_VERSION: "18.04"
REGISTRY: "ci.cluster.math.kit.edu"
IMAGE_NAME_MPP: "mpp-${CI_COMMIT_SHORT_SHA}-${OS}${OS_VERSION}"
IMAGE_NAME_MPP: "mpp-${CI_COMMIT_SHORT_SHA}-${OS}${OS_VERSION}-${CI_PIPELINE_ID}"
build-mpp:
......@@ -28,22 +28,30 @@ build-mpp:
tags: [ shell ]
unit-test-mpp:
ctest-mpp:
stage: test
variables:
GIT_STRATEGY: none
image: ${REGISTRY}/${IMAGE_NAME_MPP}
script:
- ls -al
- cd /mpp/build
- cmake .. -DBUILD_TESTS=ON -DUSE_CXSC=ON -DBUILD_IA_TESTS=ON -DUSE_SPACETIME=ON
- make -j
- cd tests
- ctest
dependencies: [ "build-mpp" ]
tags: [ docker ]
mpitest-mpp:
stage: test
variables:
GIT_STRATEGY: none
image: ${REGISTRY}/${IMAGE_NAME_MPP}
script:
- cd /mpp/build
- python3 mppyrun.py --mpi_tests=1
dependencies: [ "build-mpp" ]
tags: [ docker ]
trigger-tutorial:
stage: downstream
variables:
......@@ -103,7 +111,7 @@ deploy-mpp:
${REGISTRY}/mpp-${CI_COMMIT_TAG}-${OS}${OS_VERSION}
- docker push ${REGISTRY}/mpp-${CI_COMMIT_TAG}-${OS}${OS_VERSION}
only: [ tags ]
dependencies: [ "unit-test-mpp" ]
dependencies: [ "ctest-mpp", "mpitest-mpp" ]
tags: [ shell ]
......
......@@ -58,12 +58,19 @@ message(STATUS "Mpp directory= " ${PROJECT_MPP_DIR})
execute_process(COMMAND bash -c ${PROJECT_MPP_DIR}/doc/addCommitMsgHook.sh)
# Google test
# Todo
#set(BENCHMARK_OUT_FORMAT json CACHE STRING "BENCHMARK_OUT_FORMAT")
#set(BENCHMARK_OUT benchmarks CACHE STRING "BENCHMARK_OUT")
add_subdirectory(${PROJECT_MPP_DIR}/googletest)
include_directories(${PROJECT_MPP_DIR}/googletest/googletest/include)
include_directories(${PROJECT_MPP_DIR}/googletest/googlemock/include)
#-DBENCHMARK_ENABLE_TESTING=ON -DBENCHMARK_ENABLE_GTEST_TESTS=ON (als cmake flag funktionsfähig)
SET(BENCHMARK_ENABLE_TESTING OFF CACHE STRING "Disable testing of the benchmark library.")
add_subdirectory(${PROJECT_MPP_DIR}/benchmark)
include_directories(${PROJECT_MPP_DIR}/benchmark/include)
set(GTEST_LIB gtest gtest_main gmock gmock_main benchmark::benchmark)
set(GTEST_LIB gtest gtest_main gmock gmock_main
benchmark::benchmark benchmark::benchmark_main)
#---------------------------------------------------------------------------------------#
# Interval arithmetic options
......@@ -268,8 +275,6 @@ add_subdirectory(${PROJECT_MPP_DIR}/src)
#---------------------------------------------------------------------------------------#
# Tests
set(BENCHMARK_OUT_FORMAT json CACHE STRING "BENCHMARK_OUT_FORMAT")
set(BENCHMARK_OUT benchmarks CACHE STRING "BENCHMARK_OUT")
set(BUILD_TESTS ON CACHE STRING "BUILD_TESTS")
message(STATUS "Building mpp unit tests= " ${BUILD_TESTS})
set(BUILD_IA_TESTS OFF CACHE STRING "BUILD_IA_TESTS")
......@@ -280,3 +285,7 @@ enable_testing()
include_directories(${PROJECT_MPP_DIR}/tests)
add_subdirectory(${PROJECT_MPP_DIR}/tests)
file(COPY ${PROJECT_MPP_DIR}/python/__init__.py
${PROJECT_MPP_DIR}/python/mppyrun.py
${PROJECT_MPP_DIR}/python/mppy
DESTINATION ${PROJECT_BINARY_DIR})
\ No newline at end of file
......@@ -15,7 +15,7 @@ RUN mkdir -p build && \
cd build && \
cmake .. -DBUILD_TESTS=OFF && \
make -j && \
cmake .. -DBUILD_TESTS=OFF -DUSE_CXSC=ON -DBUILD_IA_TESTS=OFF && \
cmake .. -DBUILD_TESTS=ON -DUSE_CXSC=ON -DBUILD_IA_TESTS=ON -DUSE_SPACETIME=ON && \
make -j
# Default to a login shell
......
import os
import shutil
import socket
import time
import sys
from .utilities.directory_manager import DirectoryManager
from .utilities.log_utilities import LogParser
from .utilities.subprocess_utilities import SubprocessManager
sys.path.append('.')
sys.path.append('..')
from mpp.python.vtk_utilities import *
from mpp.python.log_utilities import LogParser
from mpp.python.subprocess_utilities import SubprocessManager
# Todo maybe include indented logger some day
class Mpp:
"""
Initialize
"""
PY_FILE_DIR = os.path.dirname(os.path.realpath(__file__))
MPP_ROOT_DIR = os.path.abspath(os.path.join(PY_FILE_DIR, '..'))
MPP_BUILD_DIR = os.path.abspath(os.path.join(MPP_ROOT_DIR, 'build'))
MPP_LOG_DIR = os.path.abspath(os.path.join(MPP_BUILD_DIR, 'log'))
MPP_DATA_DIR = os.path.abspath(os.path.join(MPP_BUILD_DIR, 'data'))
MPP_VTK_DATA_DIR = os.path.abspath(os.path.join(MPP_DATA_DIR, 'vtk'))
MPP_PY_DATA_DIR = os.path.abspath(os.path.join(MPP_DATA_DIR, 'py'))
PROJECT_ROOT_DIR = os.path.abspath(os.path.join(MPP_ROOT_DIR, '..'))
PROJECT_BUILD_DIR = os.path.abspath(os.path.join(PROJECT_ROOT_DIR, 'build'))
PROJECT_TESTS_DIR = os.path.abspath(os.path.join(PROJECT_BUILD_DIR, 'tests'))
PROJECT_LOG_DIR = os.path.abspath(os.path.join(PROJECT_BUILD_DIR, 'log'))
PROJECT_DATA_DIR = os.path.abspath(os.path.join(PROJECT_BUILD_DIR, 'data'))
PROJECT_VTK_DATA_DIR = os.path.abspath(os.path.join(PROJECT_DATA_DIR, 'vtk'))
PROJECT_PY_DATA_DIR = os.path.abspath(os.path.join(PROJECT_DATA_DIR, 'py'))
def __init__(self):
self.executable = 'M++'
self.kernels = 4
self.git_mpp_address = 'https://git.scc.kit.edu/mpp/mpp.git'
self.git_project_address = None
self.kernel_commit = None
self.cwd = self.PROJECT_BUILD_DIR
# Compiler args
self.cmake_args = ['cmake', '..']
self.make_args = ['make', '-j', str(self.kernels)]
def __init__(self, project_name='M++', executable='M++',
kernels=4, mute=False):
self.project_name = project_name
self.executable = executable
self.kernels = kernels
self.mute = mute
# Utility classes
self.log_file = os.path.join(self.PROJECT_LOG_DIR, 'log')
self.log_parser = LogParser(self.log_file)
self.dm = DirectoryManager(self.project_name)
self.sm = SubprocessManager(self.mute)
self.lp = LogParser(self.dm.LOG_FILE)
self.mute = False
self.subprocess_manager = SubprocessManager(self.mute)
self.cwd = self.dm.PROJECT_BUILD_DIR
self.cmake_args = ['cmake', '..']
self.make_args = ['make', '-j', str(self.kernels)]
self.data = {}
def create_working_dir(self):
if not os.path.isdir(self.PROJECT_BUILD_DIR):
os.mkdir(self.PROJECT_BUILD_DIR)
if not os.path.isdir(self.dm.PROJECT_BUILD_DIR):
os.mkdir(self.dm.PROJECT_BUILD_DIR)
def setup_cluster(self):
if not self.mute:
print('\n================ setup cluster ================\n')
if socket.gethostname().find('ma-pde') != -1:
return self.run_subprocess(['module', 'add', 'foss'],
self.PROJECT_ROOT_DIR, self.mute)
self.dm.PROJECT_ROOT_DIR, self.mute)
def run_cmake(self):
if not self.mute:
print('\n================ running cmake ================\n')
return self.run_subprocess(self.cmake_args, self.PROJECT_BUILD_DIR, self.mute)
return self.run_subprocess(self.cmake_args, self.dm.PROJECT_BUILD_DIR, self.mute)
def run_make(self):
if not self.mute:
print('\n================ running make ================\n')
return self.run_subprocess(self.make_args, self.PROJECT_BUILD_DIR, self.mute)
return self.run_subprocess(self.make_args, self.dm.PROJECT_BUILD_DIR, self.mute)
def kill(self):
if not self.mute:
......@@ -99,7 +79,7 @@ class Mpp:
kernels = self.kernels if kernels is None else kernels
kwargs = {} if kwargs is None else kwargs
if type(kernels) is dict:
kernels = {str(k).zfill(2):v for k,v in kernels.items()}
kernels = {str(k).zfill(2): v for k, v in kernels.items()}
with open(os.path.join(self.cwd, "hosts"), "w") as f:
for cid in reversed(sorted(kernels.keys())):
f.write("ma-pde{} slots={}\n".format(cid, kernels[cid]))
......@@ -115,52 +95,20 @@ class Mpp:
run_parameters.append(kwarg)
return run_parameters
"""
Interfaces to utility classes
"""
def run_subprocess(self, args, cwd, mute=False, return_log=False):
return self.subprocess_manager.run_subprocess(args, cwd, mute, return_log)
return self.sm.run_subprocess(args, cwd, mute, return_log)
def reset_data(self):
self.log_parser.reset_data()
self.lp.reset_data()
self.data = {}
def read_log(self, log_file=None):
return self.log_parser.read_log(log_file)
return self.lp.read_log(log_file)
def parse_log(self, log_file=None, additional_entries=None):
self.data = self.log_parser.parse_log(log_file, additional_entries)
self.data = self.lp.parse_log(log_file, additional_entries)
return self.data
def check_git_project(self):
if not self.mute:
print('\n================ check project ================\n')
return self.run_subprocess(['git', 'ls-remote', self.git_project_address],
self.PROJECT_ROOT_DIR)
def check_git_mpp(self):
if not self.mute:
print('\n================ check mpp git ================\n')
return self.run_subprocess(self.make_args, self.PROJECT_BUILD_DIR)
return self.run_subprocess(['git', 'ls-remote', self.git_mpp_address],
self.MPP_ROOT_DIR)
def git_pull_project(self, branch='master'):
rc_project = self.run_subprocess(['git', 'pull', 'origin', branch],
self.PROJECT_ROOT_DIR)
rc_mpp = self.git_pull_mpp()
rc_sub = self.run_subprocess(['git', 'submodule', 'update'],
self.PROJECT_ROOT_DIR)
if rc_project == 0 and rc_mpp == 0 and rc_sub == 0:
return 0
else:
return 1
def git_pull_mpp(self, branch='master'):
return self.run_subprocess(['git', 'pull', 'origin', branch],
self.MPP_ROOT_DIR)
@staticmethod
def remove_file(file):
if os.path.isfile(file):
......@@ -182,13 +130,13 @@ class Mpp:
print(e)
def clean_vtk(self):
self.clean_directory(self.PROJECT_VTK_DATA_DIR, True)
self.clean_directory(self.dm.PROJECT_VTK_DATA_DIR, True)
def clean_log(self):
self.clean_directory(self.PROJECT_LOG_DIR, False)
self.clean_directory(self.dm.PROJECT_LOG_DIR, False)
def clean_python_plots(self):
self.clean_directory(self.PROJECT_PY_DATA_DIR, False)
self.clean_directory(self.dm.PROJECT_PY_DATA_DIR, False)
def clean_data(self):
self.clean_vtk()
......@@ -196,24 +144,148 @@ class Mpp:
self.clean_python_plots()
def clean_build(self):
if os.path.isdir(self.PROJECT_BUILD_DIR):
self.clean_directory(self.PROJECT_BUILD_DIR, True)
if os.path.isdir(self.dm.PROJECT_BUILD_DIR):
self.clean_directory(self.dm.PROJECT_BUILD_DIR, True)
def clean_cmake_cache(self):
cmake_cache = self.PROJECT_BUILD_DIR + '/CMakeCache.txt'
cmake_cache = self.dm.PROJECT_BUILD_DIR + '/CMakeCache.txt'
self.remove_file(cmake_cache)
def set_cmake_arg(self, args):
# Todo
# 1. Compiler options:
if args.CXX_VERSION is not None:
self.cmake_args.append('-CXX_VERSION={}'.format(args.CXX_VERSION))
if args.COMPILER_VERSION is not None:
self.cmake_args.append('-COMPILER_VERSION={}'.format(args.COMPILER_VERSION))
if args.COMPILER_OPTIMIZE is not None:
self.cmake_args.append('-COMPILER_OPTIMIZE={}'.format(args.COMPILER_OPTIMIZE))
if args.NO_DEPRECATED is not None:
self.cmake_args.append('-DNO_DEPRECATED={}'.format(args.NO_DEPRECATED))
if args.BUILD_TESTS is not None:
self.cmake_args.append('-DBUILD_TESTS={}'.format(args.BUILD_TESTS))
if args.USE_SUPERLU30 is not None:
self.cmake_args.append('-NO_DEPRECATED={}'.format(args.NO_DEPRECATED))
# 2. Problem options:
if args.SPACE_DIM is not None:
self.cmake_args.append('-SPACE_DIM={}'.format(args.SPACE_DIM))
# 3. Transformation options:
if args.AFFINE_LINEAR_TRAFO is not None:
self.cmake_args.append(
'-DAFFINE_LINEAR_TRAFO={}'.format(args.AFFINE_LINEAR_TRAFO))
'-AFFINE_LINEAR_TRAFO={}'.format(args.AFFINE_LINEAR_TRAFO))
# 4. Constant options:
if args.CONST_GEOMETRIC_TOLERANCE is not None:
self.cmake_args.append(
'-CONST_GEOMETRIC_TOLERANCE={}'.format(args.CONST_GEOMETRIC_TOLERANCE))
if args.CONST_NEAR_ZERO is not None:
self.cmake_args.append('-CONST_NEAR_ZERO={}'.format(args.CONST_NEAR_ZERO))
if args.CONST_VERY_LARGE is not None:
self.cmake_args.append('-CONST_VERY_LARGE={}'.format(args.CONST_VERY_LARGE))
if args.CONST_INFTY is not None:
self.cmake_args.append('-CONST_INFTY={}'.format(args.CONST_INFTY))
# 5. Interval arithmetic options:
if args.USE_CXSC is not None:
self.cmake_args.append('-USE_CXSC={}'.format(args.USE_CXSC))
if args.BUILD_CXSC_TOOLBOX is not None:
self.cmake_args.append(
'-BUILD_CXSC_TOOLBOX={}'.format(args.BUILD_CXSC_TOOLBOX))
if args.BUILD_CXSC_EXAMPLES is not None:
self.cmake_args.append(
'-BUILD_CXSC_EXAMPLES={}'.format(args.BUILD_CXSC_EXAMPLES))
if args.BUILD_IA_VERIFY_QUAD is not None:
self.cmake_args.append(
'-BUILD_IA_VERIFY_QUAD={}'.format(args.BUILD_IA_VERIFY_QUAD))
# 6. Space time options:
if args.USE_SPACETIME is not None:
self.cmake_args.append('-USE_SPACETIME={}'.format(args.USE_SPACETIME))
# 7. Test options:
if args.BUILD_TESTS is not None:
self.cmake_args.append('-DBUILD_TESTS={}'.format(args.BUILD_TESTS))
self.cmake_args.append('-BUILD_TESTS={}'.format(args.BUILD_TESTS))
if args.BUILD_IA_TESTS is not None:
self.cmake_args.append('-BUILD_IA_TESTS={}'.format(args.BUILD_IA_TESTS))
def run_mpi_tests(self, kernels):
print('MPI Tests in project {}'.format(self.dm.PROJECT_BUILD_DIR))
rc_total = 0
file_path = os.path.join(self.dm.PROJECT_BUILD_DIR, 'mpi_tests.txt')
if not os.path.isfile(file_path):
raise OSError(os.path.join(self.dm.PROJECT_BUILD_DIR, 'mpi_tests.txt') +
' does not exist')
total_num_of_tests = len(open(file_path, 'r').readlines())
with open(file_path, 'r') as file:
for index, line in enumerate(file.readlines()):
# remove /, \n and cwd
self.executable = (line[:-1].replace(self.cwd, ''))[1:]
name = self.executable[self.executable.rfind('/') + 1:]
print(f' Start {index + 1:>3}: {name}')
start = time.time()
rc = self.run(kernels)
duration = time.time() - start
if rc == 0:
message = f'{index + 1:>3}/{total_num_of_tests:<3}' \
f' Test {index + 1:>4}: {name} '
message = message.ljust(64, '.')
message = message + ' Passed {:3.2f} sec'.format(duration)
print(message)
else:
message = f'{index + 1:>3}/{total_num_of_tests:<3}' \
f' Test {index + 1:>4}: {name} '
message = message.ljust(64, '.')
message = message + ' Failed {:3.2f} sec'.format(duration)
print(message)
rc_total += rc
return rc
def run_bench_tests(self, kernels):
print('MPP Benchmarks in project {}'.format(self.dm.PROJECT_BUILD_DIR))
rc_total = 0
file_path = os.path.join(self.dm.PROJECT_BUILD_DIR, 'mpp_bench.txt')
if not os.path.isfile(file_path):
raise OSError(os.path.join(self.dm.PROJECT_BUILD_DIR, 'mpp_bench.txt') +
' does not exist')
total_num_of_tests = len(open(file_path, 'r').readlines())
with open(file_path, 'r') as file:
for index, line in enumerate(file.readlines()):
# remove /, \n and cwd
self.executable = (line[:-1].replace(self.cwd, ''))[1:]
name = self.executable[self.executable.rfind('/') + 1:]
print(f' Start {index + 1:>3}: {name}')
bench_kwargs = {
"--benchmark_out": name,
"--benchmark_out_format": "json"
}
start = time.time()
rc = self.run(1, None, bench_kwargs)
duration = time.time() - start
if rc == 0:
message = f'{index + 1:>3}/{total_num_of_tests:<3}' \
f' Test {index + 1:>4}: {name} '
message = message.ljust(64, '.')
message = message + ' Passed {:3.2f} sec'.format(duration)
print(message)
else:
message = f'{index + 1:>3}/{total_num_of_tests:<3}' \
f' Test {index + 1:>4}: {name} '
message = message.ljust(64, '.')
message = message + ' Failed {:3.2f} sec'.format(duration)
print(message)
rc_total += rc
return rc
if __name__ == '__main__':
mpp = Mpp()
mpp.run_mpi_tests()
mpp = Mpp()
import unittest
import numpy as np
import os
import shutil
from vtk_utilities import *
from mpp.python.src.utilities.vtk_utilities import *
minimal_cell_scalar = "# vtk DataFile Version 2.0\nUnstructured Grid by M++\nASCII\nDATASET UNSTRUCTURED_GRID\nPOINTS 4 float\n0.000000 0.000000 0\n1.000000 0.000000 0\n1.000000 1.000000 0\n0.000000 1.000000 0\nCELLS 1 5\n4 0 1 2 3\nCELL_TYPES 1\n8\nCELL_DATA 1\nSCALARS scalar_value float 1\nLOOKUP_TABLE default\n1.0"
minimal_cell_vector = "# vtk DataFile Version 2.0\nUnstructured Grid by M++\nASCII\nDATASET UNSTRUCTURED_GRID\nPOINTS 4 float\n0.000000 0.000000 0\n1.000000 0.000000 0\n1.000000 1.000000 0\n0.000000 1.000000 0\nCELLS 1 5\n4 0 1 2 3\nCELL_TYPES 1\n8\nCELL_DATA 1\nVECTORS vector_value float\n-1.000000 1.000000 0"
......
......@@ -6,7 +6,7 @@ import pandas as pd
sys.path.append('.')
sys.path.append('..')
sys.path.append('../..')
from mpp.python.log_utilities import LogParser
from mpp.python.src.utilities.log_utilities import LogParser
class TestLogParser(TestCase):
......
from .log_utilities import LogParser
from .subprocess_utilities import SubprocessManager
import os
class DirectoryManager:
def __init__(self, project_name='M++'):
self.PY_FILE_DIR = os.path.dirname(os.path.realpath(__file__))
if project_name == 'M++':
self.MPP_ROOT_DIR = os.path.abspath(
os.path.join(self.PY_FILE_DIR, '../../../'))
self.PROJECT_ROOT_DIR = self.MPP_ROOT_DIR
else:
self.MPP_ROOT_DIR = os.path.abspath(
os.path.join(self.PY_FILE_DIR, '../../../mpp'))
self.PROJECT_ROOT_DIR = os.path.abspath(
os.path.join(self.MPP_ROOT_DIR, '..'))
self.MPP_BUILD_DIR = os.path.abspath(os.path.join(self.MPP_ROOT_DIR, 'build'))
self.MPP_LOG_DIR = os.path.abspath(os.path.join(self.MPP_BUILD_DIR, 'log'))
self.MPP_DATA_DIR = os.path.abspath(os.path.join(self.MPP_BUILD_DIR, 'data'))
self.MPP_VTK_DATA_DIR = os.path.abspath(os.path.join(self.MPP_DATA_DIR, 'vtk'))
self.MPP_PY_DATA_DIR = os.path.abspath(os.path.join(self.MPP_DATA_DIR, 'py'))
self.PROJECT_BUILD_DIR = os.path.abspath(
os.path.join(self.PROJECT_ROOT_DIR, 'build'))
self.PROJECT_LOG_DIR = os.path.abspath(
os.path.join(self.PROJECT_BUILD_DIR, 'log'))
self.PROJECT_DATA_DIR = os.path.abspath(
os.path.join(self.PROJECT_BUILD_DIR, 'data'))
self.PROJECT_VTK_DATA_DIR = os.path.abspath(
os.path.join(self.PROJECT_DATA_DIR, 'vtk'))
self.PROJECT_PY_DATA_DIR = os.path.abspath(
os.path.join(self.PROJECT_DATA_DIR, 'py'))
self.LOG_FILE = os.path.join(self.PROJECT_LOG_DIR, 'log')
......@@ -12,7 +12,7 @@ class SubprocessManager:
log = ""
if not os.path.exists(cwd):
raise OSError('working directory' + cwd + ' does not exist')
raise OSError('working directory ' + cwd + ' does not exist')
if not isinstance(args, list):
raise TypeError('expected args as list')
......
from mppy.mppy import Mpp
import sys
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser('Python interface to M++')
# Run options
parser.add_argument('-m', '--mute', type=int, default=1,
help='mutes output')
parser.add_argument('-exe', '--executable', type=str, default='M++',
help='name of executable')
parser.add_argument('-n', '--kernels', type=int, default=4,
help='number of kernels used by M++')
# Test options
parser.add_argument('--mpi_tests', type=int, default=0,
help='runs all registered tests in mpi_tests')
parser.add_argument('--mpp_tests', type=int, default=0,
help='runs all registered tests in ctest')
parser.add_argument('--bench_tests', type=int, default=0,
help='runs all registered tests in mpp_bench')
args = parser.parse_args()
project_name = 'M++'
with open('CMakeCache.txt', 'r') as file:
for index, line in enumerate(file.readlines()):
if line.find('CMAKE_PROJECT_NAME') != -1:
project_name = line[line.rfind('=') + 1:line.rfind('\n')]
mpp = Mpp(project_name, executable=args.executable,
kernels=args.kernels, mute=bool(args.mute))
if args.mpi_tests:
mpp.run_mpi_tests(args.kernels)
if args.mpp_tests:
mpp.run_mpp_tests(args.kernels)
if args.bench_tests:
mpp.run_bench_tests(args.kernels)
import argparse
import sys
import setuptools
sys.path.append('.')
sys.path.append('..')
from mpp.python.mppy import *
# Todo
setuptools.setup(
name="MPP-USER",
version="1.0",
description="Python module to connecting to Mpp-Applications",
packages=setuptools.find_packages(
def setup(mpp):
if not isinstance(mpp, Mpp):
raise TypeError
parser = argparse.ArgumentParser('Python interface to M++')
),
# Parse mppy properties
parser.add_argument('--mute', type=int, help='mutes output')
parser.add_argument('--executable', type=str, help='name of executable')
parser.add_argument('--kernels', type=int, help='number of kernels used by M++')
parser.add_argument('--commit', type=str, help='hash to mpp kernel commit')
install_requires=[
],
# Parse cmake arguments
parser.add_argument('--NO_DEPRECATED', type=str, help='CMake option')
parser.add_argument('--BUILD_TESTS', type=str, help='CMake option')
parser.add_argument('--PROBLEM_NO_TIME', type=str, help='CMake option')
parser.add_argument('--PROBLEM_1D', type=str, help='CMake option')
parser.add_argument('--PROBLEM_2D', type=str, help='CMake option')
parser.add_argument('--USE_SUPERLU30', type=str, help='CMake option')
parser.add_argument('--AFFINE_LINEAR_TRAFO', type=str, help='CMake option')
args = parser.parse_args()
sys.argv = [sys.argv[0]] # Hack
# Set mppy properties
mpp.mute = bool(args.mute) if args.mute is not None else mpp.mute
mpp.executable = args.executable if args.executable is not None else mpp.executable
mpp.kernels = args.kernels if args.kernels is not None else mpp.kernels
mpp.kernel_commit = args.commit if args.commit is not None else mpp.kernel_commit
mpp.set_cmake_arg(args)
if mpp.mute:
print('----------------------------------------------------------------------')
print('Test ID Duration')
print('----------------------------------------------------------------------')
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.6',
)
\ No newline at end of file
......@@ -8,6 +8,7 @@ set(basic_src
utility/Assertion.cpp
utility/M_IOFiles.cpp
utility/MemoryLogger.cpp
parallel/Buffer.cpp
parallel/ExchangeBuffer.cpp
parallel/Parallel.cpp
parallel/Communicator.cpp
......
......@@ -102,9 +102,9 @@ public:
Exit("Point not time dependent!")
}
PointT<T, sDim, tDim> CopyWithT(double t) {
PointT<T, sDim, tDim> CopyWithT(double t) const {
if constexpr(tDim > 0) {
return PointT<T, sDim, tDim>(this).WithT(t);
return PointT<T, sDim, tDim>(*this).WithT(t);
}
Exit("Point not time dependent!")
}
......
#include "Buffer.hpp"
Buffer::Buffer(size_t m) : n(m), max_n(0) {
if (m)
b = new char[m];
else
b = 0;
p = b;
}
Buffer::~Buffer() {
Destruct();
}
void Buffer::Destruct() {
if (b) {
delete[] b;
b = 0;
max_n = n;
}
p = 0;
n = 0;
}
size_t Buffer::size() const {
return size_t(p - b);
}
size_t Buffer::Size() const {
return n;
}
void Buffer::rewind() {
if (max_n > 0 && !b)
resize(max_n);
p = b;
}
char *Buffer::operator()() {
return b;
}
void Buffer::resize(size_t m) {
int s = size();
if (s && b) {
char *tmp = new char[m];
memcpy(tmp, b, s);
delete[] b;
p = tmp + s;
b = tmp;
} else {
b = new char[m];
p = b;
}
n = m;
}
#ifndef BUFFER_HPP
#define BUFFER_HPP
#include <cstdio>
#include <cstring>
class Buffer {
private:
char *b;
char *p;
size_t n;
size_t max_n;
size_t BufferSize = 512000;
public:
Buffer(size_t m = 0);
~Buffer();
void Destruct();
size_t size() const;
size_t Size() const;
void rewind();
char *operator()();
void resize(size_t m);
template<typename T>
Buffer &fill(const T &type, size_t m) {
if (size() + m > n) {
size_t j = size_t(((size() + m) - n) / BufferSize) + 1;
resize(n + j * BufferSize);
}
memcpy(p, &type, m);
p += m; // Todo double check purpose
return *this;
}
template<typename T>
Buffer &read(T &type, size_t m) {
memcpy(&type, p, m);
p += m; // Todo double check purpose
return *this;
}
template<typename T>
Buffer &operator<<(const T &type) {
size_t m = sizeof(type);
return fill(type, m);
}
template<typename T>
Buffer &operator>>(T &type) {
size_t m = sizeof(type);
return read(type, m);
}
};
#endif //BUFFER_HPP
#include "Communicator.hpp"
#include <iostream>
Communicator::Communicator(MPI_Comm comm, int splitLevel, int color) :
P(0), p(0), mpiComm(comm), splitLevel(splitLevel), color(color) {
MPI_Comm_size(comm, &P);
MPI_Comm_rank(comm, &p);
}
Communicator::~Communicator() {
if (mpiComm != MPI_COMM_WORLD)
MPI_Comm_free(&mpiComm);
}
bool Communicator::Master() const {
return (p == 0);
......@@ -22,15 +34,154 @@ int Communicator::SplitLevel() const {
}
Communicator *Communicator::Split() const {
int newColor = p * 2 / P;
int worldSize;
int worldRank;
MPI_Comm_size(MPI_COMM_WORLD, &worldSize);
MPI_Comm_rank(MPI_COMM_WORLD, &worldRank);
int newColor = worldRank * pow(2, splitLevel + 1) / worldSize;
MPI_Comm newComm;
MPI_Comm_split(mpiComm, newColor, p, &newComm);
return new Communicator(newComm, splitLevel + 1, newColor);
}
void Communicator::Broadcast(void *data, size_t size, int q) {
char *Data = (char *) data;
while (size > MaxBroadcastSize) {
MPI_Bcast(Data, MaxBroadcastSize, MPI_BYTE, q, mpiComm);
MPI_Barrier(mpiComm);
Data += MaxBroadcastSize;
size -= MaxBroadcastSize;
}
if (size > 0)
MPI_Bcast(Data, size, MPI_BYTE, q, mpiComm);
MPI_Barrier(mpiComm);
}
void Communicator::PrintInfo() const {
std::cout << "\tProc rank: " << p
<< "\tComm size: " << P
<< "\tComm color: " << color
<< "\tSplit level: " << splitLevel << std::endl;
}
void Communicator::Sum(int *a, size_t n) {
int *b = new int[n];
MPI_Allreduce(a, b, n, MPI_INT, MPI_SUM, mpiComm);
memcpy(a, b, sizeof(int) * n);
delete[] b;
}
void Communicator::Sum(double *a, size_t n) {
double *b = new double[n];
MPI_Allreduce(a, b, n, MPI_DOUBLE, MPI_SUM, mpiComm);
memcpy(a, b, sizeof(double) * n);
delete[] b;
}
void Communicator::Sum(size_t *a, size_t n) {
double *b = new double[n];
MPI_Allreduce(a, b, n, MPI_LONG, MPI_SUM, mpiComm);
memcpy(a, b, sizeof(size_t) * n);
delete[] b;
}
void Communicator::Sum(std::complex<double> *z, size_t n) {
double *a = new double[2 * n];
double *b = new double[2 * n];
for (int i = 0; i < n; ++i) {
a[i] = real(z[i]);
a[i + n] = imag(z[i]);
}
MPI_Allreduce(a, b, 2 * n, MPI_DOUBLE, MPI_SUM, mpiComm);
for (int i = 0; i < n; ++i)
z[i] = std::complex<double>(b[i], b[i + n]);
delete[] a;
delete[] b;
}
double Communicator::Min(double a) {
double b;
MPI_Allreduce(&a, &b, 1, MPI_DOUBLE, MPI_MIN, mpiComm);
return b;
}
int Communicator::Min(int a) {
int b;
MPI_Allreduce(&a, &b, 1, MPI_INT, MPI_MIN, mpiComm);
return b;
}
long unsigned int Communicator::Min(long unsigned int a) {
long unsigned int b;
MPI_Allreduce(&a, &b, 1, MPI_UNSIGNED_LONG, MPI_MIN, mpiComm);
return b;
}
double Communicator::Max(double a) {
double b;
MPI_Allreduce(&a, &b, 1, MPI_DOUBLE, MPI_MAX, mpiComm);
return b;
}
int Communicator::Max(int a) {
int b;
MPI_Allreduce(&a, &b, 1, MPI_INT, MPI_MAX, mpiComm);
return b;
}
long unsigned int Communicator::Max(long unsigned int a) {
long unsigned int b;
MPI_Allreduce(&a, &b, 1, MPI_UNSIGNED_LONG, MPI_MAX, mpiComm);
return b;
}
void Communicator::Communicate(ExchangeBuffer &exBuffer) {
const int tag = 27;
auto sendRequest = new MPI_Request[exBuffer.SendMessages()];
auto recvRequest = new MPI_Request[exBuffer.RecvMessages()];
MPI_Request *r = recvRequest;
for (int q = 0; q < Size(); ++q)
for (int k = exBuffer.Messages(q); k < exBuffer.Messages(q + 1); ++k)
if (exBuffer.MessageDest(k) == Proc())
MPI_Irecv(exBuffer.Receive(q)(), exBuffer.MessageSize(k),
MPI_BYTE, q, tag, mpiComm, r++);
r = sendRequest;
for (int k = exBuffer.Messages(Proc());
k < exBuffer.Messages(Proc() + 1); ++k) {
MPI_Isend(exBuffer.Send(exBuffer.MessageDest(k))(), exBuffer.MessageSize(k),
MPI_BYTE, exBuffer.MessageDest(k), tag, mpiComm, r++);
}
MPI_Status st;
r = sendRequest;
for (int k = 0; k < exBuffer.SendMessages(); ++k) MPI_Wait(r++, &st);
r = recvRequest;
for (int k = 0; k < exBuffer.RecvMessages(); ++k) MPI_Wait(r++, &st);
delete[] sendRequest;
delete[] recvRequest;
}
bool Communicator::And(bool b) {
int a = 0;
if (b) a = 1;
a = Min(a);
if (a == 0) return false;
return true;
}
bool Communicator::Or(bool b) {
int a = 0;
if (b) a = 1;
a = Max(a);
if (a == 1) return true;
return false;
}
void Communicator::Barrier() {
// Blocks the caller until all group members have called it.
// The call returns at any process only after all group
// members have entered the call.
MPI_Barrier(mpiComm);
}
#ifndef COMMUNICATOR_HPP
#define COMMUNICATOR_HPP
#include "ExchangeBuffer.hpp"
#include "mpi.h"
#include <vector>
#include <complex>
constexpr size_t MaxBroadcastSize = 2147483647; // 2^31 - 1
class Communicator {
protected:
int P; // communicator size
// communicator size
int P;
int p; // process rank
// process rank
int p;
int color; // communicator color
// communicator color
int color;
// communicators are divided into 2^splitLevel partitions
int splitLevel;
MPI_Comm mpiComm;
public:
MPI_Comm mpiComm; // Todo make private
Communicator(MPI_Comm comm, int splitLevel, int color);
Communicator(MPI_Comm comm, int splitLevel, int color) :
P(0), p(0), mpiComm(comm), splitLevel(splitLevel), color(color) {
MPI_Comm_size(comm, &P);
MPI_Comm_rank(comm, &p);
}
~Communicator() {
if (mpiComm != MPI_COMM_WORLD)
MPI_Comm_free(&mpiComm);
}
~Communicator();
bool Master() const;
......@@ -43,21 +44,39 @@ public:
int SplitLevel() const;
virtual void PrintInfo() const;
Communicator *Split() const;
void Broadcast(void *data, size_t size, int q = 0) {
char *Data = (char *) data;
while (size > MaxBroadcastSize) {
MPI_Bcast(Data, MaxBroadcastSize, MPI_BYTE, q, mpiComm);
MPI_Barrier(mpiComm);
Data += MaxBroadcastSize;
size -= MaxBroadcastSize;
}
if (size > 0) {
MPI_Bcast(Data, size, MPI_BYTE, q, mpiComm);
}
MPI_Barrier(mpiComm);
}
void Broadcast(void *data, size_t size, int q = 0);
void Sum(int *a, size_t n);
void Sum(double *a, size_t n);
void Sum(size_t *a, size_t n);
void Sum(std::complex<double> *z, size_t n);
double Min(double a);
int Min(int a);
long unsigned int Min(long unsigned int a);
double Max(double a);
int Max(int a);
long unsigned int Max(long unsigned int a);
void Communicate(ExchangeBuffer &exBuffer);
bool And(bool b);
bool Or(bool b);
void Barrier();
template<typename T>
void Broadcast(T &t) {
......@@ -69,8 +88,6 @@ public:
T data = t;
Broadcast(&data, sizeof(t));
}
virtual void PrintInfo() const;
};
struct WorldCommunicator : public Communicator {
......
......@@ -2,185 +2,155 @@
#include "Parallel.hpp"
using namespace std;
Exchange::Exchange() : n(PPM->size() + 1), s(PPM->size(), 0),
n_send(0), n_recv(0), init(false) {}
void Exchange::Destruct() {
n.clear();
d.clear();
s.clear();
}
size_t Exchange::SendSize(int q) const {
for (int k = n[PPM->proc()]; k < n[PPM->proc() + 1]; ++k)
if (d[k] == q) return s[k];
return 0;
}
size_t Exchange::SendSize() const {
size_t b = 0;
for (int k = n[0]; k < n[PPM->size()]; ++k)
b += s[k];
return b;
}
size_t Exchange::ReceiveSize(int q) const {
for (int k = n[q]; k < n[q + 1]; ++k)
if (d[k] == PPM->proc()) return s[k];
return 0;
}
void Exchange::CommunicateSize() {
for (int q = 0; q < PPM->size(); ++q) n[q] = 0;
for (int q = 0; q < PPM->size(); ++q) if (s[q]) ++(n[PPM->proc()]);
PPM->Sum(n);
for (int q = PPM->size(); q > 0; --q) n[q] = n[q - 1];
n[0] = 0;
for (int q = 0; q < PPM->size(); ++q) n[q + 1] += n[q];
d.resize(n[PPM->size()], 0);
vector<size_t> tmp(n[PPM->size()], 0);
int k = n[PPM->proc()];
for (int q = 0; q < PPM->size(); ++q)
if (s[q]) {
tmp[k] = s[q];
d[k++] = q;
ExchangeBuffer::ExchangeBuffer(int splitLevel)
: numOfMessages(PPM->Size(splitLevel) + 1),
sendSizes(PPM->Size(splitLevel), 0),
numberOfSendMessages(0),
numberOfReceiveMessages(0),
init(false), splitLevel(splitLevel),
sendBuffers(PPM->Size(splitLevel)),
receiveBuffers(PPM->Size(splitLevel)) {}
ExchangeBuffer::~ExchangeBuffer() {
Destruct();
}
void ExchangeBuffer::Destruct() {
ClearBuffers();
sendBuffers.clear();
receiveBuffers.clear();
numOfMessages.clear();
destinations.clear();
sendSizes.clear();
}
bool ExchangeBuffer::IsInitialized() const {
return init;
}
void ExchangeBuffer::CommunicateSize() {
for (int q = 0; q < PPM->Size(splitLevel); ++q)
numOfMessages[q] = 0;
for (int q = 0; q < PPM->Size(splitLevel); ++q)
if (sendSizes[q]) ++(numOfMessages[PPM->Proc(splitLevel)]);
PPM->SumOnSplitLevel(numOfMessages, splitLevel);
for (int q = PPM->Size(splitLevel); q > 0; --q)
numOfMessages[q] = numOfMessages[q - 1];
numOfMessages[0] = 0;
for (int q = 0; q < PPM->Size(splitLevel); ++q)
numOfMessages[q + 1] += numOfMessages[q];
destinations.resize(numOfMessages[PPM->Size(splitLevel)], 0);
std::vector<size_t> tmp(numOfMessages[PPM->Size(splitLevel)], 0);
int k = numOfMessages[PPM->Proc(splitLevel)];
for (int q = 0; q < PPM->Size(splitLevel); ++q) {
if (sendSizes[q]) {
tmp[k] = sendSizes[q];
destinations[k++] = q;
}
}
s = tmp;
PPM->Sum(s);
PPM->Sum(d);
n_send = n[PPM->proc() + 1] - n[PPM->proc()];
n_recv = 0;
for (int k = 0; k < n[PPM->size()]; ++k) if (d[k] == PPM->proc()) ++n_recv;
init = true;
}
Logging &operator<<(Logging &s, const Exchange &E) {
s << " on " << PPM->proc() << " :"
<< "send " << E.SendMessages() << " : ";
for (int k = E.Messages(PPM->proc()); k < E.Messages(PPM->proc() + 1); ++k)
s << E.MessageDest(k) << "|" << E.MessageSize(k) << " ";
s << "recv " << E.RecvMessages() << " : ";
for (int q = 0; q < PPM->size(); ++q)
for (int k = E.Messages(q); k < E.Messages(q + 1); ++k)
if (E.MessageDest(k) == PPM->proc())
s << q << "|" << E.MessageSize(k) << " ";
return s << endl;
}
Buffer::Buffer(size_t m) : n(m), max_n(0) {
if (m) {
b = new char[m];
} else b = 0;
p = b;
}
void Buffer::Destruct() {