diff --git a/src/pystencils/backend/jit/__init__.py b/src/pystencils/backend/jit/__init__.py index 6953f8daffe1d7cfb12e10e9e22bda7b4838f038..b3340a9ab7ffb0be2ea9812b0684178102105e20 100644 --- a/src/pystencils/backend/jit/__init__.py +++ b/src/pystencils/backend/jit/__init__.py @@ -29,15 +29,11 @@ Both are available here through `LegacyCpuJit` and `LegacyGpuJit`. from .jit import JitBase, NoJit, LegacyCpuJit, LegacyGpuJit no_jit = NoJit() -legacy_cpu = LegacyCpuJit() -legacy_gpu = LegacyGpuJit() __all__ = [ "JitBase", "LegacyCpuJit", - "legacy_cpu", "NoJit", "no_jit", "LegacyGpuJit", - "legacy_gpu", ] diff --git a/src/pystencils/backend/jit/cpu_extension_module.py b/src/pystencils/backend/jit/cpu_extension_module.py index f2c0d3ff98ee5e762cee8419b46d6a4b64b1bb61..739aefb272a1a018db4609852561fcdf2f48bf5c 100644 --- a/src/pystencils/backend/jit/cpu_extension_module.py +++ b/src/pystencils/backend/jit/cpu_extension_module.py @@ -112,8 +112,6 @@ class PsKernelExtensioNModule: "mod_" + hashlib.sha256(code.encode() + header_hash).hexdigest() ) - from ...cpu.cpujit import create_module_boilerplate_code - code += create_module_boilerplate_code(self._code_hash, self._kernels.keys()) self._code_string = code @@ -142,6 +140,35 @@ def emit_call_wrapper(function_name: str, kernel: PsKernelFunction) -> str: return builder.resolve(function_name) +template_module_boilerplate = """ +static PyMethodDef method_definitions[] = {{ + {method_definitions} + {{NULL, NULL, 0, NULL}} +}}; + +static struct PyModuleDef module_definition = {{ + PyModuleDef_HEAD_INIT, + "{module_name}", /* name of module */ + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + method_definitions +}}; + +PyMODINIT_FUNC +PyInit_{module_name}(void) +{{ + return PyModule_Create(&module_definition); +}} +""" + + +def create_module_boilerplate_code(module_name, names): + method_definition = '{{"{name}", (PyCFunction){name}, METH_VARARGS | METH_KEYWORDS, ""}},' + method_definitions = "\n".join([method_definition.format(name=name) for name in names]) + return template_module_boilerplate.format(module_name=module_name, method_definitions=method_definitions) + + class CallWrapperBuilder: TMPL_EXTRACT_SCALAR = """ PyObject * obj_{name} = PyDict_GetItemString(kwargs, "{name}"); diff --git a/src/pystencils/backend/jit/jit.py b/src/pystencils/backend/jit/jit.py index 4e9ae46b61f7018485976f3cfebcbce6e46641c3..842a2f8da52bb13436e469491291fd6b99439581 100644 --- a/src/pystencils/backend/jit/jit.py +++ b/src/pystencils/backend/jit/jit.py @@ -31,7 +31,7 @@ class LegacyCpuJit(JitBase): """Wrapper around ``pystencils.cpu.cpujit``""" def compile(self, kernel: PsKernelFunction) -> Callable[..., None]: - from ...cpu.cpujit import compile_and_load + from .legacy_cpu import compile_and_load return compile_and_load(kernel) @@ -40,6 +40,6 @@ class LegacyGpuJit(JitBase): """Wrapper around ``pystencils.gpu.gpujit``""" def compile(self, kernel: PsKernelFunction) -> Callable[..., None]: - from ...gpu.gpujit import make_python_function + from ...old.gpu.gpujit import make_python_function return make_python_function(kernel) diff --git a/src/pystencils/backend/jit/legacy_cpu.py b/src/pystencils/backend/jit/legacy_cpu.py new file mode 100644 index 0000000000000000000000000000000000000000..7906bb5e59bc9f45bd2dcbcc6e2c0eadd4b1a3c1 --- /dev/null +++ b/src/pystencils/backend/jit/legacy_cpu.py @@ -0,0 +1,380 @@ +r""" + +*pystencils* automatically searches for a compiler, so in most cases no explicit configuration is required. +On Linux make sure that 'gcc' and 'g++' are installed and in your path. +On Windows a recent Visual Studio installation is required. +In case anything does not work as expected or a special compiler should be used, changes can be specified +in a configuration file. + +*pystencils* looks for a configuration file in JSON format at the following locations in the listed order. + +1. at the path specified in the environment variable ``PYSTENCILS_CONFIG`` +2. in the current working direction for a file named ``pystencils.json`` +3. or in your home directory at ``~/.config/pystencils/config.json`` (Linux) or + ``%HOMEPATH%\.pystencils\config.json`` (Windows) + +If no configuration file is found, a default configuration is created at the above-mentioned location in your home. +So run *pystencils* once, then edit the created configuration file. + + +Compiler Config (Linux) +----------------------- + +- **'os'**: should be detected automatically as 'linux' +- **'command'**: path to C++ compiler (defaults to 'g++') +- **'flags'**: space separated list of compiler flags. Make sure to activate OpenMP in your compiler +- **'restrict_qualifier'**: the 'restrict' qualifier is not standardized across compilers. + For most Linux compilers the qualifier is ``__restrict__`` + + +Compiler Config (Windows) +------------------------- + +*pystencils* uses the mechanism of *setuptools.msvc* to search for a compilation environment. +Then 'cl.exe' is used to compile. + +- **'os'**: should be detected automatically as 'windows' +- **'msvc_version'**: either a version number, year number, 'auto' or 'latest' for automatic detection of latest + installed version or 'setuptools' for setuptools-based detection. Alternatively path to folder + where Visual Studio is installed. This path has to contain a file called 'vcvarsall.bat' +- **'arch'**: 'x86' or 'x64' +- **'flags'**: flags passed to 'cl.exe', make sure OpenMP is activated +- **'restrict_qualifier'**: the 'restrict' qualifier is not standardized across compilers. + For Windows compilers the qualifier should be ``__restrict`` + +""" +from appdirs import user_cache_dir, user_config_dir +from collections import OrderedDict +import importlib.util +import json +import os +import platform +import shutil +import subprocess +import sysconfig +import tempfile +import time +import warnings + + +from ..ast import PsKernelFunction +from .cpu_extension_module import PsKernelExtensioNModule + +from .msvc_detection import get_environment +from pystencils.include import get_pystencils_include_path +from pystencils.kernel_wrapper import KernelWrapper +from pystencils.utils import atomic_file_write, recursive_dict_update + + +def make_python_function(kernel_function_node, custom_backend=None): + """ + Creates C code from the abstract syntax tree, compiles it and makes it accessible as Python function + + The parameters of the kernel are: + - numpy arrays for each field used in the kernel. The keyword argument name is the name of the field + - all symbols which are not defined in the kernel itself are expected as parameters + + :param kernel_function_node: the abstract syntax tree + :param custom_backend: use own custom printer for code generation + :return: kernel functor + """ + result = compile_and_load(kernel_function_node, custom_backend) + return result + + +def set_config(config): + """ + Override the configuration provided in config file + + Configuration of compiler parameters: + If this function is not called the configuration is taken from a config file in JSON format which + is searched in the following locations in the order specified: + - at location provided in environment variable PYSTENCILS_CONFIG (if this variable exists) + - a file called ".pystencils.json" in the current working directory + - ~/.pystencils.json in your home + If none of these files exist a file ~/.pystencils.json is created with a default configuration using + the GNU 'g++' + + An example JSON file with all possible keys. If not all keys are specified, default values are used + `` + { + 'compiler' : + { + "command": "/software/intel/2017/bin/icpc", + "flags": "-Ofast -DNDEBUG -fPIC -march=native -fopenmp", + "env": { + "LM_PROJECT": "iwia", + } + } + } + `` + """ + global _config + _config = config.copy() + + +def get_configuration_file_path(): + config_path_in_home = os.path.join(user_config_dir('pystencils'), 'config.json') + + # 1) Read path from environment variable if found + if 'PYSTENCILS_CONFIG' in os.environ: + return os.environ['PYSTENCILS_CONFIG'], True + # 2) Look in current directory for pystencils.json + elif os.path.exists("pystencils.json"): + return "pystencils.json", True + # 3) Try ~/.pystencils.json + elif os.path.exists(config_path_in_home): + return config_path_in_home, True + else: + return config_path_in_home, False + + +def create_folder(path, is_file): + if is_file: + path = os.path.split(path)[0] + try: + os.makedirs(path) + except os.error: + pass + + +def read_config(): + if platform.system().lower() == 'linux': + default_compiler_config = OrderedDict([ + ('os', 'linux'), + ('command', 'g++'), + ('flags', '-Ofast -DNDEBUG -fPIC -march=native -fopenmp -std=c++11'), + ('restrict_qualifier', '__restrict__') + ]) + if platform.machine().startswith('ppc64') or platform.machine() == 'arm64': + default_compiler_config['flags'] = default_compiler_config['flags'].replace('-march=native', + '-mcpu=native') + elif platform.system().lower() == 'windows': + default_compiler_config = OrderedDict([ + ('os', 'windows'), + ('msvc_version', 'latest'), + ('arch', 'x64'), + ('flags', '/Ox /fp:fast /OpenMP /arch:avx'), + ('restrict_qualifier', '__restrict') + ]) + if platform.machine() == 'ARM64': + default_compiler_config['arch'] = 'ARM64' + default_compiler_config['flags'] = default_compiler_config['flags'].replace(' /arch:avx', '') + elif platform.system().lower() == 'darwin': + default_compiler_config = OrderedDict([ + ('os', 'darwin'), + ('command', 'clang++'), + ('flags', '-Ofast -DNDEBUG -fPIC -march=native -Xclang -fopenmp -std=c++11'), + ('restrict_qualifier', '__restrict__') + ]) + if platform.machine() == 'arm64': + default_compiler_config['flags'] = default_compiler_config['flags'].replace('-march=native ', '') + for libomp in ['/opt/local/lib/libomp/libomp.dylib', '/usr/local/lib/libomp.dylib', + '/opt/homebrew/lib/libomp.dylib']: + if os.path.exists(libomp): + default_compiler_config['flags'] += ' ' + libomp + break + else: + raise NotImplementedError('Generation of default compiler flags for %s is not implemented' % + (platform.system(),)) + + default_cache_config = OrderedDict([ + ('object_cache', os.path.join(user_cache_dir('pystencils'), 'objectcache')), + ('clear_cache_on_start', False), + ]) + + default_config = OrderedDict([('compiler', default_compiler_config), + ('cache', default_cache_config)]) + + config_path, config_exists = get_configuration_file_path() + config = default_config.copy() + if config_exists: + with open(config_path, 'r') as json_config_file: + loaded_config = json.load(json_config_file) + config = recursive_dict_update(config, loaded_config) + else: + create_folder(config_path, True) + with open(config_path, 'w') as f: + json.dump(config, f, indent=4) + + if config['cache']['object_cache'] is not False: + config['cache']['object_cache'] = os.path.expanduser(config['cache']['object_cache']).format(pid=os.getpid()) + + clear_cache_on_start = False + cache_status_file = os.path.join(config['cache']['object_cache'], 'last_config.json') + if os.path.exists(cache_status_file): + # check if compiler config has changed + last_config = json.load(open(cache_status_file, 'r')) + if set(last_config.items()) != set(config['compiler'].items()): + clear_cache_on_start = True + else: + for key in last_config.keys(): + if last_config[key] != config['compiler'][key]: + clear_cache_on_start = True + + if config['cache']['clear_cache_on_start'] or clear_cache_on_start: + shutil.rmtree(config['cache']['object_cache'], ignore_errors=True) + + create_folder(config['cache']['object_cache'], False) + with tempfile.NamedTemporaryFile('w', dir=os.path.dirname(cache_status_file), delete=False) as f: + json.dump(config['compiler'], f, indent=4) + os.replace(f.name, cache_status_file) + + if config['compiler']['os'] == 'windows': + msvc_env = get_environment(config['compiler']['msvc_version'], config['compiler']['arch']) + if 'env' not in config['compiler']: + config['compiler']['env'] = {} + config['compiler']['env'].update(msvc_env) + + return config + + +_config = read_config() + + +def get_compiler_config(): + return _config['compiler'] + + +def get_cache_config(): + return _config['cache'] + + +def add_or_change_compiler_flags(flags): + if not isinstance(flags, list) and not isinstance(flags, tuple): + flags = [flags] + + compiler_config = get_compiler_config() + cache_config = get_cache_config() + cache_config['object_cache'] = False # disable cache + + for flag in flags: + flag = flag.strip() + if '=' in flag: + base = flag.split('=')[0].strip() + else: + base = flag + + new_flags = [c for c in compiler_config['flags'].split() if not c.startswith(base)] + new_flags.append(flag) + compiler_config['flags'] = ' '.join(new_flags) + + +def clear_cache(): + cache_config = get_cache_config() + if cache_config['object_cache'] is not False: + shutil.rmtree(cache_config['object_cache'], ignore_errors=True) + create_folder(cache_config['object_cache'], False) + + +def load_kernel_from_file(module_name, function_name, path): + try: + spec = importlib.util.spec_from_file_location(name=module_name, location=path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + except ImportError: + warnings.warn(f"Could not load {path}, trying on more time in 5 seconds ...") + time.sleep(5) + spec = importlib.util.spec_from_file_location(name=module_name, location=path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + + return getattr(mod, function_name) + + +def run_compile_step(command): + compiler_config = get_compiler_config() + config_env = compiler_config['env'] if 'env' in compiler_config else {} + compile_environment = os.environ.copy() + compile_environment.update(config_env) + try: + shell = True if compiler_config['os'].lower() == 'windows' else False + subprocess.check_output(command, env=compile_environment, stderr=subprocess.STDOUT, shell=shell) + except subprocess.CalledProcessError as e: + print(" ".join(command)) + print(e.output.decode('utf8')) + raise e + + +def compile_module(code, code_hash, base_dir, compile_flags=None): + if compile_flags is None: + compile_flags = [] + + compiler_config = get_compiler_config() + extra_flags = ['-I' + sysconfig.get_paths()['include'], '-I' + get_pystencils_include_path()] + compile_flags + + if compiler_config['os'].lower() == 'windows': + lib_suffix = '.pyd' + object_suffix = '.obj' + windows = True + else: + lib_suffix = '.so' + object_suffix = '.o' + windows = False + + src_file = os.path.join(base_dir, code_hash + ".cpp") + lib_file = os.path.join(base_dir, code_hash + lib_suffix) + object_file = os.path.join(base_dir, code_hash + object_suffix) + + if not os.path.exists(object_file): + try: + with open(src_file, 'x') as f: + code.write_to_file(f) + except FileExistsError: + pass + + if windows: + compile_cmd = ['cl.exe', '/c', '/EHsc'] + compiler_config['flags'].split() + compile_cmd += [*extra_flags, src_file, '/Fo' + object_file] + run_compile_step(compile_cmd) + else: + with atomic_file_write(object_file) as file_name: + compile_cmd = [compiler_config['command'], '-c'] + compiler_config['flags'].split() + compile_cmd += [*extra_flags, '-o', file_name, src_file] + run_compile_step(compile_cmd) + + # Linking + if windows: + config_vars = sysconfig.get_config_vars() + py_lib = os.path.join(config_vars["installed_base"], "libs", + f"python{config_vars['py_version_nodot']}.lib") + run_compile_step(['link.exe', py_lib, '/DLL', '/out:' + lib_file, object_file]) + elif platform.system().lower() == 'darwin': + with atomic_file_write(lib_file) as file_name: + run_compile_step([compiler_config['command'], '-shared', object_file, '-o', file_name, '-undefined', + 'dynamic_lookup'] + + compiler_config['flags'].split()) + else: + with atomic_file_write(lib_file) as file_name: + run_compile_step([compiler_config['command'], '-shared', object_file, '-o', file_name] + + compiler_config['flags'].split()) + return lib_file + + +def compile_and_load(ast: PsKernelFunction, custom_backend=None): + cache_config = get_cache_config() + + compiler_config = get_compiler_config() + function_prefix = '__declspec(dllexport)' if compiler_config['os'].lower() == 'windows' else '' + + code = PsKernelExtensioNModule() + + code.add_function(ast, ast.function_name) + + code.create_code_string(compiler_config['restrict_qualifier'], function_prefix) + code_hash_str = code.get_hash_of_code() + + compile_flags = [] + if ast.instruction_set and 'compile_flags' in ast.instruction_set: + compile_flags = ast.instruction_set['compile_flags'] + + if cache_config['object_cache'] is False: + with tempfile.TemporaryDirectory() as base_dir: + lib_file = compile_module(code, code_hash_str, base_dir, compile_flags=compile_flags) + result = load_kernel_from_file(code_hash_str, ast.function_name, lib_file) + else: + lib_file = compile_module(code, code_hash_str, base_dir=cache_config['object_cache'], + compile_flags=compile_flags) + result = load_kernel_from_file(code_hash_str, ast.function_name, lib_file) + + return KernelWrapper(result, ast.get_parameters(), ast) diff --git a/src/pystencils/backend/jit/msvc_detection.py b/src/pystencils/backend/jit/msvc_detection.py new file mode 100644 index 0000000000000000000000000000000000000000..9cc1fc5ad64a9e50d24788f6e4eea8135cbf7a2c --- /dev/null +++ b/src/pystencils/backend/jit/msvc_detection.py @@ -0,0 +1,105 @@ +import os +import subprocess + + +def get_environment(version_specifier, arch='x64'): + """Returns an environment dictionary, for activating the Visual Studio compiler. + + Args: + version_specifier: either a version number, year number, 'auto' or 'latest' for automatic detection of latest + installed version or 'setuptools' for setuptools-based detection + arch: x86 or x64 + """ + if version_specifier == 'setuptools': + return get_environment_from_setup_tools(arch) + elif '\\' in version_specifier: + vc_vars_path = find_vc_vars_all_via_filesystem_search(version_specifier) + return get_environment_from_vc_vars_file(vc_vars_path, arch) + else: + try: + if version_specifier in ('auto', 'latest'): + version_nr = find_latest_msvc_version_using_environment_variables() + else: + version_nr = normalize_msvc_version(version_specifier) + vc_vars_path = get_vc_vars_path_via_environment_variable(version_nr) + except ValueError: + vc_vars_path = find_vc_vars_all_via_filesystem_search("C:\\Program Files (x86)\\Microsoft Visual Studio") + if vc_vars_path is None: + vc_vars_path = find_vc_vars_all_via_filesystem_search("C:\\Program Files\\Microsoft Visual Studio") + if vc_vars_path is None: + raise ValueError("Visual Studio not found. Write path to VS folder in pystencils config") + + return get_environment_from_vc_vars_file(vc_vars_path, arch) + + +def find_latest_msvc_version_using_environment_variables(): + import re + # noinspection SpellCheckingInspection + regex = re.compile(r'VS(\d\d)\dCOMNTOOLS') + versions = [] + for key, value in os.environ.items(): + match = regex.match(key) + if match: + versions.append(int(match.group(1))) + if len(versions) == 0: + raise ValueError("Visual Studio not found.") + versions.sort() + return versions[-1] + + +def normalize_msvc_version(version): + """ + Takes version specifiers in the following form: + - year: 2012, 2013, 2015, either as int or string + - version numbers with or without dot i.e. 11.0 or 11 + :return: integer version number + """ + if isinstance(version, str) and '.' in version: + version = version.split('.')[0] + + version = int(version) + mapping = { + 2015: 14, + 2013: 12, + 2012: 11 + } + if version in mapping: + return mapping[version] + else: + return version + + +def get_environment_from_vc_vars_file(vc_vars_file, arch): + out = subprocess.check_output( + f'cmd /u /c "{vc_vars_file}" {arch} && set', + stderr=subprocess.STDOUT, + ).decode('utf-16le', errors='replace') + + env = {key.upper(): value for key, _, value in (line.partition('=') for line in out.splitlines()) if key and value} + return env + + +def get_vc_vars_path_via_environment_variable(version_nr): + # noinspection SpellCheckingInspection + environment_var_name = 'VS%d0COMNTOOLS' % (version_nr,) + vc_path = os.environ[environment_var_name] + path = os.path.join(vc_path, '..', '..', 'VC', 'vcvarsall.bat') + return os.path.abspath(path) + + +def get_environment_from_setup_tools(arch): + from setuptools.msvc import msvc14_get_vc_env + msvc_env = msvc14_get_vc_env(arch) + return {k.upper(): v for k, v in msvc_env.items()} + + +def find_vc_vars_all_via_filesystem_search(base_path): + matches = [] + for root, dir_names, file_names in os.walk(base_path): + for filename in file_names: + if filename == 'vcvarsall.bat': + matches.append(os.path.join(root, filename)) + + matches.sort(reverse=True) + if matches: + return matches[0] diff --git a/src/pystencils/backend/kernelcreation/__init__.py b/src/pystencils/backend/kernelcreation/__init__.py index 6ac30e9eed597e7d3ae2d9421fea3156a4d5de33..c04cab827a7c28fc38a04bed7bffd749b334e79b 100644 --- a/src/pystencils/backend/kernelcreation/__init__.py +++ b/src/pystencils/backend/kernelcreation/__init__.py @@ -98,8 +98,6 @@ It is furthermore annotated with constraints collected during the translation, a """ -from .config import CreateKernelConfig - from .context import KernelCreationContext from .analysis import KernelAnalysis from .freeze import FreezeExpressions @@ -113,7 +111,6 @@ from .iteration_space import ( ) __all__ = [ - "CreateKernelConfig", "KernelCreationContext", "KernelAnalysis", "FreezeExpressions", diff --git a/src/pystencils/backend/kernelcreation/analysis.py b/src/pystencils/backend/kernelcreation/analysis.py index b0267a3d6950d1218e4976ff109d62c065f2520a..c43452cc42c620363a4428ed065a6387577da347 100644 --- a/src/pystencils/backend/kernelcreation/analysis.py +++ b/src/pystencils/backend/kernelcreation/analysis.py @@ -207,4 +207,4 @@ class NestedScopes: @property def depth(self): - return len(self._defined) \ No newline at end of file + return len(self._defined) diff --git a/src/pystencils/datahandling/parallel_datahandling.py b/src/pystencils/datahandling/parallel_datahandling.py index d9d91cd6c364469ae574ed9a3b5322e44977f6f1..c0ddc9a464f4d2ebded2e0530100c098ea6728da 100644 --- a/src/pystencils/datahandling/parallel_datahandling.py +++ b/src/pystencils/datahandling/parallel_datahandling.py @@ -9,7 +9,7 @@ from pystencils.datahandling.blockiteration import block_iteration, sliced_block from pystencils.datahandling.datahandling_interface import DataHandling from pystencils.enums import Backend from pystencils.field import Field, FieldType -from pystencils.typing.typed_sympy import FieldPointerSymbol +from pystencils.sympyextensions.typed_sympy import FieldPointerSymbol from pystencils.utils import DotDict from pystencils import Target diff --git a/src/pystencils/kernelcreation.py b/src/pystencils/kernelcreation.py index e12381068b101e36ff41dc01fcc63edd4ad0919b..954eb2e07aa35c7d0f7cd43af6aca52968f01def 100644 --- a/src/pystencils/kernelcreation.py +++ b/src/pystencils/kernelcreation.py @@ -112,9 +112,9 @@ class CreateKernelConfig: if self.jit is None: match self.target: case Target.CPU: - from .backend.jit import legacy_cpu + from .backend.jit import LegacyCpuJit - self.jit = legacy_cpu + self.jit = LegacyCpuJit() case _: raise NotImplementedError( f"No default JIT compiler implemented yet for target {self.target}" diff --git a/src/pystencils/old/cpu/__init__.py b/src/pystencils/old/cpu/__init__.py index ba0b57da21322f36f91cdd4cf6d2a64ad485ee41..244df5a8691836d8c1ed431826eeffbae70af977 100644 --- a/src/pystencils/old/cpu/__init__.py +++ b/src/pystencils/old/cpu/__init__.py @@ -1,4 +1,4 @@ -from pystencils.cpu.cpujit import make_python_function -from pystencils.cpu.kernelcreation import add_openmp, create_indexed_kernel, create_kernel, add_pragmas +from .cpujit import make_python_function +from .kernelcreation import add_openmp, create_indexed_kernel, create_kernel, add_pragmas __all__ = ['create_kernel', 'create_indexed_kernel', 'add_openmp', 'add_pragmas', 'make_python_function'] diff --git a/src/pystencils/old/gpu/__init__.py b/src/pystencils/old/gpu/__init__.py index c0d1fd34d7d8028469d68aaa694f88c3e607e9ee..0ee6f02aef6383d570f93d3841ede5359aa7c86c 100644 --- a/src/pystencils/old/gpu/__init__.py +++ b/src/pystencils/old/gpu/__init__.py @@ -1,6 +1,6 @@ -from pystencils.gpu.gpu_array_handler import GPUArrayHandler, GPUNotAvailableHandler -from pystencils.gpu.gpujit import make_python_function -from pystencils.gpu.kernelcreation import create_cuda_kernel, created_indexed_cuda_kernel +from .gpu_array_handler import GPUArrayHandler, GPUNotAvailableHandler +from .gpujit import make_python_function +from .kernelcreation import create_cuda_kernel, created_indexed_cuda_kernel from .indexing import AbstractIndexing, BlockIndexing, LineIndexing diff --git a/tests/nbackend/kernelcreation/platform/test_basic_cpu.py b/tests/nbackend/kernelcreation/platform/test_basic_cpu.py index 540985a2a80fa1f5f5ddbd1f7dd0c2519f59da21..d42981f8ca2e95bee2bdff7d1baf8062bb1fbd75 100644 --- a/tests/nbackend/kernelcreation/platform/test_basic_cpu.py +++ b/tests/nbackend/kernelcreation/platform/test_basic_cpu.py @@ -2,19 +2,18 @@ import pytest from pystencils.field import Field -from pystencils.nbackend.kernelcreation import ( +from pystencils.backend.kernelcreation import ( KernelCreationContext, - CreateKernelConfig, FullIterationSpace ) -from pystencils.nbackend.ast import PsBlock, PsLoop, PsComment, dfs_preorder +from pystencils.backend.ast import PsBlock, PsLoop, PsComment, dfs_preorder -from pystencils.nbackend.kernelcreation.platform import BasicCpu +from pystencils.backend.platforms import BasicCpu @pytest.mark.parametrize("layout", ["fzyx", "zyxf", "c", "f"]) def test_loop_nest(layout): - ctx = KernelCreationContext(CreateKernelConfig()) + ctx = KernelCreationContext() body = PsBlock([PsComment("Loop body goes here")]) platform = BasicCpu(ctx) diff --git a/tests/nbackend/kernelcreation/test_domain_kernels.py b/tests/nbackend/kernelcreation/test_domain_kernels.py index 4221bbad18849b1148139aa350d9db999f511f9d..9ce2f661d840641d28774134070fc7050e90e6d1 100644 --- a/tests/nbackend/kernelcreation/test_domain_kernels.py +++ b/tests/nbackend/kernelcreation/test_domain_kernels.py @@ -2,9 +2,9 @@ import sympy as sp import numpy as np from pystencils import fields, Field, AssignmentCollection -from pystencils.sympyextensions.assignmentcollection.assignment import assignment_from_stencil +from pystencils.sympyextensions.astnodes import assignment_from_stencil -from pystencils.nbackend.kernelcreation import create_kernel +from pystencils.kernelcreation import create_kernel def test_filter_kernel(): diff --git a/tests/nbackend/kernelcreation/test_freeze.py b/tests/nbackend/kernelcreation/test_freeze.py index ca3a470a5fce49a1d45171c50ee62e88d263e051..acecc6503add4a2f858b696886a30a8dbe7fdd98 100644 --- a/tests/nbackend/kernelcreation/test_freeze.py +++ b/tests/nbackend/kernelcreation/test_freeze.py @@ -3,17 +3,16 @@ import pymbolic.primitives as pb from pystencils import Assignment, fields -from pystencils.nbackend.ast import ( +from pystencils.backend.ast import ( PsAssignment, PsDeclaration, PsExpression, PsSymbolExpr, PsLvalueExpr, ) -from pystencils.nbackend.typed_expressions import PsTypedConstant, PsTypedVariable -from pystencils.nbackend.arrays import PsArrayAccess -from pystencils.nbackend.kernelcreation import ( - CreateKernelConfig, +from pystencils.backend.typed_expressions import PsTypedConstant, PsTypedVariable +from pystencils.backend.arrays import PsArrayAccess +from pystencils.backend.kernelcreation import ( KernelCreationContext, FreezeExpressions, FullIterationSpace, @@ -21,8 +20,7 @@ from pystencils.nbackend.kernelcreation import ( def test_freeze_simple(): - options = CreateKernelConfig() - ctx = KernelCreationContext(options) + ctx = KernelCreationContext() freeze = FreezeExpressions(ctx) x, y, z = sp.symbols("x, y, z") @@ -37,8 +35,7 @@ def test_freeze_simple(): def test_freeze_fields(): - options = CreateKernelConfig() - ctx = KernelCreationContext(options) + ctx = KernelCreationContext() zero = PsTypedConstant(0, ctx.index_dtype) forty_two = PsTypedConstant(42, ctx.index_dtype) diff --git a/tests/nbackend/kernelcreation/test_iteration_space.py b/tests/nbackend/kernelcreation/test_iteration_space.py index e785b64a27d84dc9e2699b9e3c60fd5593a81455..6fe905f73bcbd8ebd65bf0013240325aeb109b04 100644 --- a/tests/nbackend/kernelcreation/test_iteration_space.py +++ b/tests/nbackend/kernelcreation/test_iteration_space.py @@ -1,16 +1,15 @@ from pystencils.field import Field -from pystencils.nbackend.kernelcreation import ( +from pystencils.backend.kernelcreation import ( KernelCreationContext, - CreateKernelConfig, FullIterationSpace ) -from pystencils.nbackend.kernelcreation.defaults import Pymbolic as PbDefaults +from pystencils.backend.kernelcreation.defaults import Pymbolic as PbDefaults def test_loop_order(): - ctx = KernelCreationContext(CreateKernelConfig()) + ctx = KernelCreationContext() ctr_symbols = PbDefaults.spatial_counters # FZYX Order diff --git a/tests/nbackend/kernelcreation/test_options.py b/tests/nbackend/kernelcreation/test_options.py index 77b13da0c94416884adaff4c11ae53aa18fcfb8c..726ee8def24ee3735a6a95f62ab364414024c1a6 100644 --- a/tests/nbackend/kernelcreation/test_options.py +++ b/tests/nbackend/kernelcreation/test_options.py @@ -1,8 +1,8 @@ import pytest from pystencils.field import Field, FieldType -from pystencils.nbackend.types.quick import * -from pystencils.nbackend.kernelcreation.config import ( +from pystencils.backend.types.quick import * +from pystencils.kernelcreation import ( CreateKernelConfig, PsOptionsError, ) diff --git a/tests/nbackend/kernelcreation/test_typification.py b/tests/nbackend/kernelcreation/test_typification.py index 26d702b2306c11aa370420c1e96e93085922373b..6e24a876f221a2880a8dd71958973d75e1b59a58 100644 --- a/tests/nbackend/kernelcreation/test_typification.py +++ b/tests/nbackend/kernelcreation/test_typification.py @@ -5,19 +5,17 @@ import pymbolic.primitives as pb from pystencils import Assignment, TypedSymbol, Field, FieldType -from pystencils.nbackend.ast import PsDeclaration -from pystencils.nbackend.types import constify -from pystencils.nbackend.types.quick import * -from pystencils.nbackend.typed_expressions import PsTypedConstant, PsTypedVariable -from pystencils.nbackend.kernelcreation.config import CreateKernelConfig -from pystencils.nbackend.kernelcreation.context import KernelCreationContext -from pystencils.nbackend.kernelcreation.freeze import FreezeExpressions -from pystencils.nbackend.kernelcreation.typification import Typifier, TypificationError +from pystencils.backend.ast import PsDeclaration +from pystencils.backend.types import constify +from pystencils.backend.types.quick import * +from pystencils.backend.typed_expressions import PsTypedConstant, PsTypedVariable +from pystencils.backend.kernelcreation.context import KernelCreationContext +from pystencils.backend.kernelcreation.freeze import FreezeExpressions +from pystencils.backend.kernelcreation.typification import Typifier, TypificationError def test_typify_simple(): - options = CreateKernelConfig() - ctx = KernelCreationContext(options) + ctx = KernelCreationContext() freeze = FreezeExpressions(ctx) typify = Typifier(ctx) @@ -33,10 +31,10 @@ def test_typify_simple(): match expr: case PsTypedConstant(value, dtype): assert value == 2 - assert dtype == constify(ctx.options.default_dtype) + assert dtype == constify(ctx.default_dtype) case PsTypedVariable(name, dtype): assert name in "xyz" - assert dtype == ctx.options.default_dtype + assert dtype == ctx.default_dtype case pb.Sum(cs) | pb.Product(cs): [check(c) for c in cs] case _: @@ -47,8 +45,7 @@ def test_typify_simple(): def test_typify_structs(): - options = CreateKernelConfig(default_dtype=Fp(32)) - ctx = KernelCreationContext(options) + ctx = KernelCreationContext(default_dtype=Fp(32)) freeze = FreezeExpressions(ctx) typify = Typifier(ctx) @@ -69,8 +66,7 @@ def test_typify_structs(): def test_contextual_typing(): - options = CreateKernelConfig() - ctx = KernelCreationContext(options) + ctx = KernelCreationContext() freeze = FreezeExpressions(ctx) typify = Typifier(ctx) @@ -82,10 +78,10 @@ def test_contextual_typing(): match expr: case PsTypedConstant(value, dtype): assert value in (2, 3, -4) - assert dtype == constify(ctx.options.default_dtype) + assert dtype == constify(ctx.default_dtype) case PsTypedVariable(name, dtype): assert name in "xyz" - assert dtype == ctx.options.default_dtype + assert dtype == ctx.default_dtype case pb.Sum(cs) | pb.Product(cs): [check(c) for c in cs] case _: @@ -95,8 +91,7 @@ def test_contextual_typing(): def test_erronous_typing(): - options = CreateKernelConfig(default_dtype=make_numeric_type(np.float64)) - ctx = KernelCreationContext(options) + ctx = KernelCreationContext(default_dtype=make_numeric_type(np.float64)) freeze = FreezeExpressions(ctx) typify = Typifier(ctx) diff --git a/tests/nbackend/test_constant_folding.py b/tests/nbackend/test_constant_folding.py index c297534b4ea1cc2e545d2f631f7857614f5bfddb..686a4346f1935a7c7b1dd795f6f672352d138df6 100644 --- a/tests/nbackend/test_constant_folding.py +++ b/tests/nbackend/test_constant_folding.py @@ -3,8 +3,8 @@ import pytest import pymbolic.primitives as pb from pymbolic.mapper.constant_folder import ConstantFoldingMapper -from pystencils.nbackend.types.quick import * -from pystencils.nbackend.typed_expressions import PsTypedConstant +from pystencils.backend.types.quick import * +from pystencils.backend.typed_expressions import PsTypedConstant @pytest.mark.parametrize("width", (8, 16, 32, 64)) diff --git a/tests/nbackend/test_cpujit.py b/tests/nbackend/test_cpujit.py index b93f7a1e22c94b9cb6fa6443be4690581c66193c..865b698c4fd8df1f7a073ae923930fb90f469802 100644 --- a/tests/nbackend/test_cpujit.py +++ b/tests/nbackend/test_cpujit.py @@ -2,16 +2,15 @@ import pytest from pystencils import Target -from pystencils.nbackend.ast import * -from pystencils.nbackend.constraints import PsKernelConstraint -from pystencils.nbackend.typed_expressions import * -from pystencils.nbackend.arrays import PsLinearizedArray, PsArrayBasePointer, PsArrayAccess -from pystencils.nbackend.types.quick import * +from pystencils.backend.ast import * +from pystencils.backend.constraints import PsKernelConstraint +from pystencils.backend.typed_expressions import * +from pystencils.backend.arrays import PsLinearizedArray, PsArrayBasePointer, PsArrayAccess +from pystencils.backend.types.quick import * +from pystencils.backend.jit import LegacyCpuJit import numpy as np -from pystencils.cpu.cpujit import compile_and_load - def test_pairwise_addition(): idx_type = SInt(64) @@ -49,7 +48,8 @@ def test_pairwise_addition(): func.add_constraints(sizes_constraint) - kernel = compile_and_load(func) + jit = LegacyCpuJit() + kernel = jit.compile(func) # Positive case N = 21 diff --git a/tests/nbackend/test_expressions.py b/tests/nbackend/test_expressions.py index 6c24a6442bd5899b4221b795be2c65cf89982331..65a0a4e1ecc9573fa7df26f7251fe9aa300b6953 100644 --- a/tests/nbackend/test_expressions.py +++ b/tests/nbackend/test_expressions.py @@ -1,7 +1,6 @@ -from pystencils.nbackend.typed_expressions import PsTypedVariable -from pystencils.nbackend.arrays import PsLinearizedArray, PsArrayBasePointer, PsArrayShapeVar, PsArrayStrideVar - -from pystencils.nbackend.types.quick import * +from pystencils.backend.typed_expressions import PsTypedVariable +from pystencils.backend.arrays import PsLinearizedArray, PsArrayBasePointer, PsArrayShapeVar, PsArrayStrideVar +from pystencils.backend.types.quick import * def test_variable_equality(): var1 = PsTypedVariable("x", Fp(32)) diff --git a/tests/nbackend/types/test_constants.py b/tests/nbackend/types/test_constants.py index 4eaf4060a4182a78232660fc2285caaa8047ff3c..a5399c66e2a08bf10cd1829bd8a0707baa0f0bcd 100644 --- a/tests/nbackend/types/test_constants.py +++ b/tests/nbackend/types/test_constants.py @@ -1,8 +1,8 @@ import pytest -from pystencils.nbackend.types.quick import * -from pystencils.nbackend.types import PsTypeError -from pystencils.nbackend.typed_expressions import PsTypedConstant +from pystencils.backend.types.quick import * +from pystencils.backend.types import PsTypeError +from pystencils.backend.typed_expressions import PsTypedConstant @pytest.mark.parametrize("width", (8, 16, 32, 64)) diff --git a/tests/nbackend/types/test_types.py b/tests/nbackend/types/test_types.py index 06ec7db163b4c096591da4bdb6d67bcc27513e8b..9726fac47cfb38b61903e518b04c86ea2b69bc80 100644 --- a/tests/nbackend/types/test_types.py +++ b/tests/nbackend/types/test_types.py @@ -1,9 +1,9 @@ import pytest import numpy as np -from pystencils.nbackend.exceptions import PsInternalCompilerError -from pystencils.nbackend.types import * -from pystencils.nbackend.types.quick import * +from pystencils.backend.exceptions import PsInternalCompilerError +from pystencils.backend.types import * +from pystencils.backend.types.quick import * @pytest.mark.parametrize(