Skip to content
Snippets Groups Projects
Commit b5f4dc95 authored by Martin Bauer's avatar Martin Bauer
Browse files

Reverted boundary optimization

- not generic enough - does not work if there a multiple blocks
parent 966e8633
No related branches found
No related tags found
No related merge requests found
......@@ -202,9 +202,14 @@ class BoundaryHandling:
for b in self._data_handling.iterate(gpu=self._target == 'gpu'):
for b_obj, idx_arr in b[self._index_array_name].boundary_object_to_index_list.items():
kwargs[self._field_name] = b[self._field_name]
kwargs['indexField'] = idx_arr
kernel = self._boundary_object_to_boundary_info[b_obj].kernel
self._data_handling.run_kernel(kernel, **kwargs)
data_used_in_kernel = (p.field_name
for p in self._boundary_object_to_boundary_info[b_obj].kernel.parameters
if p.is_field_ptr_argument and p.field_name not in kwargs)
kwargs.update({name: b[name] for name in data_used_in_kernel})
self._boundary_object_to_boundary_info[b_obj].kernel(**kwargs)
def geometry_to_vtk(self, file_name='geometry', boundaries='all', ghost_layers=False):
"""
......
......@@ -62,7 +62,7 @@ from pystencils.backends.cbackend import generate_c, get_headers
from pystencils.utils import file_handle_for_atomic_write, atomic_file_write
def make_python_function(kernel_function_node, argument_dict=None):
def make_python_function(kernel_function_node):
"""
Creates C code from the abstract syntax tree, compiles it and makes it accessible as Python function
......@@ -71,13 +71,9 @@ def make_python_function(kernel_function_node, argument_dict=None):
- all symbols which are not defined in the kernel itself are expected as parameters
:param kernel_function_node: the abstract syntax tree
:param argument_dict: parameters passed here are already fixed. Remaining parameters have to be passed to the
returned kernel functor.
:return: kernel functor
"""
result = compile_and_load(kernel_function_node)
if argument_dict:
result = functools.partial(result, **argument_dict)
return result
......@@ -246,7 +242,10 @@ PyBuffer_Release(&buffer_{name});
template_function_boilerplate = """
static PyObject * {func_name}(PyObject * self, PyObject * args, PyObject * kwargs)
{{
if( !kwargs || !PyDict_Check(kwargs) ) {{ PyErr_SetString(PyExc_TypeError, "No keyword arguments passed"); return NULL; }}
if( !kwargs || !PyDict_Check(kwargs) ) {{
PyErr_SetString(PyExc_TypeError, "No keyword arguments passed");
return NULL;
}}
{pre_call_code}
kernel_{func_name}({parameters});
{post_call_code}
......@@ -320,7 +319,9 @@ def create_function_boilerplate_code(parameter_info, name, insert_checks=True):
shapes = ", ".join(["buffer_{name}.shape[{i}]".format(name=arg.field_name, i=i)
for i in range(len(arg.field.strides))])
pre_call_code += "{type} {name}_shape[] = {{ {elements} }};\n".format(type=get_base_type(Field.SHAPE_DTYPE),
shape_type = get_base_type(Field.SHAPE_DTYPE)
pre_call_code += "{type} {name}_shape[] = {{ {elements} }};\n".format(type=shape_type,
name=arg.field_name,
elements=shapes)
......@@ -328,7 +329,8 @@ def create_function_boilerplate_code(parameter_info, name, insert_checks=True):
strides = ["buffer_{name}.strides[{i}] / {bytes}".format(i=i, name=arg.field_name, bytes=item_size)
for i in range(len(arg.field.strides))]
strides = ", ".join(strides)
pre_call_code += "{type} {name}_strides[] = {{ {elements} }};\n".format(type=get_base_type(Field.STRIDE_DTYPE),
strides_type = get_base_type(Field.STRIDE_DTYPE)
pre_call_code += "{type} {name}_strides[] = {{ {elements} }};\n".format(type=strides_type,
name=arg.field_name,
elements=strides)
......
......@@ -3,9 +3,98 @@ import llvmlite.binding as llvm
import numpy as np
import ctypes as ct
from pystencils.data_types import create_composite_type_from_string
from ..data_types import to_ctypes, ctypes_from_llvm
from ..data_types import to_ctypes, ctypes_from_llvm, StructType, get_base_type
from .llvm import generate_llvm
from ..cpu.cpujit import build_ctypes_argument_list, make_python_function_incomplete_params
from pystencils.transformations import symbol_name_to_variable_name
from pystencils.field import FieldType
def build_ctypes_argument_list(parameter_specification, argument_dict):
argument_dict = {symbol_name_to_variable_name(k): v for k, v in argument_dict.items()}
ct_arguments = []
array_shapes = set()
index_arr_shapes = set()
for arg in parameter_specification:
if arg.is_field_argument:
try:
field_arr = argument_dict[arg.field_name]
except KeyError:
raise KeyError("Missing field parameter for kernel call " + arg.field_name)
symbolic_field = arg.field
if arg.is_field_ptr_argument:
ct_arguments.append(field_arr.ctypes.data_as(to_ctypes(arg.dtype)))
if symbolic_field.has_fixed_shape:
symbolic_field_shape = tuple(int(i) for i in symbolic_field.shape)
if isinstance(symbolic_field.dtype, StructType):
symbolic_field_shape = symbolic_field_shape[:-1]
if symbolic_field_shape != field_arr.shape:
raise ValueError("Passed array '%s' has shape %s which does not match expected shape %s" %
(arg.field_name, str(field_arr.shape), str(symbolic_field.shape)))
if symbolic_field.has_fixed_shape:
symbolic_field_strides = tuple(int(i) * field_arr.itemsize for i in symbolic_field.strides)
if isinstance(symbolic_field.dtype, StructType):
symbolic_field_strides = symbolic_field_strides[:-1]
if symbolic_field_strides != field_arr.strides:
raise ValueError("Passed array '%s' has strides %s which does not match expected strides %s" %
(arg.field_name, str(field_arr.strides), str(symbolic_field_strides)))
if FieldType.is_indexed(symbolic_field):
index_arr_shapes.add(field_arr.shape[:symbolic_field.spatial_dimensions])
elif FieldType.is_generic(symbolic_field):
array_shapes.add(field_arr.shape[:symbolic_field.spatial_dimensions])
elif arg.is_field_shape_argument:
data_type = to_ctypes(get_base_type(arg.dtype))
ct_arguments.append(field_arr.ctypes.shape_as(data_type))
elif arg.is_field_stride_argument:
data_type = to_ctypes(get_base_type(arg.dtype))
strides = field_arr.ctypes.strides_as(data_type)
for i in range(len(field_arr.shape)):
assert strides[i] % field_arr.itemsize == 0
strides[i] //= field_arr.itemsize
ct_arguments.append(strides)
else:
assert False
else:
try:
param = argument_dict[arg.name]
except KeyError:
raise KeyError("Missing parameter for kernel call " + arg.name)
expected_type = to_ctypes(arg.dtype)
ct_arguments.append(expected_type(param))
if len(array_shapes) > 1:
raise ValueError("All passed arrays have to have the same size " + str(array_shapes))
if len(index_arr_shapes) > 1:
raise ValueError("All passed index arrays have to have the same size " + str(array_shapes))
return ct_arguments
def make_python_function_incomplete_params(kernel_function_node, argument_dict, func):
parameters = kernel_function_node.parameters
cache = {}
cache_values = []
def wrapper(**kwargs):
key = hash(tuple((k, v.ctypes.data, v.strides, v.shape) if isinstance(v, np.ndarray) else (k, id(v))
for k, v in kwargs.items()))
try:
args = cache[key]
func(*args)
except KeyError:
full_arguments = argument_dict.copy()
full_arguments.update(kwargs)
args = build_ctypes_argument_list(parameters, full_arguments)
cache[key] = args
cache_values.append(kwargs) # keep objects alive such that ids remain unique
func(*args)
wrapper.ast = kernel_function_node
wrapper.parameters = kernel_function_node.parameters
return wrapper
def generate_and_jit(ast):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment