Commit cb05590d authored by Michael Kuron's avatar Michael Kuron Committed by Martin Bauer
Browse files

Python 2.7 compatibility

This commit makes the Python code backwards compatible down to Python 2.7. Previously it would only run on Python 3.5 and up.

Problems fixed included:
- `time.perf_counter()` doesn't exist
- all classes need to be new-style
- `functools.lru_cache` doesn't exist
- only the last argument to a function call can be `*`-expanded
- the `nonlocal` keyword doesn't exist
- metaclasses are used with a different syntax
- `yield from` doesn't exist
- `tempdir.TemporaryDirectory` doesn't exist
- iterators need a `next()` method
parent a875e22e
import sympy as sp
import textwrap as textwrap
from sympy.tensor import IndexedBase, Indexed
from pystencils.field import Field
from pystencils.types import TypedSymbol, DataType
......@@ -119,7 +118,7 @@ class KernelFunction(Node):
def __str__(self):
self._updateParameters()
return '{0} {1}({2})\n{3}'.format(type(self).__name__, self.functionName, self.parameters,
textwrap.indent(str(self.body), '\t'))
("\t" + "\t".join(str(self.body).splitlines(True))))
def __repr__(self):
self._updateParameters()
......@@ -284,7 +283,7 @@ class LoopOverCoordinate(Node):
def __str__(self):
return 'loop:{!s} in {!s}:{!s}:{!s}\n{!s}'.format(self.loopCounterName, self.start, self.stop, self.step,
textwrap.indent(str(self.body), '\t'))
("\t" + "\t".join(str(self.body).splitlines(True))))
def __repr__(self):
return 'loop:{!s} in {!s}:{!s}:{!s}'.format(self.loopCounterName, self.start, self.stop, self.step)
......
import textwrap
from sympy.utilities.codegen import CCodePrinter
from pystencils.astnodes import Node
......@@ -54,7 +53,7 @@ class PrintNode(CustomCppCode):
# ------------------------------------------- Printer ------------------------------------------------------------------
class CBackend:
class CBackend(object):
def __init__(self, cuda=False, constantsAsFloats=False, sympyPrinter=None):
self.cuda = cuda
......@@ -84,7 +83,7 @@ class CBackend:
def _print_Block(self, node):
blockContents = "\n".join([self._print(child) for child in node.args])
return "{\n%s\n}" % (textwrap.indent(blockContents, self._indent))
return "{\n%s\n}" % (self._indent + self._indent.join(blockContents.splitlines(True)))
def _print_PragmaBlock(self, node):
return "%s\n%s" % (node.pragmaLine, self._print_Block(node))
......
......@@ -7,7 +7,7 @@ class DotPrinter(Printer):
A printer which converts ast to DOT (graph description language).
"""
def __init__(self, nodeToStrFunction, **kwargs):
super().__init__()
super(DotPrinter, self).__init__()
self._nodeToStrFunction = nodeToStrFunction
self.dot = Digraph(**kwargs)
self.dot.quote_edge = lang.quote
......
from __future__ import print_function
import os
import subprocess
from ctypes import cdll, c_double, c_float, sizeof
from tempfile import TemporaryDirectory
import tempfile
import shutil
from pystencils.backends.cbackend import generateC
import numpy as np
import pickle
......@@ -31,11 +33,15 @@ CONFIG_INTEL_SUPERMUC = {
}
CONFIG_CLANG = {
'compiler': 'clang++',
'flags': '-Ofast -DNDEBUG -fPIC -shared -march=native -fopenmp',
'flags': '-Ofast -DNDEBUG -fPIC -shared -march=native ',
}
CONFIG = CONFIG_GCC
if CONFIG is CONFIG_CLANG and not 'Apple LLVM' in subprocess.check_output(['clang++', '--version']):
CONFIG_CLANG['flags'] += '-fopenmp'
def ctypeFromString(typename, includePointers=True):
import ctypes as ct
......@@ -85,7 +91,11 @@ def compile(code, tmpDir, libFile, createAssemblyCode=False):
configEnv = CONFIG['env'] if 'env' in CONFIG else {}
env = os.environ.copy()
env.update(configEnv)
subprocess.call(compilerCmd, env=env)
try:
subprocess.check_output(compilerCmd, env=env, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
print(e.output)
raise e
assembly = None
if createAssemblyCode:
......@@ -97,10 +107,11 @@ def compile(code, tmpDir, libFile, createAssemblyCode=False):
def compileAndLoad(kernelFunctionNode):
with TemporaryDirectory() as tmpDir:
libFile = os.path.join(tmpDir, "jit.so")
compile(generateC(kernelFunctionNode), tmpDir, libFile)
loadedJitLib = cdll.LoadLibrary(libFile)
tmpDir = tempfile.mkdtemp()
libFile = os.path.join(tmpDir, "jit.so")
compile(generateC(kernelFunctionNode), tmpDir, libFile)
loadedJitLib = cdll.LoadLibrary(libFile)
shutil.rmtree(tmpDir)
return loadedJitLib
......@@ -187,7 +198,7 @@ def makePythonFunction(kernelFunctionNode, argumentDict={}):
return lambda: func(*args)
class CachedKernel:
class CachedKernel(object):
def __init__(self, configDict, ast, parameterValues):
self.configDict = configDict
self.ast = ast
......@@ -211,22 +222,23 @@ def hashToFunctionName(h):
def createLibrary(cachedKernels, libraryFile):
libraryInfoFile = libraryFile + ".info"
with TemporaryDirectory() as tmpDir:
code = ""
infoDict = {}
for cachedKernel in cachedKernels:
s = repr(sorted(cachedKernel.configDict.items()))
configHash = hashlib.sha1(s.encode()).hexdigest()
cachedKernel.ast.functionName = hashToFunctionName(configHash)
kernelCode = generateC(cachedKernel.ast)
code += kernelCode + "\n"
infoDict[configHash] = {'code': kernelCode,
'parameterValues': cachedKernel.parameterValues,
'configDict': cachedKernel.configDict,
'parameterSpecification': cachedKernel.ast.parameters}
compile(code, tmpDir, libraryFile)
pickle.dump(infoDict, open(libraryInfoFile, "wb"))
tmpDir = tempfile.mkdtemp()
code = ""
infoDict = {}
for cachedKernel in cachedKernels:
s = repr(sorted(cachedKernel.configDict.items()))
configHash = hashlib.sha1(s.encode()).hexdigest()
cachedKernel.ast.functionName = hashToFunctionName(configHash)
kernelCode = generateC(cachedKernel.ast)
code += kernelCode + "\n"
infoDict[configHash] = {'code': kernelCode,
'parameterValues': cachedKernel.parameterValues,
'configDict': cachedKernel.configDict,
'parameterSpecification': cachedKernel.ast.parameters}
compile(code, tmpDir, libraryFile)
pickle.dump(infoDict, open(libraryInfoFile, "wb"))
shutil.rmtree(tmpDir)
def loadLibrary(libraryFile):
......
......@@ -3,7 +3,7 @@ from copy import deepcopy
from pystencils.sympyextensions import fastSubs, countNumberOfOperations, sortEquationsTopologically
class EquationCollection:
class EquationCollection(object):
"""
A collection of equations with subexpression definitions, also represented as equations,
that are used in the main equations. EquationCollections can be passed to simplification methods.
......@@ -40,6 +40,9 @@ class EquationCollection:
def __next__(self):
self._ctr += 1
return sp.Symbol("xi_" + str(self._ctr))
def next(self):
return self.__next__()
if subexpressionSymbolNameGenerator is None:
self.subexpressionSymbolNameGenerator = SymbolGen()
......
import sympy as sp
import textwrap
from collections import namedtuple
class SimplificationStrategy:
class SimplificationStrategy(object):
"""
A simplification strategy is an ordered collection of simplification rules.
Each simplification is a function taking an equation collection, and returning a new simplified
......@@ -71,15 +70,15 @@ class SimplificationStrategy:
htmlTable += "</table>"
return htmlTable
import time
import timeit
report = Report()
op = equationCollection.operationCount
total = op['adds'] + op['muls'] + op['divs']
report.add(ReportElement("OriginalTerm", '-', op['adds'], op['muls'], op['divs'], total))
for t in self._rules:
startTime = time.perf_counter()
startTime = timeit.default_timer()
equationCollection = t(equationCollection)
endTime = time.perf_counter()
endTime = timeit.default_timer()
op = equationCollection.operationCount
timeStr = "%.2f ms" % ((endTime - startTime) * 1000,)
total = op['adds'] + op['muls'] + op['divs']
......@@ -100,7 +99,7 @@ class SimplificationStrategy:
if self.restrictSymbols:
text += "\n".join([str(e) for e in eqColl.get(self.restrictSymbols)])
else:
text += textwrap.indent(str(eqColl), " " * 3)
text += (" " * 3 + (" " * 3).join(str(eqColl).splitlines(True)))
return text
result = printEqCollection("Initial Version", self.equationCollection)
......
......@@ -6,7 +6,7 @@ from sympy.tensor import IndexedBase
from pystencils.types import TypedSymbol
class Field:
class Field(object):
"""
With fields one can formulate stencil-like update rules on structured grids.
This Field class knows about the dimension, memory layout (strides) and optionally about the size of an array.
......
import llvmlite.ir as ir
class Loop:
class Loop(object):
def __init__(self, builder, start_val, stop_val, step_val=1, loop_name='loop', phi_name="_phi"):
self.builder = builder
self.start_val = start_val
......
......@@ -289,8 +289,8 @@ def mostCommonTermFactorization(term):
if len(symbolsInFactorization) <= 1:
return sp.Mul(commonFactor, term, evaluate=False)
else:
return sp.Mul(commonFactor, *symbolsInFactorization[:-1],
constantsInFactorization * symbolsInFactorization[-1])
args = symbolsInFactorization[:-1] + [constantsInFactorization * symbolsInFactorization[-1]]
return sp.Mul(commonFactor, *args)
else:
return sp.Mul(commonFactor, term, evaluate=False)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment