diff --git a/.gitignore b/.gitignore index a2d6a99f84db6fcb2c2be09dcef62fb2d1a60d1c..4a07a1b46da8abf8ebbd204d3ca42e4cdb5f5db4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,10 @@ Makefile.in .deps/ .libs/ -config.* +config.guess +config.h.in +config.h +config.sub Makefile diff --git a/music-config/config.py b/music-config/config.py new file mode 100644 index 0000000000000000000000000000000000000000..e7a3b81722ba1f18f534d4031ec0cd8c90ceb1cd --- /dev/null +++ b/music-config/config.py @@ -0,0 +1,250 @@ +# +# This file is part of MUSIC. +# Copyright (C) 2012 Mikael Djurfeldt +# +# MUSIC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# MUSIC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# This API allows for querying the MPI rank and specification of the +# information in MUSIC configuration files + +import os + +from music.predict_rank import predictRank + +# This function now defined in predict_rank.py +# +#def predictRank (): +# """ +# Returns the predicted MPI rank of this process +# +# :rtype: Integer +# """ +# return 0 + +CONFIGVARNAME = '_MUSIC_CONFIG_' + +OUTPUT = '0' +INPUT = '1' + + +def launchedByMusic (): + return CONFIGVARNAME in os.environ + + +def supersedeArgv (argv): + """ + Replace argc and argv before MUSIC initialization + """ + # Should insert escape characters + args = argv[0] + for arg in argv[1:]: + args += ' ' + arg + os.environ['MUSIC_ARGV'] = args + + +def postponeSetup (): + """ + Postpones processing of configuration info until the creation of + the first port. Must be called before creation of MUSIC::Setup. + """ + if not thisApp: + raise RuntimeError, \ + 'must define Application before calling postponeSetup ()' + os.environ[CONFIGVARNAME] = 'POSTPONE:' + str (thisApp.number) + + +portCodes = {} +code = 0 + +def portCode (appName, portName): + global code + key = (appName, portName) + if key in portCodes: + return portCodes[key] + portCodes[key] = code + ans = code + code += 1 + return ans + + +class ConnectivityMap (object): + def __init__ (self): + self.ports = {} + + def register (self, portName, direction, width, *connection): + if portName in self.ports: + (direction_, width_, connections) = self.ports[portName] + #*fixme* error checks here + else: + connections = [] + self.ports[portName] = (direction, width, connections) + connections.append (connection) + + def conf (self): + conf = str (len (self.ports)) + for portName in self.ports: + (direction, width, connections) = self.ports[portName] + conf += ':' + portName + ':' + direction + ':' + width + conf += ':' + str (len (connections)) + for connection in connections: + for item in connection: + conf += ':' + item + return conf + + +configDict = {} +appNumber = 0 +rankSum = 0 +thisRank = predictRank () +thisApp = None + +class Application (object): + def __init__ (self, np = None, binary = None, args = None, name = None): + global appNumber, rankSum, thisApp + self.name = name + self.number = appNumber + appNumber += 1 + self.np = np + self.leader = rankSum + rankSum += np + self.this = False + if self.leader <= thisRank and thisRank < rankSum: + self.this = True + thisApp = self + + self.configDict = {} + self.connectivityMap = ConnectivityMap () + + if binary: + self.define ('binary', binary) + if args: + self.define ('args', args) + + applicationMap.register (self) + + def __getitem__ (self, varName): + if varName in self.configDict: + return self.configDict[varName] + return configDict[varName] + + def define (self, varName, value): + """ + Define configuration variable varName to value value. + """ + self.configDict[varName] = str (value) + + def connect (self, fromPort, toApp, toPort, width): + """ + Connect fromPort to toPort. + """ + connections.append ((self, fromPort, toApp, toPort, str (width))) + + +class ApplicationMap (object): + def __init__ (self): + self.applications = [] + self.nameMap = {} + + def register (self, app): + if not app.name: + app.name = 'application' + if app.name in self.nameMap: + # Adjust the name to become unique + record = self.nameMap[app.name] + base, suffix = record + if base == app.name: + suffix += 1 + record[1] = suffix + else: + base = app.name + suffix = 0 + self.nameMap[base] = [base, suffix] + app.name += str (suffix) + else: + self.nameMap[app.name] = [app.name, 0] + self.applications.append (app) + + def conf (self): + conf = str (len (self.applications)) + for app in self.applications: + conf += ':' + app.name + ':' + str (app.np) + return conf + +applicationMap = ApplicationMap () + + +def define (varName, value): + """ + Define configuration variable varName to value value. + """ + configDict[varName] = str (value) + + +# Communication algorithms + +commAlgorithms = { 'collective' : 0, 'point-to-point' : 1 } + +# Processing methods + +procMethods = { 'tree' : 0, 'table' : 1 } + + +def connect (fromApp, fromPort, toApp, toPort, width, + commAlgName = 'collective', procMethodName = 'table'): + """ + Connect fromPort to toPort specifying port width width. + """ + width = str (width) + commAlg = commAlgorithms[commAlgName] + procMethod = procMethods[procMethodName] + fromApp.connectivityMap.register (fromPort, OUTPUT, width, + toApp.name, toPort, + str (portCode (toApp.name, toPort)), + str (toApp.leader), str (toApp.np), + str (commAlg), str (procMethod)) + toApp.connectivityMap.register (toPort, INPUT, width, + toApp.name, toPort, + str (portCode (toApp.name, toPort)), + str (fromApp.leader), str (fromApp.np), + str (commAlg), str (procMethod)) + + +configured = False + +def configure (): + """ + Configure the MUSIC library using the information provided by + define and connect. + """ + conf = thisApp.name \ + + ':' + str (thisApp.number) \ + + ':' + applicationMap.conf () \ + + ':' + thisApp.connectivityMap.conf () + + configDict.update (thisApp.configDict) + + for key in configDict: + conf += ':' + key + '=' + configDict[key] + + os.environ[CONFIGVARNAME] = conf + + configured = True + + +def launch (): + if not configured: + configure () + binary = thisApp['binary'] + os.execvp (binary, [binary] + thisApp['args'].split (' '))