#!/usr/bin/env python2 # Copyright (c) 2005 The Regents of The University of Michigan # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer; # redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution; # neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Authors: Nathan Binkert # Steve Reinhardt # Ali Saidi import os, os.path, shutil, signal, socket, sys from os import environ as env from os.path import join as joinpath, expanduser def date(): import time return time.strftime('%a %b %e %H:%M:%S %Z %Y', time.localtime()) def cleandir(dir): for root, dirs, files in os.walk(dir, False): for name in files: os.remove(joinpath(root, name)) for name in dirs: os.rmdir(joinpath(root, name)) class rsync: def __init__(self): self.sudo = False self.rsync = 'rsync' self.compress = False self.archive = True self.delete = False self.options = '' def do(self, src, dst): args = [] if self.sudo: args.append('sudo') args.append(self.rsync) if (self.archive): args.append('-a') if (self.compress): args.append('-z') if (self.delete): args.append('--delete') if len(self.options): args.append(self.options) args.append(src) args.append(dst) return os.spawnvp(os.P_WAIT, args[0], args) class JobDir(object): def __init__(self, dir): self.dir = dir def file(self, filename): return joinpath(self.dir, filename) def create(self): if os.path.exists(self.dir): if not os.path.isdir(self.dir): sys.exit('%s is not a directory. Cannot build job' % self.dir) else: os.mkdir(self.dir) def exists(self): return os.path.isdir(self.dir) def clean(self): cleandir(self.dir) def hasfile(self, filename): return os.path.isfile(self.file(filename)) def echofile(self, filename, string): filename = self.file(filename) try: f = file(filename, 'w') print >>f, string f.flush() f.close() except IOError,e: sys.exit(e) def rmfile(self, filename): filename = self.file(filename) if os.path.isfile(filename): os.unlink(filename) def readval(self, filename): filename = self.file(filename) f = file(filename, 'r') value = f.readline().strip() f.close() return value def setstatus(self, string): filename = self.file('.status') try: f = file(filename, 'a') print >>f, string f.flush() f.close() except IOError,e: sys.exit(e) def getstatus(self): filename = self.file('.status') try: f = file(filename, 'r') except IOError, e: return 'none' # fast forward to the end for line in f: pass # the first word on the last line is the status return line.split(' ')[0] def __str__(self): return self.dir if __name__ == '__main__': rootdir = env.setdefault('ROOTDIR', os.getcwd()) pbs_jobid = env['PBS_JOBID'] pbs_jobname = env['PBS_JOBNAME'] basedir = joinpath(rootdir, 'Base') jobname = env.setdefault('JOBNAME', pbs_jobname) jobfile = env.setdefault('JOBFILE', joinpath(rootdir, 'Test.py')) outdir = env.setdefault('OUTPUT_DIR', joinpath(rootdir, jobname)) env['POOLJOB'] = 'True' if os.path.isdir("/work"): workbase = "/work" else: workbase = "/tmp/" workdir = joinpath(workbase, '%s.%s' % (env['USER'], pbs_jobid)) host = socket.gethostname() os.umask(0022) jobdir = JobDir(outdir) started = date() jobdir.echofile('.running', started) jobdir.rmfile('.queued') jobdir.echofile('.host', host) jobdir.setstatus('running on %s on %s' % (host, started)) if os.path.isdir(workdir): cleandir(workdir) else: os.mkdir(workdir) if False and os.path.isdir('/z/dist'): sync = rsync() sync.delete = True sync.sudo = True sync.do('poolfs::dist/m5/', '/z/dist/m5/') try: os.chdir(workdir) except OSError,e: sys.exit(e) os.symlink(jobdir.file('output'), 'status.out') args = [ joinpath(basedir, 'm5'), joinpath(basedir, 'run.py') ] if not len(args): sys.exit("no arguments") print 'starting job... %s' % started print ' '.join(args) print sys.stdout.flush() childpid = os.fork() if not childpid: # Execute command sys.stdin.close() fd = os.open(jobdir.file("output"), os.O_WRONLY | os.O_CREAT | os.O_TRUNC) os.dup2(fd, sys.stdout.fileno()) os.dup2(fd, sys.stderr.fileno()) os.execvp(args[0], args) def handler(signum, frame): if childpid != 0: os.kill(childpid, signum) signal.signal(signal.SIGHUP, handler) signal.signal(signal.SIGINT, handler) signal.signal(signal.SIGQUIT, handler) signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGCONT, handler) signal.signal(signal.SIGUSR1, handler) signal.signal(signal.SIGUSR2, handler) done = 0 while not done: try: thepid,ec = os.waitpid(childpid, 0) if ec: print 'Exit code ', ec status = 'failure' else: status = 'success' done = 1 except OSError: pass complete = date() print '\njob complete... %s' % complete jobdir.echofile('.%s' % status, complete) jobdir.rmfile('.running') jobdir.setstatus('%s on %s' % (status, complete))