From eb9e40d78dbd3ea491cc6a5a6c93a16b15ade3b2 Mon Sep 17 00:00:00 2001 From: Martin Bauer <martin.bauer@fau.de> Date: Tue, 21 Feb 2017 17:33:45 +0100 Subject: [PATCH] pystencils compiler config moved to configuration file --- cpu/cpujit.py | 145 +++++++++++++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 54 deletions(-) diff --git a/cpu/cpujit.py b/cpu/cpujit.py index 789d08a64..20d414aeb 100644 --- a/cpu/cpujit.py +++ b/cpu/cpujit.py @@ -8,38 +8,98 @@ from pystencils.backends.cbackend import generateC import numpy as np import pickle import hashlib - +import json +from collections import OrderedDict from pystencils.transformations import symbolNameToVariableName -CONFIG_GCC = { - 'compiler': 'g++', - 'flags': '-Ofast -DNDEBUG -fPIC -shared -march=native -fopenmp', -} -CONFIG_INTEL = { - 'compiler': '/software/intel/2017/bin/icpc', - 'flags': '-Ofast -DNDEBUG -fPIC -shared -march=native -fopenmp -Wl,-rpath=/software/intel/2017/lib/intel64', - 'env': { - 'INTEL_LICENSE_FILE': '1713@license4.rrze.uni-erlangen.de', - 'LM_PROJECT': 'iwia', - } -} -CONFIG_INTEL_SUPERMUC = { - 'compiler': '/lrz/sys/intel/studio2017_u1/compilers_and_libraries_2017.1.132/linux/bin/intel64/icpc', - 'flags': '-Ofast -DNDEBUG -fPIC -shared -march=native -fopenmp -Wl,' - '-rpath=/lrz/sys/intel/studio2016_u4/compilers_and_libraries_2016.4.258/linux/mkl/lib/intel64', - 'env': { - 'INTEL_LICENSE_FILE': '/lrz/sys/intel/licenses', + +def makePythonFunction(kernelFunctionNode, argumentDict={}): + """ + 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 kernelFunctionNode: the abstract syntax tree + :param argumentDict: parameters passed here are already fixed. Remaining parameters have to be passed to the + returned kernel functor. + :return: kernel functor + """ + # build up list of CType arguments + try: + args = buildCTypeArgumentList(kernelFunctionNode.parameters, argumentDict) + except KeyError: + # not all parameters specified yet + return makePythonFunctionIncompleteParams(kernelFunctionNode, argumentDict) + func = compileAndLoad(kernelFunctionNode)[kernelFunctionNode.functionName] + func.restype = None + return lambda: func(*args) + + +def setCompilerConfig(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": "/software/intel/2017/bin/icpc", + "flags": "-Ofast -DNDEBUG -fPIC -shared -march=native -fopenmp", + "env": { + "LM_PROJECT": "iwia", + } } -} -CONFIG_CLANG = { - 'compiler': 'clang++', - 'flags': '-Ofast -DNDEBUG -fPIC -shared -march=native ', -} -CONFIG = CONFIG_GCC + `` + """ + global _compilerConfig + _compilerConfig = config.copy() + +def getConfigurationFilePath(): + configFileName = ".pystencils.json" + configPathInHome = os.path.expanduser(os.path.join("~", configFileName)) -if CONFIG is CONFIG_CLANG and not 'Apple LLVM' in subprocess.check_output(['clang++', '--version']): - CONFIG_CLANG['flags'] += '-fopenmp' + # 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(configFileName): + return configFileName, True + # 3) Try ~/.pystencils.json + elif os.path.exists(configPathInHome): + return configPathInHome, True + else: + return configPathInHome, False + + +def readCompilerConfig(): + defaultConfig = OrderedDict([ + ('compiler', 'g++'), + ('flags', '-Ofast -DNDEBUG -fPIC -shared -march=native -fopenmp'), + ]) + configPath, configExists = getConfigurationFilePath() + config = defaultConfig.copy() + if configExists: + config.update(json.load(open(configPath, 'r'))) + json.dump(config, open(configPath, 'w'), indent=4) + return config + + +_compilerConfig = readCompilerConfig() + + +def getCompilerConfig(): + return _compilerConfig def ctypeFromString(typename, includePointers=True): @@ -86,9 +146,10 @@ def compile(code, tmpDir, libFile, createAssemblyCode=False): print(code, file=sourceFile) print('}', file=sourceFile) - compilerCmd = [CONFIG['compiler']] + CONFIG['flags'].split() + config = getCompilerConfig() + compilerCmd = [config['compiler']] + config['flags'].split() compilerCmd += [srcFile, '-o', libFile] - configEnv = CONFIG['env'] if 'env' in CONFIG else {} + configEnv = config['env'] if 'env' in config else {} env = os.environ.copy() env.update(configEnv) try: @@ -100,7 +161,7 @@ def compile(code, tmpDir, libFile, createAssemblyCode=False): assembly = None if createAssemblyCode: assemblyFile = os.path.join(tmpDir, "assembly.s") - compilerCmd = [CONFIG['compiler'], '-S', '-o', assemblyFile, srcFile] + CONFIG['flags'].split() + compilerCmd = [config['compiler'], '-S', '-o', assemblyFile, srcFile] + config['flags'].split() subprocess.call(compilerCmd, env=env) assembly = open(assemblyFile, 'r').read() return assembly @@ -174,30 +235,6 @@ def makePythonFunctionIncompleteParams(kernelFunctionNode, argumentDict): return wrapper -def makePythonFunction(kernelFunctionNode, argumentDict={}): - """ - 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 kernelFunctionNode: the abstract syntax tree - :param argumentDict: parameters passed here are already fixed. Remaining parameters have to be passed to the - returned kernel functor. - :return: kernel functor - """ - # build up list of CType arguments - try: - args = buildCTypeArgumentList(kernelFunctionNode.parameters, argumentDict) - except KeyError: - # not all parameters specified yet - return makePythonFunctionIncompleteParams(kernelFunctionNode, argumentDict) - func = compileAndLoad(kernelFunctionNode)[kernelFunctionNode.functionName] - func.restype = None - return lambda: func(*args) - - class CachedKernel(object): def __init__(self, configDict, ast, parameterValues): self.configDict = configDict -- GitLab