diff --git a/kerncraft/generate_benchmark.py b/kerncraft/generate_benchmark.py new file mode 100644 index 0000000000000000000000000000000000000000..a200352a19f3e2c22e47ca5e386dd27b98e713c7 --- /dev/null +++ b/kerncraft/generate_benchmark.py @@ -0,0 +1,109 @@ +from jinja2 import Template +from pystencils.cpu import generateC +from pystencils.sympyextensions import prod +from pystencils.types import getBaseType + +benchmarkTemplate = Template(""" +#include "kerncraft.h" +#include <stdlib.h> +#include <stdint.h> +#include <math.h> +{%- if likwid %} +#include <likwid.h> +{%- endif %} + +#define RESTRICT __restrict__ +#define FUNC_PREFIX +void dummy(double *); +extern int var_false; + + +{{kernelCode}} + + +int main(int argc, char **argv) +{ + {%- if likwid %} + likwid_markerInit(); + likwid_markerThreadInit(); + {%- endif %} + + {%- for fieldName, dataType, size in fields %} + + // Initialization {{fieldName}} + double * {{fieldName}} = aligned_malloc(sizeof({{dataType}}) * {{size}}, 32); + for (int i = 0; i < {{size}}; ++i) + {{fieldName}}[i] = 0.23; + + if(var_false) + dummy({{fieldName}}); + + {%- endfor %} + + + + {%- for constantName, dataType in constants %} + + // Constant {{constantName}} + {{dataType}} {{constantName}}; + {{constantName}} = 0.23; + if(var_false) + dummy(& {{constantName}}); + + {%- endfor %} + + int repeat = atoi(argv[1]); + {%- if likwid %} + likwid_markerStartRegion("loop"); + {%- endif %} + + for (; repeat > 0; --repeat) + { + kernel({{callArgumentList}}); + + // Dummy calls + {%- for fieldName, dataType, size in fields %} + if(var_false) dummy({{fieldName}}); + {%- endfor %} + {%- for constantName, dataType in constants %} + if(var_false) dummy(&{{constantName}}); + {%- endfor %} + } + + {%- if likwid %} + likwid_markerStopRegion("loop"); + {%- endif %} + + + + {%- if likwid %} + likwid_markerClose(); + {%- endif %} +} +""") + + +def generateBenchmark(ast, likwid=False): + accessedFields = {f.name: f for f in ast.fieldsAccessed} + constants = [] + fields = [] + callParameters = [] + for p in ast.parameters: + if not p.isFieldArgument: + constants.append((p.name, str(p.dtype))) + callParameters.append(p.name) + else: + assert p.isFieldPtrArgument, "Benchmark implemented only for kernels with fixed loop size" + field = accessedFields[p.fieldName] + dtype = str(getBaseType(p.dtype)) + fields.append((p.fieldName, dtype, prod(field.shape))) + callParameters.append(p.fieldName) + + args = { + 'likwid': likwid, + 'kernelCode': generateC(ast), + 'fields': fields, + 'constants': constants, + 'callArgumentList': ",".join(callParameters), + } + return benchmarkTemplate.render(**args) diff --git a/kerncraft/kernel.py b/kerncraft/kernel.py index ed222e9e96ef13d647168abab43be22d4110934a..5fb4590f8dabc2706f224e8569f15c2a89b39b88 100644 --- a/kerncraft/kernel.py +++ b/kerncraft/kernel.py @@ -2,6 +2,7 @@ import sympy as sp from collections import defaultdict import kerncraft.kernel from pystencils.cpu import createKernel +from pystencils.kerncraft.generate_benchmark import generateBenchmark from pystencils.transformations import typeAllEquations from pystencils.astnodes import LoopOverCoordinate, SympyAssignment, ResolvedFieldAccess from pystencils.field import Field, getLayoutFromStrides @@ -77,6 +78,10 @@ class PyStencilsKerncraftKernel(kerncraft.kernel.Kernel): self.check() + def as_code(self, type_='iaca'): + likwid = type_ == 'likwid' + generateBenchmark(self.ast, likwid) + class KerncraftParameters(DotDict): def __init__(self): @@ -87,77 +92,6 @@ class KerncraftParameters(DotDict): self['verbose'] = 0 -class PyStencilsKerncraftKernelOld(kerncraft.kernel.Kernel): - """ - Implementation of kerncraft's kernel interface for pystencils CPU kernels. - Analyses a list of equations assuming they will be executed on a CPU - - - right now it uses only the equations, not the optimized form e.g. expressions - that have been pulled in front of the loop - - - """ - def __init__(self, listOfEquations, typeForSymbol=None): - super(PyStencilsKerncraftKernel, self).__init__() - - ast = createKernel(listOfEquations, typeForSymbol=typeForSymbol) - self.ast = ast - fieldsRead, fieldsWritten, assignments = typeAllEquations(listOfEquations, typeForSymbol) - allFields = fieldsRead.union(fieldsWritten) - - # Loops - innerLoops = [l for l in ast.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), positive=True) + 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 ast.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() - # ------------------------------------------- Helper functions ---------------------------------------------------------