From 0b6b1589fbd70e743047f78279d30b66f0d2fc5c Mon Sep 17 00:00:00 2001 From: Martin Bauer <martin.bauer@fau.de> Date: Sun, 25 Jun 2017 19:29:58 +0200 Subject: [PATCH] Initial work on close kerncraft integration --- field.py | 12 +- kerncraft/2d-5pt.c_compilable.c | 24 ++++ ...2d-5pt.c_compilable.c___twodfivept___1.yml | 46 +++++++ kerncraft/2d-5pt.yml | 34 +++++ kerncraft/__init__.py | 0 kerncraft/kerncraft_test.py | 120 ++++++++++++++++++ 6 files changed, 232 insertions(+), 4 deletions(-) create mode 100644 kerncraft/2d-5pt.c_compilable.c create mode 100644 kerncraft/2d-5pt.c_compilable.c___twodfivept___1.yml create mode 100644 kerncraft/2d-5pt.yml create mode 100644 kerncraft/__init__.py create mode 100644 kerncraft/kerncraft_test.py diff --git a/field.py b/field.py index 6a00e61f5..c3a83e07e 100644 --- a/field.py +++ b/field.py @@ -354,6 +354,13 @@ def extractCommonSubexpressions(equations): return equations +def getLayoutFromStrides(strides, indexDimensionIds=[]): + coordinates = list(range(len(strides))) + relevantStrides = [stride for i, stride in enumerate(strides) if i not in indexDimensionIds] + result = [x for (y, x) in sorted(zip(relevantStrides, coordinates), key=lambda pair: pair[0], reverse=True)] + return normalizeLayout(result) + + def getLayoutOfArray(arr, indexDimensionIds=[]): """ Returns a list indicating the memory layout (linearization order) of the numpy array. @@ -368,10 +375,7 @@ def getLayoutOfArray(arr, indexDimensionIds=[]): The indexDimensionIds parameter leaves specifies which coordinates should not be """ - coordinates = list(range(len(arr.shape))) - relevantStrides = [stride for i, stride in enumerate(arr.strides) if i not in indexDimensionIds] - result = [x for (y, x) in sorted(zip(relevantStrides, coordinates), key=lambda pair: pair[0], reverse=True)] - return normalizeLayout(result) + return getLayoutFromStrides(arr.strides, indexDimensionIds) def createNumpyArrayWithLayout(shape, layout): diff --git a/kerncraft/2d-5pt.c_compilable.c b/kerncraft/2d-5pt.c_compilable.c new file mode 100644 index 000000000..f22f12800 --- /dev/null +++ b/kerncraft/2d-5pt.c_compilable.c @@ -0,0 +1,24 @@ +#include <stdlib.h> + +#define M 512*512 +#define N 512*512 + +void twodfivept(double s, int n, double a[M][n], double b[M][n]) { + for (int j = 1; j < (M - 1); ++j) + for (int i = 1; i < (n - 1); ++i) + b[j][i] = (a[j][i-1] + a[j][i+1] + a[j-1][i] + a[j+1][i]) * (s ? a[j][i-1] > 0 : 1.0); +} + +int main(int argc, char **argv) +{ + double a[M][N]; + double b[M][N]; + + for(int i=0; i<M; ++i) + for(int j=0; j<N; ++j) + a[i][j] = b[i][j] = 42.0; + + twodfivept(0.23, N, a, b); + + return 0; +} diff --git a/kerncraft/2d-5pt.c_compilable.c___twodfivept___1.yml b/kerncraft/2d-5pt.c_compilable.c___twodfivept___1.yml new file mode 100644 index 000000000..6f805a938 --- /dev/null +++ b/kerncraft/2d-5pt.c_compilable.c___twodfivept___1.yml @@ -0,0 +1,46 @@ + +general: + analysis: + tool: LLVM (3.9.0svn) + build: Apr 19 2016 (14:38:27) + kernel: + file: 2d-5pt.c_compilable.c + function: twodfivept + scop number: 0 + +arrays: + a: + type: double + dimension: [*, n] + b: + type: double + dimension: [*, n] + +loops: + - + index: i + start: 0 + stop: 262142 + step: 1 + - + index: j + start: 0 + stop: (-2+n) + step: 1 + +data sources: + a: + - [1+i, j] + - [1+i, 2+j] + - [i, 1+j] + - [2+i, 1+j] + +data destinations: + b: + - [1+i, 1+j] + +flops: + "+": 3 + "*": 1 + "f+": 4 + "f*": 2 diff --git a/kerncraft/2d-5pt.yml b/kerncraft/2d-5pt.yml new file mode 100644 index 000000000..4404ae67e --- /dev/null +++ b/kerncraft/2d-5pt.yml @@ -0,0 +1,34 @@ +arrays: + a: + type: double + dimension: [30, 50] + b: + type: double + dimension: [30, 50] + +loops: + - + index: i + start: 0 + stop: 262142 + step: 1 + - + index: j + start: 0 + stop: (-2+20) + step: 1 + +data sources: + a: + - [1+i, j] + - [1+i, 2+j] + - [i, 1+j] + - [2+i, 1+j] + +data destinations: + b: + - [1+i, 1+j] + +flops: + "+": 3 + "*": 1 diff --git a/kerncraft/__init__.py b/kerncraft/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kerncraft/kerncraft_test.py b/kerncraft/kerncraft_test.py new file mode 100644 index 000000000..ac810c0d3 --- /dev/null +++ b/kerncraft/kerncraft_test.py @@ -0,0 +1,120 @@ +import kerncraft +from kerncraft.kernel import KernelCode +from kernel import KernelDescription +from pystencils.astnodes import LoopOverCoordinate +from pystencils.cpu import createKernel +from pystencils.field import getLayoutFromStrides +from pystencils.sympyextensions import countNumberOfOperations +from pystencils.transformations import typeAllEquations +from pystencils import Field +from collections import defaultdict + + +class PyStencilsKerncraftKernel(kerncraft.kernel.Kernel): + + def __init__(self, listOfEquations, typeForSymbol=None): + super(PyStencilsKerncraftKernel, self).__init__() + + pystencilsAst = createKernel(listOfEquations, typeForSymbol=typeForSymbol) + self.ast = pystencilsAst + fieldsRead, fieldsWritten, assignments = typeAllEquations(listOfEquations, typeForSymbol) + allFields = fieldsRead.union(fieldsWritten) + + # Loops + innerLoops = [l for l in pystencilsAst.atoms(LoopOverCoordinate) if l.isInnermostLoop] + if len(innerLoops) == 0: + raise ValueError("No loop found in pystencils AST") + elif len(innerLoops) > 1: + raise ValueError("pystencils AST contains multiple inner loops - only one can be analyzed") + else: + innerLoop = innerLoops[0] + + self._loop_stack = [] + curNode = innerLoop + while curNode is not None: + if isinstance(curNode, LoopOverCoordinate): + loopInfo = (curNode.loopCounterSymbol.name, curNode.start, curNode.stop, curNode.step) + self._loop_stack.append(loopInfo) + curNode = curNode.parent + self._loop_stack = list(reversed(self._loop_stack)) + + # Data sources & destinations + self._sources = defaultdict(list) + self._destinations = defaultdict(list) + for eq in listOfEquations: + for accessesDict, expr in [(self._destinations, eq.lhs), (self._sources, eq.rhs)]: + for fa in expr.atoms(Field.Access): + coord = [sp.Symbol(LoopOverCoordinate.getLoopCounterName(i)) + off for i, off in enumerate(fa.offsets)] + coord += list(fa.index) + layout = getLayoutFromStrides(fa.field.strides) + permutedCoord = [coord[i] for i in layout] + accessesDict[fa.field.name].append(permutedCoord) + + # Variables (arrays) + for field in allFields: + layout = getLayoutFromStrides(field.strides) + permutedShape = list(field.shape[i] for i in layout) + self.set_variable(field.name, str(field.dtype), permutedShape) + for param in pystencilsAst.parameters: + if not param.isFieldArgument: + self.set_variable(param.name, str(param.dtype), None) + self._sources[param.name] = [None] + + # Datatype + self.datatype = list(self.variables.values())[0][0] + + # Flops + operationCount = countNumberOfOperations(listOfEquations) + self._flops = { + '+': operationCount['adds'], + '*': operationCount['muls'], + '/': operationCount['divs'], + } + + self.check() + +from kerncraft.iaca_marker import find_asm_blocks, userselect_block, select_best_block +from kerncraft.models import ECM, ECMData +from kerncraft.machinemodel import MachineModel +from ruamel import yaml + +if __name__ == "__main__": + from pystencils import Field + import sympy as sp + import numpy as np + from pystencils.cpu import generateC + + arr = np.zeros([80, 40], order='c') + #arr = np.zeros([40, 80, 3], order='f') + a = Field.createFromNumpyArray('a', arr, indexDimensions=0) + b = Field.createFromNumpyArray('b', arr, indexDimensions=0) + + s = sp.Symbol("s") + rhs = a[0, -1](0) + a[0, 1] + a[-1, 0] + a[1, 0] + updateRule = sp.Eq(b[0, 0], s*rhs) + k = PyStencilsKerncraftKernel([updateRule]) + print(generateC(k.ast)) + kernelFile = "2d-5pt.c" + #k = KernelCode(open("/home/martin/dev/kerncraft/examples/kernels/" + kernelFile).read())] + descr = yaml.load(open("/home/martin/dev/pystencils/pystencils/kerncraft/2d-5pt.yml").read()) + k = KernelDescription(descr) + k.print_kernel_info() + k.print_variables_info() + offsets = list(k.compile_global_offsets(1000)) + print(offsets) + + machineFilePath = "/home/martin/dev/kerncraft/examples/machine-files/emmy.yaml" + machine = MachineModel(path_to_yaml=machineFilePath) + #exit(0) + from kerncraft.kerncraft import create_parser + parser = create_parser() + parserArgs = parser.parse_args(["-m", machineFilePath, "-p", "ECMData", machineFilePath]) + + model = ECMData(k, machine, parserArgs) + model.analyze() + model.report() + #blocks = find_asm_blocks(open("/home/martin/dev/kerncraft/2d-5pt.c_compilable.s").readlines()) + #userselect_block(blocks) + ##select_ + #bestBlock = select_best_block(blocks) + #print(bestBlock) -- GitLab