# restartlib -- all the helper functions to assist the SimRestart class. # this seperation allows SimRemote to remain a fairly clean abstraction. import pyini import time import shutil import sys, os, re class WallTime: def __init__(self, walltime=None): self.Walltime = walltime self.parseWalltime() def parseWalltime(self): if self.Walltime == None: self.Walltime = '876:00:00' # one year print "Warning, Walltime not specified, using %s instead" % self.Walltime if self.Walltime.count(":") == 0: print "Wall time has invalid format, expecting HH[:MM[:SS]]" sys.exit(1) parts = self.Walltime.split(":") self.walltime_hh = "%02d" % int(parts[0]) self.walltime_mm = "00" self.walltime_ss = "00" if len(parts) == 2: self.walltime_mm = "%02d" % int(parts[1]) if len(parts) == 3: self.walltime_mm = "%02d" % int(parts[1]) self.Walltime = "%d:%02d:%02d" % (int(self.walltime_hh), int(self.walltime_mm), int(self.walltime_ss)) self.walltime_seconds = int(self.walltime_hh) * 3600 + int(self.walltime_mm) * 60 + int(self.walltime_ss) self.walltime_minutes = self.walltime_seconds / 60 self.walltime_hours = self.walltime_seconds / 3600.0 class RestartProperties: def __init__(self, env): self.SimEnvironment = env self.SimLib = env.SimLib self.IniSection = 'properties' def init(self, filename=None): self.Filename = filename if not(os.path.exists(filename)): filename = None self.parser = pyini.IniParser(filename) if filename != None: self.ImportProperties() self.AddProperty('active', 'no') self.AddProperty('running', 'no') self.AddProperty('queued', 'no') def ImportProperties(self): section = self.parser.GetSectionAsDict(self.IniSection) for key in section.keys(): io = section[key] if io.IsBlock: io.ConvertToList() value = io.Value setattr(self, key, value) def AddProperty(self, key, value): if value is list: block = True bi = "EOT" else: block = False bi = None op = pyini.IniOption(self.IniSection, key, value, block) op.BlockIdentifier = bi self.parser.parser.EnterSection('properties') #self.WriteKey(self.CurrentSection, self.BlockKey, op) self.parser.parser.WriteKey(self.IniSection, key, op) setattr(self, key, value) def toString(self): return self.parser.GetIniAsString() def Save(self): if self.Filename == None: print "Could not write to filename, filename is undefined" sys.exit(1) self.SimLib.WriteContents(self.Filename, self.parser.GetIniAsString()) class RestartLib: def __init__(self, env): self.SimEnvironment = env self.OptionsManager = self.SimEnvironment.OptionsManager self.ConfigurationDatabase = self.SimEnvironment.ConfigurationDatabase self.DefineDatabase = self.SimEnvironment.DefineDatabase self.SimLib = self.SimEnvironment.SimLib def GetConfiguration(self): if not(self.OptionsManager.HasOption("configuration")): config = self.SimLib.GetDefaultConfiguration() print "Configuration name not specified -- using default configuration \"%s\"" % config return config return self.OptionsManager.GetOption("configuration") def GetRestartIds(self, restart): simulationdir = restart.SimulationDir expression = "^output-([0-9]+)$" rr = re.compile(expression) ids = list() for file in os.listdir(simulationdir): matches = rr.match(file) if matches != None: id = matches.group(1) ids.append(int(id)) ids.sort() return ids def GetActiveRestartId(self, restart): ids = self.GetRestartIds(restart) active = 0 simulationdir = restart.SimulationDir if len(ids) == 0: return active for id in ids: aid = "%04d" % id afolder = "output-%s-active" % aid if os.path.exists(self.SimLib.BuildPath([simulationdir, afolder])): if active != 0: print "Error, more than one active restart id found in directory %s" % simulationdir sys.exit(1) active = aid return active def GetCheckpointFiles(self, restore_dir, simulation_name): expression = "\.chkpt\.it_([0-9]+)\." workdir = self.SimLib.BuildPath(restore_dir, simulation_name) if not(os.path.exists(workdir)): print "Could not access simulation output directory \"%s\"" % workdir sys.exit(1) max_iter = 0 for file in os.listdir(workdir): matches = re.search(expression, file) if matches == None: continue try: ii = int(matches.group(1)) except ValueError: print "Error, could not convert chkpt iteration match %s to an integer" % matches.group(1) sys.exit(1) if ii > max_iter: max_iter = ii files = list() # now that we have our max iter, lets get all of our checkpoint files for file in os.listdir(workdir): matches = re.search(expression, file) if matches == None: continue try: ii = int(matches.group(1)) except ValueError: print "Error, could not convert chkpt iteration match %s to an integer" % matches.group(1) sys.exit(1) if ii == max_iter: files.append(file) return (files, max_iter) def GetExecutable(self): configuration = self.GetConfiguration() (machine, machineEntry, sourceBaseDir, path) = self.SimLib.GetLocalEnvironment() configPath = self.SimLib.BuildPath([self.SimEnvironment.CONFIGS_PATH, configuration]) if not(self.SimLib.FileExists(configPath)): print "Error, configuration '%s', which has path '%s' does not exist or is not readable" % (configuration, configPath) sys.exit(1) exe = self.SimLib.BuildPath([self.SimEnvironment.CACTUS_PATH, 'exe', 'cactus_%s' % configuration]) if not(self.SimLib.FileExists(exe)): print "Executable %s for configuration %s does not exist or is not readable" % (exe, configuration) sys.exit(1) scriptFile = self.SimLib.BuildPath([configPath, "ScriptFile"]) if not(self.SimLib.FileExists(scriptFile)): print "ScriptFile %s for configuration %s does not exist or is not readable" % (scriptFile, configuration) sys.exit(1) return (exe, scriptFile) def CreateSimulationId(self, simulationName): (machine, machineEntry, sourceBaseDir, path) = self.SimLib.GetLocalEnvironment() hostname = machineEntry.hostname user = os.popen('whoami').read().strip() tt = time.localtime() timestamp = "%4d.%02d.%02d-%02d.%02d.%02d" % (tt.tm_year, tt.tm_mon, tt.tm_mday, tt.tm_hour, tt.tm_min, tt.tm_sec) pid = os.getpid() simulation_id = "simulation-%s-%s-%s-%s-%s-%s" % (simulationName, machine, hostname, user, timestamp, pid) return simulation_id def CreatePbsSimulationName(self, SimRestart): simulationName = "%s-%s" % (SimRestart.SimulationName, SimRestart.LongRestartID) pid = os.getpid() if self.OptionsManager.HasOption('hide') and self.OptionsManager.GetOption('hide') == True: shortString = "sim-%06d" % pid elif self.OptionsManager.HasOption('hide-boring') and self.OptionsManager.GetOption('hide-boring') == True: words = ['headon', 'D3.0', 'a0.6', 'mu0.25', 'PN1.5', 'FMR', '1+log', 'nowaves', 'findAH', 'coarse', 'singleBH', 'PUGH', 'movie'] random.seed() randomWord = words[random.randint(0, len(words)-1)] shortString = "sim-%s-%s" % (randomWord, pid) elif self.OptionsManager.HasOption('hide-dangerous') and self.OptionsManager.GetOption('hide-dangerous') == True: words = ['paramesh', 'D25.0', 'a0.999', 'mu0.01', 'PN4.0', 'CCM', 'spec35', 'maximal', 'string', 'FE', 'tail', 'DSS', 'PRL', 'naked']; random.seed() randomWord = words[random.randint(0, len(words)-1)] shortString = "sim-%s-%s" % (randomWord, pid) else: shortString = simulationName shortString = re.sub("^[\x20-\x7E]", "", shortString) shortString = re.sub("[\s]", "_", shortString) shortString = re.sub("^(?![A-Za-z])", "J", shortString) # limit to 15 characters. shortString = shortString[:15] return shortString def CopyFileWithCaching(self, srcfile, destdir, cachedir): # os.link == create hard link. # os.makedirs() == recurse make directories. if not(os.path.exists(cachedir)): try: os.makedirs(cachedir) except: print "Error, could not create cache directory: %s" % cachedir sys.exit(1) filename = self.SimLib.BaseName(srcfile) cachefile = self.SimLib.BuildPath([cachedir, filename]) dstfile = self.SimLib.BuildPath([destdir, filename]) if not(os.path.exists(cachefile)): if os.path.exists(dstfile): try: os.remove(dstfile) except: print "Could not remove existing destination file %s" % dstfile sys.exit(1) try: shutil.copyfile(srcfile, dstfile) except: print "Error, Could not copy %s to %s" % (srcfile, dstfile) sys.exit(1) mode = os.stat(srcfile).st_mode os.chmod(dstfile, mode) os.link(dstfile, cachefile) return # cachefile exists os.link(cachefile, dstfile) eq = True srcstat = os.stat(srcfile) dststat = os.stat(dstfile) eq = eq and srcstat.st_mtime >= dststat.st_mtime eq = eq and srcstat.st_size == dststat.st_size if eq == False: os.remove(dstfile) shutil.copyfile(srcfile, dstfile) mode = os.stat(srcfile).st_mode os.chmod(dstfile, mode) if os.path.exists(cachefile): try: os.unlink(cachefile) except: print "Could not remove existing cached executable %s" % cachefile os.link(dstfile, cachefile) def CreateInternalDirs(self, internaldir): roots = ['exe', 'cfg', 'run', 'par', 'data'] mdirs = [] for root in roots: fullpath = self.SimLib.BuildPath([internaldir, root]) try: os.makedirs(fullpath) except: print "could not make %s directory: %s" % (root, fullpath) sys.exit(1) mdirs.append(fullpath) return mdirs def GetMaxRestartID(self, restart): rids = self.GetRestartIds(restart) if len(rids) == 0: max_restart_id = 0 else: max_restart_id = rids[len(rids)-1] return max_restart_id def CreateRestartSkeleton(self, simulationName): (machine, machineEntry, sourceBaseDir, path) = self.SimLib.GetLocalEnvironment() basedir = self.SimLib.GetBaseDir(machineEntry) if not(self.SimLib.FileExists(basedir)): print "Could not access simulation base directory %s for reading and writing" % basedir sys.exit(1) simulationdir = self.SimLib.BuildPath([basedir, simulationName]) if self.SimLib.FileExists(simulationdir): print "Cannot create job skeleton directory: Directory \"%s\" already exists" % simulationdir sys.exit(1) try: os.mkdir(simulationdir) except OSError: print "Could not create simulation skeleton directory \"%s\"" % simulationdir sys.exit(1) internaldir = self.SimLib.BuildPath([simulationdir, self.SimEnvironment.INTERNALDIRECTORY]) if self.SimLib.FileExists(internaldir): print "Cannot create job skeleton directory: Directory \"%s\" already exists" % internaldir sys.exit(1) try: os.mkdir(internaldir) except OSError: print "Could not create simulation skeleton directory \"%s\"" % internaldir sys.exit(1) cachedir = self.SimLib.BuildPath([basedir, 'CACHE']) if not(self.SimLib.FileExists(cachedir)): try: os.mkdir(cachedir) except OSError: print "Could not create simulation skeleton directory \"%s\"" % cachedir sys.exit(1) return (basedir, simulationdir, internaldir, cachedir)