Adding gem5 source to svn.

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1819 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
friemel
2012-10-24 19:18:57 +00:00
parent f7ff71bd46
commit b41eec3f65
3222 changed files with 658579 additions and 1 deletions

View File

@ -0,0 +1,34 @@
# -*- mode:python -*-
# Copyright (c) 2004-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: Steve Reinhardt
# Nathan Binkert
Import('*')
PySource('m5', 'jobfile.py')

View File

@ -0,0 +1,249 @@
# Copyright (c) 2006 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: Kevin Lim
import os, popen2, re, sys
class MyPOpen(object):
def __init__(self, cmd, input = None, output = None, bufsize = -1):
self.status = -1
if input is None:
p2c_read, p2c_write = os.pipe()
self.tochild = os.fdopen(p2c_write, 'w', bufsize)
else:
p2c_write = None
if isinstance(input, file):
p2c_read = input.fileno()
elif isinstance(input, str):
input = file(input, 'r')
p2c_read = input.fileno()
elif isinstance(input, int):
p2c_read = input
else:
raise AttributeError
if output is None:
c2p_read, c2p_write = os.pipe()
self.fromchild = os.fdopen(c2p_read, 'r', bufsize)
else:
c2p_read = None
if isinstance(output, file):
c2p_write = output.fileno()
elif isinstance(output, str):
output = file(output, 'w')
c2p_write = output.fileno()
elif isinstance(output, int):
c2p_write = output
else:
raise AttributeError
self.pid = os.fork()
if self.pid == 0:
os.dup2(p2c_read, sys.stdin.fileno())
os.dup2(c2p_write, sys.stdout.fileno())
os.dup2(c2p_write, sys.stderr.fileno())
try:
os.execvp(cmd[0], cmd)
finally:
os._exit(1)
os.close(p2c_read)
os.close(c2p_write)
def poll(self):
if self.status < 0:
pid, status = os.waitpid(self.pid, os.WNOHANG)
if pid == self.pid:
self.status = status
return self.status
def wait(self):
if self.status < 0:
pid, status = os.waitpid(self.pid, 0)
if pid == self.pid:
self.status = status
return self.status
class oarsub:
def __init__(self):
self.walltime = None
self.queue = None
self.properties = None
# OAR 2.0 parameters only!
self.name = None
self.afterok = None
self.notify = None
self.stderr = None
self.stdout = None
self.oarhost = None
self.oarsub = 'oarsub'
self.jobid = re.compile('IdJob = (\S+)')
#self.outfile = open("jobnames.dat", "a+")
def build(self, script, args = []):
self.cmd = [ self.oarsub ]
print "args:", args
print "script:", script
if self.properties:
self.cmd.append('-p"%s"' % self.properties )
if self.queue:
self.cmd.append('-q "%s"' % self.queue)
if self.walltime:
self.cmd.append('-l walltime=%s' % self.walltime)
if script[0] != "/":
self.script = os.getcwd()
else:
self.script = script
self.cmd.extend(args)
self.cmd.append(self.script)
#cmd = [ 'ssh', '-x', self.oarhost, '"cd %s; %s"' % (os.getcwd(), self.command) ]
self.command = ' '.join(self.cmd)
print "command: [%s]" % self.command
def do(self):
oar = MyPOpen(self.cmd)
self.result = oar.fromchild.read()
ec = oar.wait()
if ec != 0 and self.oarhost:
pstdin, pstdout = os.popen4(self.command)
self.result = pstdout.read()
jobid = self.jobid.match(self.result)
if jobid == None:
print "Couldn't get jobid from [%s]" % self.result
sys.exit(1)
else:
#self.outfile.write("%d %s\n" %(int(jobid.group(1)), self.name));
#self.outfile.flush()
self.result = jobid.group(1)
return 0
class qsub:
def __init__(self):
self.afterok = None
self.hold = False
self.join = False
self.keep_stdout = False
self.keep_stderr = False
self.node_type = None
self.mail_abort = False
self.mail_begin = False
self.mail_end = False
self.name = None
self.stdout = None
self.priority = None
self.queue = None
self.pbshost = None
self.qsub = 'qsub'
self.env = {}
def build(self, script, args = []):
self.cmd = [ self.qsub ]
if self.env:
arg = '-v'
arg += ','.join([ '%s=%s' % i for i in self.env.iteritems() ])
self.cmd.append(arg)
if self.hold:
self.cmd.append('-h')
if self.stdout:
self.cmd.append('-olocalhost:' + self.stdout)
if self.keep_stdout and self.keep_stderr:
self.cmd.append('-koe')
elif self.keep_stdout:
self.cmd.append('-ko')
elif self.keep_stderr:
self.cmd.append('-ke')
else:
self.cmd.append('-kn')
if self.join:
self.cmd.append('-joe')
if self.node_type:
self.cmd.append('-lnodes=' + self.node_type)
if self.mail_abort or self.mail_begin or self.mail_end:
flags = ''
if self.mail_abort:
flags.append('a')
if self.mail_begin:
flags.append('b')
if self.mail_end:
flags.append('e')
if len(flags):
self.cmd.append('-m ' + flags)
else:
self.cmd.append('-mn')
if self.name:
self.cmd.append("-N%s" % self.name)
if self.priority:
self.cmd.append('-p' + self.priority)
if self.queue:
self.cmd.append('-q' + self.queue)
if self.afterok:
self.cmd.append('-Wdepend=afterok:%s' % self.afterok)
self.cmd.extend(args)
self.script = script
self.command = ' '.join(self.cmd + [ self.script ])
def do(self):
pbs = MyPOpen(self.cmd + [ self.script ])
self.result = pbs.fromchild.read()
ec = pbs.wait()
if ec != 0 and self.pbshost:
cmd = ' '.join(self.cmd + [ '-' ])
cmd = [ 'ssh', '-x', self.pbshost, cmd ]
self.command = ' '.join(cmd)
ssh = MyPOpen(cmd, input = self.script)
self.result = ssh.fromchild.read()
ec = ssh.wait()
return ec

246
simulators/gem5/util/batch/job.py Executable file
View File

@ -0,0 +1,246 @@
#!/usr/bin/env python
# Copyright (c) 2006 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: Kevin Lim
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__':
import platform
binaries = { 'i686' : 'm5.i386',
'x86_64' : 'm5.amd64' }
binary = binaries[platform.machine()]
cwd = os.getcwd()
rootdir = env.setdefault('ROOTDIR', os.path.dirname(cwd))
oar_jobid = int(env['OAR_JOBID'])
oar_jobname = os.path.basename(cwd)
#pbs_jobname = env['PBS_JOBNAME']
basedir = joinpath(rootdir, 'Base')
jobname = env.setdefault('JOBNAME', oar_jobname)
jobfile = env.setdefault('JOBFILE', joinpath(rootdir, 'Test.py'))
outdir = env.setdefault('OUTPUT_DIR', cwd)
env['POOLJOB'] = 'True'
if os.path.isdir("/work"):
workbase = "/work"
else:
workbase = "/tmp/"
workdir = joinpath(workbase, '%s.%s' % (env['USER'], oar_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, binary), 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))

View File

@ -0,0 +1,306 @@
#!/usr/bin/env python
# Copyright (c) 2006 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: Kevin Lim
import os, os.path, re, socket, sys
from os import environ as env, listdir
from os.path import basename, isdir, isfile, islink, join as joinpath, normpath
from filecmp import cmp as filecmp
from shutil import copy
def nfspath(dir):
if dir.startswith('/.automount/'):
dir = '/n/%s' % dir[12:]
elif not dir.startswith('/n/'):
dir = '/n/%s%s' % (socket.gethostname().split('.')[0], dir)
return dir
def syncdir(srcdir, destdir):
srcdir = normpath(srcdir)
destdir = normpath(destdir)
if not isdir(destdir):
sys.exit('destination directory "%s" does not exist' % destdir)
for root, dirs, files in os.walk(srcdir):
root = normpath(root)
prefix = os.path.commonprefix([root, srcdir])
root = root[len(prefix):]
if root.startswith('/'):
root = root[1:]
for rem in [ d for d in dirs if d.startswith('.') or d == 'SCCS']:
dirs.remove(rem)
for entry in dirs:
newdir = joinpath(destdir, root, entry)
if not isdir(newdir):
os.mkdir(newdir)
print 'mkdir', newdir
for i,d in enumerate(dirs):
if islink(joinpath(srcdir, root, d)):
dirs[i] = joinpath(d, '.')
for entry in files:
dest = normpath(joinpath(destdir, root, entry))
src = normpath(joinpath(srcdir, root, entry))
if not isfile(dest) or not filecmp(src, dest):
print 'copy %s %s' % (dest, src)
copy(src, dest)
progpath = nfspath(sys.path[0])
progname = basename(sys.argv[0])
usage = """\
Usage:
%(progname)s [-c] [-e] [-f] [-j <jobfile>] [-q queue] [-v] <regexp>
-c clean directory if job can be run
-C submit the checkpointing runs
-d Make jobs be dependent on the completion of the checkpoint runs
-e only echo pbs command info, don't actually send the job
-f force the job to run regardless of state
-q <queue> submit job to the named queue
-j <jobfile> specify the jobfile (default is <rootdir>/Test.py)
-v be verbose
%(progname)s [-j <jobfile>] -l [-v] <regexp>
-j <jobfile> specify the jobfile (default is <rootdir>/Test.py)
-l list job names, don't submit
-v be verbose (list job parameters)
%(progname)s -h
-h display this help
""" % locals()
try:
import getopt
opts, args = getopt.getopt(sys.argv[1:], '-Ccdefhj:lnq:Rt:v')
except getopt.GetoptError:
sys.exit(usage)
depend = False
clean = False
onlyecho = False
exprs = []
force = False
listonly = False
queue = ''
verbose = False
jfile = 'Test.py'
docpts = False
doruns = True
runflag = False
node_type = 'FAST'
update = True
for opt,arg in opts:
if opt == '-C':
docpts = True
if opt == '-c':
clean = True
if opt == '-d':
depend = True
if opt == '-e':
onlyecho = True
if opt == '-f':
force = True
if opt == '-h':
print usage
sys.exit(0)
if opt == '-j':
jfile = arg
if opt == '-l':
listonly = True
if opt == '-n':
update = False
if opt == '-q':
queue = arg
if opt == '-R':
runflag = True
if opt == '-t':
node_type = arg
if opt == '-v':
verbose = True
if docpts:
doruns = runflag
for arg in args:
exprs.append(re.compile(arg))
import jobfile, batch
from job import JobDir, date
conf = jobfile.JobFile(jfile)
if update and not listonly and not onlyecho and isdir(conf.linkdir):
if verbose:
print 'Checking for outdated files in Link directory'
if not isdir(conf.basedir):
os.mkdir(conf.basedir)
syncdir(conf.linkdir, conf.basedir)
jobnames = {}
joblist = []
if docpts and doruns:
gen = conf.alljobs()
elif docpts:
gen = conf.checkpoints()
elif doruns:
gen = conf.jobs()
for job in gen:
if job.name in jobnames:
continue
if exprs:
for expr in exprs:
if expr.match(job.name):
joblist.append(job)
break
else:
joblist.append(job)
if listonly:
if verbose:
for job in joblist:
job.printinfo()
else:
for job in joblist:
print job.name
sys.exit(0)
if not onlyecho:
newlist = []
for job in joblist:
jobdir = JobDir(joinpath(conf.rootdir, job.name))
if jobdir.exists():
if not force:
status = jobdir.getstatus()
if status == 'queued':
continue
if status == 'running':
continue
if status == 'success':
continue
if not clean:
sys.exit('job directory %s not clean!' % jobdir)
jobdir.clean()
newlist.append(job)
joblist = newlist
class NameHack(object):
def __init__(self, host='pbs.pool', port=24465):
self.host = host
self.port = port
self.socket = None
def setname(self, jobid, jobname):
try:
jobid = int(jobid)
except ValueError:
jobid = int(jobid.strip().split('.')[0])
jobname = jobname.strip()
# since pbs can handle jobnames of 15 characters or less,
# don't use the raj hack.
if len(jobname) <= 15:
return
if self.socket is None:
import socket
self.socket = socket.socket()
# Connect to pbs.pool and send the jobid/jobname pair to port
# 24465 (Raj didn't realize that there are only 64k ports and
# setup inetd to point to port 90001)
self.socket.connect((self.host, self.port))
self.socket.send("%s %s\n" % (jobid, jobname))
namehack = NameHack()
rootdir = conf.rootdir
script = joinpath(rootdir, 'Base', 'job.py')
for job in joblist:
jobdir = JobDir(joinpath(rootdir, job.name))
if depend:
cptdir = JobDir(joinpath(rootdir, job.checkpoint.name))
path = str(cptdir)
if not isdir(path) or not isfile(joinpath(path, '.success')):
continue
cptjob = cptdir.readval('.batch_jobid')
if not onlyecho:
jobdir.create()
os.chdir(str(jobdir))
os.environ['PWD'] = str(jobdir)
print 'Job name: %s' % job.name
print 'Job directory: %s' % jobdir
qsub = batch.oarsub()
qsub.oarhost = 'poolfs.eecs.umich.edu'
#qsub.stdout = jobdir.file('jobout')
qsub.name = job.name
qsub.walltime = '50'
#qsub.join = True
#qsub.node_type = node_type
#qsub.env['ROOTDIR'] = conf.rootdir
#qsub.env['JOBNAME'] = job.name
#if depend:
# qsub.afterok = cptjob
#if queue:
# qsub.queue = queue
qsub.properties = "64bit = 'Yes' or 64bit = 'No'"
qsub.build(script)
if verbose:
print 'cwd: %s' % qsub.command
print 'PBS Command: %s' % qsub.command
if not onlyecho:
ec = qsub.do()
if ec == 0:
jobid = qsub.result
print 'OAR Jobid: %s' % jobid
#namehack.setname(jobid, job.name)
queued = date()
jobdir.echofile('.batch_jobid', jobid)
jobdir.echofile('.batch_jobname', job.name)
jobdir.echofile('.queued', queued)
jobdir.setstatus('queued on %s' % queued)
else:
print 'OAR Failed'
print
print

View File

@ -0,0 +1,197 @@
/*
* Copyright (c) 2004 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: Ali Saidi
*/
#include <asm/io.h>
#include <asm/page.h>
#include <asm/uaccess.h>
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#ifdef __i386__
#include <asm/msr.h>
#include <asm/processor.h>
#endif
#define DRIVER_AUTHOR "Ali Saidi"
#define DRIVER_DESC "Interface to time uncacachable read and writes to device registers"
#define DRIVER_VER "0.1"
static char *dataAddr = NULL;
static int count = 0;
#ifdef __alpha__
static int memTest = 0;
#endif
static inline uint32_t cycleCounter(uint32_t dep);
static int __init devtime_start(void)
{
uint64_t addr;
uint32_t t1, t2;
uint32_t trash;
int x;
uint32_t *times;
uint32_t num = 0;
struct net_device *dev;
printk("Devtime Driver Version %s Loaded...\n", DRIVER_VER);
#ifdef __alpha__
if (memTest) {
addr = 0xfffffc0000000000;
// addr += 16*1024*1024;
printk("Preparing memory test.\n");
t1 = cycleCounter(trash);
for (x = 0; x < count; x++) {
trash = readl(addr);
t2 = cycleCounter(trash);
times[num++] = t2 - t1;
t1 = t2;
addr += 4096;
}
printk("Measurements:\n");
for (x = 0; x < count; x++) {
printk("%d ", times[x]);
if (((x + 1) % 10) == 0)
printk("\n");
}
printk("\nDone.\n");
} else
#endif
if (dataAddr != 0 && count != 0) {
addr = simple_strtoull(dataAddr, NULL, 0);
addr = ioremap(addr, PAGE_SIZE);
/**
* Make sure that the remapping actually worked. On alpha we have
* linear addressing, so its not a problem. But it can fail in x86
* if physical memory is mapped to this address.
*/
times = kmalloc(sizeof(uint32_t) * count, GFP_USER);
if (!times) {
printk("Could not allocate memory... Try again later.\n");
return -1;
}
if (addr) {
printk("Preparing to read %#llx %d times.\n", addr, count);
t1 = cycleCounter(trash);
for (x = 0; x < count; x++) {
trash = readl(addr);
t2 = cycleCounter(trash);
times[num++] = t2 - t1;
t1 = t2;
}
/**
* Unmap the address.
*/
iounmap(addr);
printk("Measurements:\n");
for (x = 0; x < count; x++) {
printk("%d ", times[x]);
if (((x + 1) % 10) == 0)
printk("\n");
}
printk("\nDone.\n");
} else {
printk("Unable to remap address. Please try again later.\n");
}
} else {
dev = dev_get_by_name("eth0");
if (dev) {
printk("Eth0: MemStart: %#lx MemEnd: %#lx I/O Addr: %#lx\n",
dev->mem_start, dev->mem_end, dev->base_addr);
dev_put(dev);
}
dev = 0;
dev = dev_get_by_name("eth1");
if (dev) {
printk("Eth1: MemStart: %#lx MemEnd: %#lx I/O Addr: %#lx\n",
dev->mem_start, dev->mem_end, dev->base_addr);
dev_put(dev);
}
printk("Required information not supplied.\n");
}
return 0;
}
#ifdef __i386__
static inline uint32_t cycleCounter(uint32_t dep)
{
uint32_t time;
cpuid_eax(0);
rdtscl(time);
cpuid_eax(0);
return time;
}
#elif __alpha__
inline uint32_t cycleCounter(uint32_t dep)
{
uint32_t res;
asm volatile ("rpcc %0, %1" : "=r"(res) : "r" (dep) : "memory");
return res;
}
#else
#error Architecture NOT SUPPORTED
#endif
static void __exit devtime_end(void)
{
printk("Devtime Driver Version %s Unloaded...\n", DRIVER_VER);
}
module_init(devtime_start);
module_exit(devtime_end);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
module_param(dataAddr, charp, 0);
module_param(count, int, 0);
#ifdef __alpha__
module_param(memTest, int, 0);
#endif

View File

@ -0,0 +1,18 @@
This driver will read the address you point it to [count] times and
print the results to the systemlog.
To build the driver (Linux 2.6.X only) execute:
make -C /path/to/linux-2.6.X/ SUBDIRS=$PWD modules
Insmodding the kernel module without options will print
the device addresses of eth0 and eth1 if they exist.
Insmodding the kernel module with the options:
dataAddr=0xXXXXXXXXX and count=XXXXX
will read a long at addr dataAddr count times and return.
Between runs you need to rmmod the module from the kernel.

View File

@ -0,0 +1,135 @@
#! /usr/bin/env python
# Copyright (c) 2010 Advanced Micro Devices, Inc.
# 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.
#
# Author: Steve Reinhardt
#
# Basic test script for checkpointing.
#
# Given an M5 command and an interval (in ticks), this script will:
# 1. Run the command, dumping periodic checkpoints at the given interval.
# 2. Rerun the command for each pair of adjacent checkpoints:
# a. Restore from checkpoint N
# b. Run until the timestamp of checkpoint N+1
# c. Dump a checkpoint and end the simulation
# d. Diff the new checkpoint with the original checkpoint N+1
#
# Note that '--' must be used to separate the script options from the
# M5 command line.
#
# Caveats:
#
# - This script relies on the checkpoint options implemented in
# configs/common/Simulation.py, so it works with commands based on
# the se.py and fs.py scripts in configs/example, but does not work
# directly with the existing regression tests.
# - Interleaving simulator and program output can cause discrepancies
# in the file position checkpoint information since different runs
# have different amount of simulator output.
# - Probably lots more issues we don't even know about yet.
#
# Examples:
#
# util/checkpoint-tester.py -i 400000 -- build/ALPHA_SE/m5.opt \
# configs/example/se.py -c tests/test-progs/hello/bin/alpha/tru64/hello \
# --output=progout --errout=progerr
#
# util/checkpoint-tester.py -i 200000000000 -- build/ALPHA_FS/m5.opt \
# configs/example/fs.py --script tests/halt.sh
#
import os, sys, re
import subprocess
import optparse
parser = optparse.OptionParser()
parser.add_option('-i', '--interval', type='int')
parser.add_option('-d', '--directory', default='checkpoint-test')
(options, args) = parser.parse_args()
interval = options.interval
if os.path.exists(options.directory):
print 'Error: test directory', options.directory, 'exists'
print ' Tester needs to create directory from scratch'
sys.exit(1)
top_dir = options.directory
os.mkdir(top_dir)
cmd_echo = open(os.path.join(top_dir, 'command'), 'w')
print >>cmd_echo, ' '.join(sys.argv)
cmd_echo.close()
m5_binary = args[0]
options = args[1:]
initial_args = ['--take-checkpoints', '%d,%d' % (interval, interval)]
cptdir = os.path.join(top_dir, 'm5out')
print '===> Running initial simulation.'
subprocess.call([m5_binary] + ['-red', cptdir] + options + initial_args)
dirs = os.listdir(cptdir)
expr = re.compile('cpt\.([0-9]*)')
cpts = []
for dir in dirs:
match = expr.match(dir)
if match:
cpts.append(int(match.group(1)))
cpts.sort()
# We test by loading checkpoint N, simulating to (and dumping at)
# checkpoint N+1, then comparing the resulting checkpoint with the
# original checkpoint N+1. Thus the number of tests we can run is one
# less than tha number of checkpoints.
for i in range(1, len(cpts)):
print '===> Running test %d of %d.' % (i, len(cpts)-1)
mydir = os.path.join(top_dir, 'test.%d' % i)
subprocess.call([m5_binary] + ['-red', mydir] + options + initial_args +
['--max-checkpoints' , '1', '--checkpoint-dir', cptdir,
'--checkpoint-restore', str(i)])
cpt_name = 'cpt.%d' % cpts[i]
diff_name = os.path.join(mydir, 'diffout')
diffout = open(diff_name, 'w')
subprocess.call(['diff', '-ru', '-I', '^##.*',
'%s/%s' % (cptdir, cpt_name),
'%s/%s' % (mydir, cpt_name)], stdout=diffout)
diffout.close()
# print out the diff
diffout = open(diff_name)
print diffout.read(),
diffout.close()

View File

@ -0,0 +1,182 @@
# Copyright (c) 2009 The Regents of The University of Michigan
# Copyright (c) 2011 Advanced Micro Devices, Inc.
# 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: Lisa Hsu
from ConfigParser import ConfigParser
import gzip
import sys, re, optparse, os
class myCP(ConfigParser):
def __init__(self):
ConfigParser.__init__(self)
def optionxform(self, optionstr):
return optionstr
def aggregate(options, args):
merged = myCP()
page_ptr = 0
allfiles = os.listdir(os.getcwd())
cpts = []
for arg in args:
found = False
for f in allfiles:
if re.compile("cpt." + arg + ".\d+").search(f):
found = True
cpts.append(f)
break
if not found:
print "missing checkpoint: ", arg
sys.exit(1)
dirname = "-".join([options.prefix, "cpt"])
agg_name = "-".join(args)
print agg_name
fullpath = os.path.join("..", dirname, "cpt." + agg_name + ".10000")
if not os.path.isdir(fullpath):
os.system("mkdir -p " + fullpath)
elif os.path.isfile(fullpath + "/system.physmem.physmem"):
if os.path.isfile(fullpath + "/m5.cpt"):
print fullpath, " already done"
return
myfile = open(fullpath + "/system.physmem.physmem", "wb+")
merged_mem = gzip.GzipFile(fileobj=myfile, mode="wb")
max_curtick = 0
when = 0
for (i, arg) in enumerate(args):
print arg
config = myCP()
config.readfp(open(cpts[i] + "/m5.cpt"))
for sec in config.sections():
if re.compile("cpu").search(sec):
newsec = re.sub("cpu", "cpu" + str(i), sec)
merged.add_section(newsec)
if re.compile("workload$").search(sec):
merged.set(newsec, "M5_pid", i)
items = config.items(sec)
if options.alpha:
for item in items:
if item[0] == "ppn":
if config.getint(sec, "tag") != 0:
merged.set(newsec, item[0], int(item[1]) + page_ptr)
continue
elif item[0] == "asn":
tmp = re.compile("(.*).Entry(\d+)").search(sec).groups()
if config.has_option(tmp[0], "nlu"):
size = config.getint(tmp[0], "nlu")
if int(tmp[1]) < size:
merged.set(newsec, item[0], i)
continue
else:
merged.set(newsec, item[0], i)
continue
merged.set(newsec, item[0], item[1])
else:a #x86
for item in items:
if item[0] == "paddr":
merged.set(newsec, item[0], int(item[1]) + (page_ptr << 12))
continue
merged.set(newsec, item[0], item[1])
elif sec == "system":
pass
elif sec == "Globals":
tick = config.getint(sec, "curTick")
if tick > max_curtick:
max_curtick = tick
when = config.getint("system.cpu.tickEvent", "_when")
else:
if i == 0:
merged.add_section(sec)
for item in config.items(sec):
merged.set(sec, item[0], item[1])
if item[0] == "curtick":
merged.optionxform(str("curTick"))
elif item[0] == "numevents":
merged.optionxform(str("numEvents"))
page_ptr = page_ptr + int(config.get("system", "pagePtr"))
### memory stuff
f = open(cpts[i] + "/system.physmem.physmem", "rb")
gf = gzip.GzipFile(fileobj=f, mode="rb")
pages = int(config.get("system", "pagePtr"))
print "pages to be read: ", pages
x = 0
while x < pages:
if options.alpha:
bytesRead = gf.read(1 << 13)
else: #x86
bytesRead = gf.read(1 << 12)
merged_mem.write(bytesRead)
x += 1
gf.close()
f.close()
merged.add_section("system")
merged.set("system", "pagePtr", page_ptr)
merged.set("system", "nextPID", len(args))
print "WARNING: "
print "Make sure the simulation using this checkpoint has at least ",
if options.alpha:
print page_ptr, "x 8K of memory"
else: # assume x86
print page_ptr, "x 4K of memory"
merged.add_section("Globals")
merged.set("Globals", "curTick", max_curtick)
for i in xrange(len(args)):
merged.set("system.cpu" + str(i) + ".tickEvent", "_when", when)
merged.write(file(fullpath + "/m5.cpt", "wb"))
merged_mem.close()
myfile.close()
if __name__ == "__main__":
parser = optparse.OptionParser()
parser.add_option("--prefix", type="string", default="agg")
# If not alpha, then assume x86. Any other ISAs would need
# extra stuff in this script to appropriately parse their page tables
# and understand page sizes.
parser.add_option("--alpha", action="store_true")
(options, args) = parser.parse_args()
aggregate(options, args)

View File

@ -0,0 +1,38 @@
# 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: Ali Saidi
for trace in */ethertrace
do
bad=`tethereal -r $trace -q -z "io,stat,100,tcp.analysis.retransmission||tcp.analysis.fast_retransmission||tcp.analysis.out_of_order||tcp.analysis.lost_segment||tcp.analysis.ack_lost_segment||tcp.analysis.window_full||tcp.analysis.duplicate_ack||tcp.analysis.duplicate_ack_num||tcp.analysis.duplicate_ack_frame" | grep 000.000 | awk '{print $2}'`
name=`dirname $trace`
if [ "$bad" != "0" ]
then
echo "Run $name had problems."
fi
done

168
simulators/gem5/util/chkformat Executable file
View File

@ -0,0 +1,168 @@
#!/usr/bin/env python
# Copyright (c) 2006 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
from getopt import getopt, GetoptError
import re
import sys
tabsize = 8
lead = re.compile(r'^([ \t])+')
trail = re.compile(r'[ \t]+$')
any_control = re.compile(r'\b(if|while|for)[ \t]*[(]')
good_control = re.compile(r'\b(if|while|for) [(]')
def linelen(line):
tabs = line.count('\t')
if not tabs:
return len(line)
count = 0
for c in line:
if c == '\t':
count += tabsize - count % tabsize
else:
count += 1
return count
toolong = 0
toolong80 = 0
leadtabs = 0
trailwhite = 0
badcontrol = 0
cret = 0
def validate(filename, verbose, code):
global toolong, toolong80, leadtabs, trailwhite, badcontrol, cret
def msg(lineno, line, message):
print '%s:%d>' % (filename, lineno + 1), message
if verbose > 2:
print line
def bad():
if code is not None:
sys.exit(code)
cpp = filename.endswith('.cc') or filename.endswith('.hh')
py = filename.endswith('.py')
if py + cpp != 1:
raise AttributeError, \
"I don't know how to deal with the file %s" % filename
try:
f = file(filename, 'r')
except OSError:
if verbose > 0:
print 'could not open file %s' % filename
bad()
return
for i,line in enumerate(f):
line = line.rstrip('\n')
# no carriage returns
if line.find('\r') != -1:
cret += 1
if verbose > 1:
msg(i, line, 'carriage return found')
bad()
# lines max out at 79 chars
llen = linelen(line)
if llen > 79:
toolong += 1
if llen == 80:
toolong80 += 1
if verbose > 1:
msg(i, line, 'line too long (%d chars)' % llen)
bad()
# no tabs used to indent
match = lead.search(line)
if match and match.group(1).find('\t') != -1:
leadtabs += 1
if verbose > 1:
msg(i, line, 'using tabs to indent')
bad()
# no trailing whitespace
if trail.search(line):
trailwhite +=1
if verbose > 1:
msg(i, line, 'trailing whitespace')
bad()
# for c++, exactly one space betwen if/while/for and (
if cpp:
match = any_control.search(line)
if match and not good_control.search(line):
badcontrol += 1
if verbose > 1:
msg(i, line, 'improper spacing after %s' % match.group(1))
bad()
if __name__ == '__main__':
progname = sys.argv[0]
def usage(code=None):
print >>sys.stderr, '''%s [-n] [-q] [-v] <filenames>''' % progname
if code is not None:
sys.exit(code)
try:
opts, args = getopt(sys.argv[1:], '-nv')
except GetoptError:
usage(2)
code = 1
verbose = 1
for opt,arg in opts:
if opt == '-n':
code = None
if opt == '-q':
verbose -= 1
if opt == '-v':
verbose += 1
for filename in args:
validate(filename, verbose=verbose, code=code)
if verbose > 0:
print '''\
%d violations of lines over 79 chars. %d of which are 80 chars exactly.
%d cases of whitespace at the end of a line.
%d cases of tabs to indent.
%d bad parens after if/while/for.
%d carriage returns found.
''' % (toolong, toolong80, trailwhite, leadtabs, badcontrol, cret)

323
simulators/gem5/util/compile Executable file
View File

@ -0,0 +1,323 @@
#!/usr/bin/env python
# Copyright (c) 2006 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
import os, re, sys
from os.path import isdir, isfile, join as joinpath
homedir = os.environ['HOME']
def do_compile():
#
# Find SCons
#
search_dirs = [ joinpath(homedir, 'local/lib'), '/opt/local/lib',
'/usr/local/lib', '/usr/lib' ]
if os.environ.has_key("SCONS_LIB_DIR"):
search_dirs.append(os.environ["SCONS_LIB_DIR"])
local = re.compile(r'^scons-local-([0-9]*)\.([0-9]*)\.([0-9]*)$')
standard = re.compile(r'^scons-([0-9]*)\.([0-9]*)\.([0-9]*)$')
scons_dirs = []
for dir in search_dirs:
if not isdir(dir):
continue
entries = os.listdir(dir)
for entry in entries:
if not entry.startswith('scons'):
continue
version = (0,0,0)
path = joinpath(dir, entry)
match = local.search(entry)
if not match:
match = standard.search(entry)
if match:
version = match.group(1), match.group(2), match.group(3)
scons_dirs.append((version, path))
scons_dirs.sort()
scons_dirs.reverse()
if not scons_dirs:
print >>sys.stderr, \
"could not find scons in the following dirs: %s" % search_dirs
sys.exit(1)
sys.path = [ scons_dirs[0][1] ] + sys.path
# invoke SCons
import SCons.Script
SCons.Script.main()
#
# do argument parsing
#
progname = sys.argv[0]
import optparse
usage = '''%prog [compile options] <version> [SCons options]
%prog assumes that the user has a directory called ~/m5/<version> where
the source tree resides, and a directory called ~/build, where %prog
will create ~/build/<version> if it does not exist and build the resulting
simulators there.
If ~/build is set up in such a way that it points to a local disk on
each host, compiles will be very efficient. For example:
~/build -> /z/<username>/.build (Assuming that /z is a local disk and
not NFS mounted, whereas your home directory is NFS mounted).
'''
version = '%prog 0.1'
parser = optparse.OptionParser(usage=usage, version=version,
formatter=optparse.TitledHelpFormatter())
parser.disable_interspersed_args()
# current option group
group = None
def set_group(*args, **kwargs):
'''set the current option group'''
global group
if not args and not kwargs:
group = None
else:
group = parser.add_option_group(*args, **kwargs)
def add_option(*args, **kwargs):
if group:
return group.add_option(*args, **kwargs)
else:
return parser.add_option(*args, **kwargs)
def bool_option(name, default, help):
'''add a boolean option called --name and --no-name.
Display help depending on which is the default'''
tname = '--%s' % name
fname = '--no-%s' % name
dest = name.replace('-', '_')
if default:
thelp = optparse.SUPPRESS_HELP
fhelp = help
else:
thelp = help
fhelp = optparse.SUPPRESS_HELP
add_option(tname, action="store_true", default=default, help=thelp)
add_option(fname, action="store_false", dest=dest, help=fhelp)
add_option('-n', '--no-compile', default=False, action='store_true',
help="don't actually compile, just echo SCons command line")
add_option('--everything', default=False, action='store_true',
help="compile everything that can be compiled")
add_option('-E', "--experimental", action='store_true', default=False,
help="enable experimental builds")
add_option('-v', "--verbose", default=False, action='store_true',
help="be verbose")
set_group("Output binary types")
bool_option("debug", default=False, help="compile debug binaries")
bool_option("opt", default=False, help="compile opt binaries")
bool_option("fast", default=False, help="compile fast binaries")
bool_option("prof", default=False, help="compile profile binaries")
add_option('-a', "--all-bin", default=False, action='store_true',
help="compile debug, opt, and fast binaries")
set_group("ISA options")
bool_option("alpha", default=False, help="compile Alpha")
bool_option("mips", default=False, help="compile MIPS")
bool_option("sparc", default=False, help="compile SPARC")
add_option('-i', "--all-isa", default=False, action='store_true',
help="compile all ISAs")
set_group("Emulation options")
bool_option("syscall", default=True,
help="Do not compile System Call Emulation mode")
bool_option("fullsys", default=True,
help="Do not compile Full System mode")
def usage(exitcode=None):
parser.print_help()
if exitcode is not None:
sys.exit(exitcode)
(options, args) = parser.parse_args()
if options.everything:
options.all_bin = True
options.prof = True
options.all_isa = True
if options.all_bin:
options.debug = True
options.opt = True
options.fast = True
binaries = []
if options.debug:
binaries.append('m5.debug')
if options.opt:
binaries.append('m5.opt')
if options.fast:
binaries.append('m5.fast')
if options.prof:
binaries.append('m5.prof')
if not binaries:
binaries.append('m5.debug')
if options.all_isa:
options.alpha = True
options.mips = True
options.sparc = True
isas = []
if options.alpha:
isas.append('alpha')
if options.mips:
isas.append('mips')
if options.sparc:
isas.append('sparc')
if not isas:
isas.append('alpha')
modes = []
if options.syscall:
modes.append('syscall')
if options.fullsys:
modes.append('fullsys')
if not modes:
sys.exit("must specify at least one mode")
#
# Convert options into SCons command line arguments
#
# valid combinations of ISA and emulation mode
valid = { ('alpha', 'syscall') : 'ALPHA_SE',
('alpha', 'fullsys') : 'ALPHA_FS',
('mips', 'syscall') : 'MIPS_SE',
('sparc', 'syscall') : 'SPARC_SE' }
# experimental combinations of ISA and emulation mode
experiment = { ('mips', 'fullsys') : 'MIPS_FS',
('sparc', 'fullsys') : 'SPARC_FS' }
if options.experimental:
valid.update(experiment)
builds = []
for isa in isas:
for mode in modes:
try:
build = valid[(isa, mode)]
builds.append(build)
except KeyError:
pass
if not builds:
sys.exit("must specify at least one valid combination of ISA and mode")
if not args:
usage(2)
version = args[0]
del args[0]
for bin in binaries:
for build in builds:
args.append('%s/%s' % (build, bin))
#
# set up compile
#
build_base = joinpath(homedir, 'build')
m5_base = joinpath(homedir, 'm5')
if not isdir(build_base):
sys.exit('build directory %s not found' % build_base)
if not isdir(m5_base):
sys.exit('m5 base directory %s not found' % m5_base)
m5_dir = joinpath(m5_base, version)
if not isdir(m5_dir):
sys.exit('source directory %s not found' % m5_dir)
# support M5 1.x
oldstyle = isfile(joinpath(m5_dir, 'SConscript'))
if oldstyle:
ext_dir = joinpath(m5_base, 'ext')
test_dir = joinpath(m5_base, 'test.' + version)
if not isdir(ext_dir):
sys.exit('ext directory not found at %s' % ext_dir)
if not isdir(test_dir):
sys.exit('test directory not found at %s' % test_dir)
build_dir = joinpath(build_base, version)
if not isdir(build_dir):
os.mkdir(build_dir)
# need some symlinks for m5 1.x
if oldstyle:
os.symlink(m5_dir, joinpath(build_dir, 'm5'))
os.symlink(ext_dir, joinpath(build_dir, 'ext'))
os.symlink(test_dir, joinpath(build_dir, 'test'))
os.symlink(joinpath(m5_dir, 'build', 'SConstruct'),
joinpath(build_dir, 'SConstruct'))
os.symlink(joinpath(m5_dir, 'build', 'default_options'),
joinpath(build_dir, 'default_options'))
sys.argv = [ progname ]
if oldstyle:
os.chdir(build_dir)
sys.argv.extend(args)
else:
os.chdir(m5_dir)
for arg in args:
if not arg.startswith('-') and '=' not in arg:
arg = joinpath(build_dir, 'build', arg)
sys.argv.append(arg)
if options.no_compile or options.verbose:
for arg in sys.argv[1:]:
print arg
if not options.no_compile:
do_compile()

View File

@ -0,0 +1,186 @@
#!/usr/bin/env python
# Copyright (c) 2012 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# 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: Ali Saidi
#
# This python code is used to migrate checkpoints that were created in one
# version of the simulator to newer version. As features are added or bugs are
# fixed some of the state that needs to be checkpointed can change. If you have
# many historic checkpoints that you use, manually editing them to fix them is
# both time consuming and error-prone.
# This script provides a way to migrate checkpoints to the newer repository in
# a programatic way. It can be imported into another script or used on the
# command line. From the command line the script will either migrate every
# checkpoint it finds recursively (-r option) or a single checkpoint. When a
# change is made to the gem5 repository that breaks previous checkpoints a
# from_N() method should be implemented here and the gem5CheckpointVersion
# variable in src/sim/serialize.hh should be incremented. For each version
# between the checkpoints current version and the new version the from_N()
# method will be run, passing in a ConfigParser object which contains the open
# file. As these operations can be isa specific the method can verify the isa
# and use regexes to find the correct sections that need to be updated.
import ConfigParser
import sys, os
import os.path as osp
def from_0(cpt):
pass
# An example of a translator
def from_1(cpt):
if cpt.get('root','isa') == 'arm':
for sec in cpt.sections():
import re
# Search for all the execution contexts
if re.search('.*sys.*\.cpu.*\.x.\..*', sec):
# Update each one
mr = cpt.get(sec, 'miscRegs').split()
#mr.insert(21,0)
#mr.insert(26,0)
cpt.set(sec, 'miscRegs', ' '.join(str(x) for x in mr))
migrations = []
migrations.append(from_0)
migrations.append(from_1)
verbose_print = False
def verboseprint(*args):
if not verbose_print:
return
for arg in args:
print arg,
print
def process_file(path, **kwargs):
if not osp.isfile(path):
import errno
raise IOError(ennro.ENOENT, "No such file", path)
verboseprint("Processing file %s...." % path)
if kwargs.get('backup', True):
import shutil
shutil.copyfile(path, path + '.bak')
cpt = ConfigParser.SafeConfigParser()
# gem5 is case sensitive with paramaters
cpt.optionxform = str
# Read the current data
cpt_file = file(path, 'r')
cpt.readfp(cpt_file)
cpt_file.close()
# Make sure we know what we're starting from
if not cpt.has_option('root','cpt_ver'):
raise LookupError("cannot determine version of checkpoint")
cpt_ver = cpt.getint('root','cpt_ver')
# If the current checkpoint is longer than the migrations list, we have a problem
# and someone didn't update this file
if cpt_ver > len(migrations):
raise ValueError("upgrade script is too old and needs updating")
verboseprint("\t...file is at version %#x" % cpt_ver)
if cpt_ver == len(migrations):
verboseprint("\t...nothing to do")
return
# Walk through every function from now until the end fixing the checkpoint
for v in xrange(cpt_ver,len(migrations)):
verboseprint("\t...migrating to version %#x" % (v + 1))
migrations[v](cpt)
cpt.set('root','cpt_ver', str(v + 1))
# Write the old data back
verboseprint("\t...completed")
cpt.write(file(path, 'w'))
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser("usage: %prog [options] <filename or directory>")
parser.add_option("-r", "--recurse", action="store_true",
help="Recurse through all subdirectories modifying "\
"each checkpoint that is found")
parser.add_option("-N", "--no-backup", action="store_false",
dest="backup", default=True,
help="Do no backup each checkpoint before modifying it")
parser.add_option("-v", "--verbose", action="store_true",
help="Print out debugging information as")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.error("You must specify a checkpoint file to modify or a "\
"directory of checkpoints to recursively update")
verbose_print = options.verbose
# Deal with shell variables and ~
path = osp.expandvars(osp.expanduser(args[0]))
# Process a single file if we have it
if osp.isfile(path):
process_file(path, **vars(options))
# Process an entire directory
elif osp.isdir(path):
cpt_file = osp.join(path, 'm5.cpt')
if options.recurse:
# Visit very file and see if it matches
for root,dirs,files in os.walk(path):
for name in files:
if name == 'm5.cpt':
process_file(osp.join(root,name), **vars(options))
for dir in dirs:
pass
# Maybe someone passed a cpt.XXXXXXX directory and not m5.cpt
elif osp.isfile(cpt_file):
process_file(cpt_file, **vars(options))
else:
print "Error: checkpoint file not found at in %s " % path,
print "and recurse not specified"
sys.exit(1)
sys.exit(0)

View File

@ -0,0 +1,71 @@
#! /usr/bin/python
# Copyright (c) 2006 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: Steve Reinhardt
# Generate list of files to index with cscope and then generate cscope index.
# Should be run from root of m5 tree (i.e. as 'util/cscope-index.py').
import os
# absolute paths to skip
skipdirs = [ 'src/unittest', 'src/doxygen' ]
# suffixes of files to index
suffixes = [ '.cc', '.hh', '.c', '.h' ]
def oksuffix(f):
for s in suffixes:
if f.endswith(s):
return True
return False
file_list = file('cscope.files', 'w')
for dirpath,subdirs,files in os.walk('src'):
# filter out undesirable subdirectories
for i,dir in enumerate(subdirs):
if dir == 'SCCS':
del subdirs[i]
break
# filter out undesirable absolute paths
if dirpath in skipdirs:
del subdirs[:]
continue
# find C/C++ sources
okfiles = [f for f in files if oksuffix(f)]
if okfiles:
print >> file_list, \
'\n'.join([os.path.join(dirpath, f) for f in okfiles])
file_list.close()
# run cscope to generate index
os.system("cscope -b")

View File

@ -0,0 +1,41 @@
; Copyright (c) 2003-2004, 2006 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
(c-add-style "m5"
'((c-basic-offset . 4)
(indent-tabs-mode . nil)
(c-offsets-alist . ((substatement-open . 0)
(inline-open . 0)
(block-open . -4)
(case-label . 2)
(label . 2)
(statement-case-intro . 2)
(statement-case-open . 2)
(access-label . -2)
(innamespace . 0)))))

View File

@ -0,0 +1,174 @@
import os
# lanuage type for each file extension
lang_types = {
'.c' : "C",
'.h' : "C",
'.cc' : "C++",
'.hh' : "C++",
'.cxx' : "C++",
'.hxx' : "C++",
'.cpp' : "C++",
'.hpp' : "C++",
'.C' : "C++",
'.H' : "C++",
'.i' : "swig",
'.py' : "python",
'.pl' : "perl",
'.pm' : "perl",
'.s' : "asm",
'.S' : "asm",
'.l' : "lex",
'.ll' : "lex",
'.y' : "yacc",
'.yy' : "yacc",
'.isa' : "isa",
'.sh' : "shell",
'.slicc' : "slicc",
'.sm' : "slicc",
'.awk' : "awk",
'.el' : "lisp",
'.txt' : "text",
'.tex' : "tex",
}
# languages based on file prefix
lang_prefixes = (
('SCons', 'scons'),
('Make', 'make'),
('make', 'make'),
('Doxyfile', 'doxygen'),
)
# languages based on #! line of first file
hash_bang = (
('python', 'python'),
('perl', 'perl'),
('sh', 'shell'),
)
# the list of all languages that we detect
all_languages = frozenset(lang_types.itervalues())
all_languages |= frozenset(lang for start,lang in lang_prefixes)
all_languages |= frozenset(lang for start,lang in hash_bang)
def lang_type(filename, firstline=None, openok=True):
'''identify the language of a given filename and potentially the
firstline of the file. If the firstline of the file is not
provided and openok is True, open the file and read the first line
if necessary'''
basename = os.path.basename(filename)
name,extension = os.path.splitext(basename)
# first try to detect language based on file extension
try:
return lang_types[extension]
except KeyError:
pass
# now try to detect language based on file prefix
for start,lang in lang_prefixes:
if basename.startswith(start):
return lang
# if a first line was not provided but the file is ok to open,
# grab the first line of the file.
if firstline is None and openok:
handle = file(filename, 'r')
firstline = handle.readline()
handle.close()
# try to detect language based on #! in first line
if firstline and firstline.startswith('#!'):
for string,lang in hash_bang:
if firstline.find(string) > 0:
return lang
# sorry, we couldn't detect the language
return None
# directories and files to ignore by default
default_dir_ignore = frozenset(('.hg', '.svn', 'build', 'ext'))
default_file_ignore = frozenset(('parsetab.py', ))
def find_files(base, languages=all_languages,
dir_ignore=default_dir_ignore,
file_ignore=default_file_ignore):
'''find all files in a directory and its subdirectories based on a
set of languages, ignore directories specified in dir_ignore and
files specified in file_ignore'''
if base[-1] != '/':
base += '/'
def update_dirs(dirs):
'''strip the ignored directories out of the provided list'''
index = len(dirs) - 1
for i,d in enumerate(reversed(dirs)):
if d in dir_ignore:
del dirs[index - i]
# walk over base
for root,dirs,files in os.walk(base):
root = root.replace(base, '', 1)
# strip ignored directories from the list
update_dirs(dirs)
for filename in files:
if filename in file_ignore:
# skip ignored files
continue
# try to figure out the language of the specified file
fullpath = os.path.join(base, root, filename)
language = lang_type(fullpath)
# if the file is one of the langauges that we want return
# its name and the language
if language in languages:
yield fullpath, language
def update_file(dst, src, language, mutator):
'''update a file of the specified language with the provided
mutator generator. If inplace is provided, update the file in
place and return the handle to the updated file. If inplace is
false, write the updated file to cStringIO'''
# if the source and destination are the same, we're updating in place
inplace = dst == src
if isinstance(src, str):
# if a filename was provided, open the file
if inplace:
mode = 'r+'
else:
mode = 'r'
src = file(src, mode)
orig_lines = []
# grab all of the lines of the file and strip them of their line ending
old_lines = list(line.rstrip('\r\n') for line in src.xreadlines())
new_lines = list(mutator(old_lines, src.name, language))
for line in src.xreadlines():
line = line
if inplace:
# if we're updating in place and the file hasn't changed, do nothing
if old_lines == new_lines:
return
# otherwise, truncate the file and seek to the beginning.
dst = src
dst.truncate(0)
dst.seek(0)
elif isinstance(dst, str):
# if we're not updating in place and a destination file name
# was provided, create a file object
dst = file(dst, 'w')
for line in new_lines:
dst.write(line)
dst.write('\n')

View File

@ -0,0 +1,273 @@
#!/usr/bin/env python
import os
import re
import sys
from file_types import lang_type, find_files
mode_line = re.compile('(-\*- *mode:.* *-\*-)')
shell_comment = re.compile(r'^\s*#')
lisp_comment = re.compile(r';')
cpp_comment = re.compile(r'//')
c_comment_start = re.compile(r'/\*')
c_comment_end = re.compile(r'\*/')
def find_copyright_block(lines, lang_type):
start = None
if lang_type in ('python', 'make', 'shell', 'perl', 'scons'):
for i,line in enumerate(lines):
if i == 0 and (line.startswith('#!') or mode_line.search(line)):
continue
if shell_comment.search(line):
if start is None:
start = i
elif start is None:
if line.strip():
return
else:
yield start, i-1
start = None
elif lang_type in ('lisp', ):
for i,line in enumerate(lines):
if i == 0 and mode_line.search(line):
continue
if lisp_comment.search(line):
if start is None:
start = i
elif start is None:
if line.strip():
return
else:
yield start, i-1
start = None
elif lang_type in ('C', 'C++', 'swig', 'isa', 'asm', 'slicc',
'lex', 'yacc'):
mode = None
for i,line in enumerate(lines):
if i == 0 and mode_line.search(line):
continue
if mode == 'C':
assert start is not None, 'on line %d' % (i + 1)
match = c_comment_end.search(line)
if match:
yield start, i
mode = None
continue
cpp_match = cpp_comment.search(line)
c_match = c_comment_start.search(line)
if cpp_match:
assert not c_match, 'on line %d' % (i + 1)
if line[:cpp_match.start()].strip():
return
if mode is None:
mode = 'CPP'
start = i
else:
text = line[cpp_match.end():].lstrip()
if text.startswith("Copyright") > 0:
yield start, i-1
start = i
continue
elif mode == 'CPP':
assert start is not None, 'on line %d' % (i + 1)
if not line.strip():
continue
yield start, i-1
mode = None
if not c_match:
return
if c_match:
assert mode is None, 'on line %d' % (i + 1)
mode = 'C'
start = i
if mode is None and line.strip():
return
else:
raise AttributeError, "Could not handle language %s" % lang_type
date_range_re = re.compile(r'([0-9]{4})\s*-\s*([0-9]{4})')
def process_dates(dates):
dates = [ d.strip() for d in dates.split(',') ]
output = set()
for date in dates:
match = date_range_re.match(date)
if match:
f,l = [ int(d) for d in match.groups() ]
for i in xrange(f, l+1):
output.add(i)
else:
try:
date = int(date)
output.add(date)
except ValueError:
pass
return output
copyright_re = \
re.compile(r'Copyright (\([cC]\)) ([-, 0-9]+)[\s*#/]*([A-z-,. ]+)',
re.DOTALL)
authors_re = re.compile(r'^[\s*#/]*Authors:\s*([A-z .]+)\s*$')
more_authors_re = re.compile(r'^[\s*#/]*([A-z .]+)\s*$')
all_owners = set()
def get_data(lang_type, lines):
data = []
last = None
for start,end in find_copyright_block(lines, lang_type):
joined = ''.join(lines[start:end+1])
match = copyright_re.search(joined)
if not match:
continue
c,dates,owner = match.groups()
dates = dates.strip()
owner = owner.strip()
all_owners.add(owner)
try:
dates = process_dates(dates)
except Exception:
print dates
print owner
raise
authors = []
for i in xrange(start,end+1):
line = lines[i]
if not authors:
match = authors_re.search(line)
if match:
authors.append(match.group(1).strip())
else:
match = more_authors_re.search(line)
if not match:
for j in xrange(i, end+1):
line = lines[j].strip()
if not line:
end = j
break
if line.startswith('//'):
line = line[2:].lstrip()
if line:
end = j - 1
break
break
authors.append(match.group(1).strip())
info = (owner, dates, authors, start, end)
data.append(info)
return data
def datestr(dates):
dates = list(dates)
dates.sort()
output = []
def add_output(first, second):
if first == second:
output.append('%d' % (first))
else:
output.append('%d-%d' % (first, second))
first = dates.pop(0)
second = first
while dates:
next = dates.pop(0)
if next == second + 1:
second = next
else:
add_output(first, second)
first = next
second = next
add_output(first, second)
return ','.join(output)
usage_str = """usage:
%s [-v] <directory>"""
def usage(exitcode):
print usage_str % sys.argv[0]
if exitcode is not None:
sys.exit(exitcode)
if __name__ == '__main__':
import getopt
show_counts = False
ignore = set()
verbose = False
try:
opts, args = getopt.getopt(sys.argv[1:], "ci:v")
except getopt.GetoptError:
usage(1)
for o,a in opts:
if o == '-c':
show_counts = True
if o == '-i':
ignore.add(a)
if o == '-v':
verbose = True
files = []
for base in args:
if os.path.isfile(base):
files += [ (base, lang_type(base)) ]
elif os.path.isdir(base):
files += find_files(base)
else:
raise AttributeError, "can't access '%s'" % base
copyrights = {}
counts = {}
for filename, lang in files:
f = file(filename, 'r')
lines = f.readlines()
if not lines:
continue
lines = [ line.rstrip('\r\n') for line in lines ]
lt = lang_type(filename, lines[0])
try:
data = get_data(lt, lines)
except Exception, e:
if verbose:
if len(e.args) == 1:
e.args = ('%s (%s))' % (e, filename), )
print "could not parse %s: %s" % (filename, e)
continue
for owner, dates, authors, start, end in data:
if owner not in copyrights:
copyrights[owner] = set()
if owner not in counts:
counts[owner] = 0
copyrights[owner] |= dates
counts[owner] += 1
info = [ (counts[o], d, o) for o,d in copyrights.items() ]
for count,dates,owner in sorted(info, reverse=True):
if show_counts:
owner = '%s (%s files)' % (owner, count)
print 'Copyright (c) %s %s' % (datestr(dates), owner)

83
simulators/gem5/util/fixwhite Executable file
View File

@ -0,0 +1,83 @@
#! /usr/bin/env python
# Copyright (c) 2006 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
import re
import os
import sys
from getopt import getopt, GetoptError
tabs = re.compile(r'^[ \t]+')
def fixwhite(filename, tabsize):
try:
f = file(filename, 'r+')
except OSError, msg:
print 'could not open file %s: %s' % (filename, msg)
return
lines = list(f)
f.seek(0)
f.truncate()
for line in lines:
if tabs.search(line):
newline = ''
for i,c in enumerate(line):
if c == ' ':
newline += ' '
elif c == '\t':
newline += ' ' * (tabsize - len(newline) % tabsize)
else:
newline += line[i:]
break
line = newline
print >>f, line.rstrip()
if __name__ == '__main__':
progname = sys.argv[0]
def usage(code=None):
print >>sys.stderr, '''%s [-t <tabsize>] <filenames>''' % progname
if code is not None:
sys.exit(code)
try:
opts, args = getopt(sys.argv[1:], '-t:')
except GetoptError:
usage(2)
tabsize = 8
for opt,arg in opts:
if opt == '-t':
tabsize = int(arg)
for filename in args:
fixwhite(filename, tabsize)

372
simulators/gem5/util/gem5img.py Executable file
View File

@ -0,0 +1,372 @@
#!/usr/bin/python
#
# gem5img.py
# Script for managing a gem5 disk image.
#
from optparse import OptionParser
import os
from os import environ as env
import string
from subprocess import CalledProcessError, Popen, PIPE, STDOUT
from sys import exit, argv
# Some constants.
MaxLBACylinders = 16383
MaxLBAHeads = 16
MaxLBASectors = 63
MaxLBABlocks = MaxLBACylinders * MaxLBAHeads * MaxLBASectors
BlockSize = 512
MB = 1024 * 1024
# Setup PATH to look in the sbins.
env['PATH'] += ':/sbin:/usr/sbin'
# Whether to print debug output.
debug = False
# Figure out cylinders, heads and sectors from a size in blocks.
def chsFromSize(sizeInBlocks):
if sizeInBlocks >= MaxLBABlocks:
sizeInMBs = (sizeInBlocks * BlockSize) / MB
print '%d MB is too big for LBA, truncating file.' % sizeInMBs
return (MaxLBACylinders, MaxLBAHeads, MaxLBASectors)
sectors = sizeInBlocks
if sizeInBlocks > 63:
sectors = 63
headSize = sizeInBlocks / sectors
heads = 16
if headSize < 16:
heads = sizeInBlocks
cylinders = sizeInBlocks / (sectors * heads)
return (cylinders, heads, sectors)
# Figure out if we should use sudo.
def needSudo():
if not hasattr(needSudo, 'notRoot'):
needSudo.notRoot = (os.geteuid() != 0)
if needSudo.notRoot:
print 'You are not root. Using sudo.'
return needSudo.notRoot
# Run an external command.
def runCommand(command, inputVal=''):
print "%>", ' '.join(command)
proc = Popen(command, stdin=PIPE)
proc.communicate(inputVal)
return proc.returncode
# Run an external command and capture its output. This is intended to be
# used with non-interactive commands where the output is for internal use.
def getOutput(command, inputVal=''):
global debug
if debug:
print "%>", ' '.join(command)
proc = Popen(command, stderr=STDOUT,
stdin=PIPE, stdout=PIPE)
(out, err) = proc.communicate(inputVal)
return (out, proc.returncode)
# Run a command as root, using sudo if necessary.
def runPriv(command, inputVal=''):
realCommand = command
if needSudo():
realCommand = [findProg('sudo')] + command
return runCommand(realCommand, inputVal)
def privOutput(command, inputVal=''):
realCommand = command
if needSudo():
realCommand = [findProg('sudo')] + command
return getOutput(realCommand, inputVal)
# Find the path to a program.
def findProg(program, cleanupDev=None):
(out, returncode) = getOutput(['which', program])
if returncode != 0:
if cleanupDev:
cleanupDev.destroy()
exit("Unable to find program %s, check your PATH variable." % program)
return string.strip(out)
class LoopbackDevice(object):
def __init__(self, devFile=None):
self.devFile = devFile
def __str__(self):
return str(self.devFile)
def setup(self, fileName, offset=False):
assert not self.devFile
(out, returncode) = privOutput([findProg('losetup'), '-f'])
if returncode != 0:
print out
return returncode
self.devFile = string.strip(out)
command = [findProg('losetup'), self.devFile, fileName]
if offset:
off = findPartOffset(self.devFile, fileName, 0)
command = command[:1] + \
["-o", "%d" % off] + \
command[1:]
return runPriv(command)
def destroy(self):
assert self.devFile
returncode = runPriv([findProg('losetup'), '-d', self.devFile])
self.devFile = None
return returncode
def findPartOffset(devFile, fileName, partition):
# Attach a loopback device to the file so we can use sfdisk on it.
dev = LoopbackDevice()
dev.setup(fileName)
# Dump the partition information.
command = [findProg('sfdisk'), '-d', dev.devFile]
(out, returncode) = privOutput(command)
if returncode != 0:
print out
exit(returncode)
lines = out.splitlines()
# Make sure the first few lines of the output look like what we expect.
assert(lines[0][0] == '#')
assert(lines[1] == 'unit: sectors')
assert(lines[2] == '')
# This line has information about the first partition.
chunks = lines[3].split()
# The fourth chunk is the offset of the partition in sectors followed by
# a comma. We drop the comma and convert that to an integer.
sectors = string.atoi(chunks[3][:-1])
# Free the loopback device and return an answer.
dev.destroy()
return sectors * BlockSize
def mountPointToDev(mountPoint):
(mountTable, returncode) = getOutput([findProg('mount')])
if returncode != 0:
print mountTable
exit(returncode)
mountTable = mountTable.splitlines()
for line in mountTable:
chunks = line.split()
if os.path.samefile(chunks[2], mountPoint):
return LoopbackDevice(chunks[0])
return None
# Commands for the gem5img.py script
commands = {}
commandOrder = []
class Command(object):
def addOption(self, *args, **kargs):
self.parser.add_option(*args, **kargs)
def __init__(self, name, description, posArgs):
self.name = name
self.description = description
self.func = None
self.posArgs = posArgs
commands[self.name] = self
commandOrder.append(self.name)
usage = 'usage: %prog [options]'
posUsage = ''
for posArg in posArgs:
(argName, argDesc) = posArg
usage += ' %s' % argName
posUsage += '\n %s: %s' % posArg
usage += posUsage
self.parser = OptionParser(usage=usage, description=description)
self.addOption('-d', '--debug', dest='debug', action='store_true',
help='Verbose output.')
def parseArgs(self, argv):
(self.options, self.args) = self.parser.parse_args(argv[2:])
if len(self.args) != len(self.posArgs):
self.parser.error('Incorrect number of arguments')
global debug
if self.options.debug:
debug = True
def runCom(self):
if not self.func:
exit('Unimplemented command %s!' % self.name)
self.func(self.options, self.args)
# A command which prepares an image with an partition table and an empty file
# system.
initCom = Command('init', 'Create an image with an empty file system.',
[('file', 'Name of the image file.'),
('mb', 'Size of the file in MB.')])
initCom.addOption('-t', '--type', dest='fstype', action='store',
default='ext2',
help='Type of file system to use. Appended to mkfs.')
# A command to mount the first partition in the image.
mountCom = Command('mount', 'Mount the first partition in the disk image.',
[('file', 'Name of the image file.'),
('mount point', 'Where to mount the image.')])
def mountComFunc(options, args):
(path, mountPoint) = args
if not os.path.isdir(mountPoint):
print "Mount point %s is not a directory." % mountPoint
dev = LoopbackDevice()
if dev.setup(path, offset=True) != 0:
exit(1)
if runPriv([findProg('mount'), str(dev), mountPoint]) != 0:
dev.destroy()
exit(1)
mountCom.func = mountComFunc
# A command to unmount the first partition in the image.
umountCom = Command('umount', 'Unmount the first partition in the disk image.',
[('mount point', 'What mount point to unmount.')])
def umountComFunc(options, args):
(mountPoint,) = args
if not os.path.isdir(mountPoint):
print "Mount point %s is not a directory." % mountPoint
exit(1)
dev = mountPointToDev(mountPoint)
if not dev:
print "Unable to find mount information for %s." % mountPoint
# Unmount the loopback device.
if runPriv([findProg('umount'), mountPoint]) != 0:
exit(1)
# Destroy the loopback device.
dev.destroy()
umountCom.func = umountComFunc
# A command to create an empty file to hold the image.
newCom = Command('new', 'File creation part of "init".',
[('file', 'Name of the image file.'),
('mb', 'Size of the file in MB.')])
def newImage(file, mb):
(cylinders, heads, sectors) = chsFromSize((mb * MB) / BlockSize)
size = cylinders * heads * sectors * BlockSize
# We lseek to the end of the file and only write one byte there. This
# leaves a "hole" which many file systems are smart enough not to actually
# store to disk and which is defined to read as zero.
fd = os.open(file, os.O_WRONLY | os.O_CREAT)
os.lseek(fd, size - 1, os.SEEK_SET)
os.write(fd, '\0')
def newComFunc(options, args):
(file, mb) = args
mb = string.atoi(mb)
newImage(file, mb)
newCom.func = newComFunc
# A command to partition the image file like a raw disk device.
partitionCom = Command('partition', 'Partition part of "init".',
[('file', 'Name of the image file.')])
def partition(dev, cylinders, heads, sectors):
# Use fdisk to partition the device
comStr = '0,\n;\n;\n;\n'
return runPriv([findProg('sfdisk'), '--no-reread', '-D', \
'-C', "%d" % cylinders, \
'-H', "%d" % heads, \
'-S', "%d" % sectors, \
str(dev)], inputVal=comStr)
def partitionComFunc(options, args):
(path,) = args
dev = LoopbackDevice()
if dev.setup(path) != 0:
exit(1)
# Figure out the dimensions of the file.
size = os.path.getsize(path)
if partition(dev, *chsFromSize(size / BlockSize)) != 0:
dev.destroy()
exit(1)
dev.destroy()
partitionCom.func = partitionComFunc
# A command to format the first partition in the image.
formatCom = Command('format', 'Formatting part of "init".',
[('file', 'Name of the image file.')])
formatCom.addOption('-t', '--type', dest='fstype', action='store',
default='ext2',
help='Type of file system to use. Appended to mkfs.')
def formatImage(dev, fsType):
return runPriv([findProg('mkfs.%s' % fsType, dev), str(dev)])
def formatComFunc(options, args):
(path,) = args
dev = LoopbackDevice()
if dev.setup(path, offset=True) != 0:
exit(1)
# Format the device.
if formatImage(dev, options.fstype) != 0:
dev.destroy()
exit(1)
dev.destroy()
formatCom.func = formatComFunc
def initComFunc(options, args):
(path, mb) = args
mb = string.atoi(mb)
newImage(path, mb)
dev = LoopbackDevice()
if dev.setup(path) != 0:
exit(1)
size = os.path.getsize(path)
if partition(dev, *chsFromSize((mb * MB) / BlockSize)) != 0:
dev.destroy()
exit(1)
dev.destroy()
if dev.setup(path, offset=True) != 0:
exit(1)
if formatImage(dev, options.fstype) != 0:
dev.destroy()
exit(1)
dev.destroy()
initCom.func = initComFunc
# Figure out what command was requested and execute it.
if len(argv) < 2 or argv[1] not in commands:
print 'Usage: %s [command] <command arguments>'
print 'where [command] is one of '
for name in commandOrder:
command = commands[name]
print ' %s: %s' % (command.name, command.description)
print 'Watch for orphaned loopback devices and delete them with'
print 'losetup -d. Mounted images will belong to root, so you may need'
print 'to use sudo to modify their contents.'
exit(1)
command = commands[argv[1]]
command.parseArgs(argv)
command.runCom()

View File

@ -0,0 +1,34 @@
from mercurial import context
from mercurial.i18n import _
'''
[extensions]
hgfilesize=~/m5/incoming/util/hgfilesize.py
[hooks]
pretxncommit = python:hgfilesize.limit_file_size
pretxnchangegroup = python:hgfilesize.limit_file_size
[limit_file_size]
maximum_file_size = 200000
'''
def limit_file_size(ui, repo, node=None, **kwargs):
'''forbid files over a given size'''
# default limit is 1 MB
limit = int(ui.config('limit_file_size', 'maximum_file_size', 1024*1024))
existing_tip = context.changectx(repo, node).rev()
new_tip = context.changectx(repo, 'tip').rev()
for rev in xrange(existing_tip, new_tip + 1):
ctx = context.changectx(repo, rev)
for f in ctx.files():
if f not in ctx:
continue
fctx = ctx.filectx(f)
if fctx.size() > limit:
ui.write(_('file %s of %s is too large: %d > %d\n') % \
(f, ctx, fctx.size(), limit))
return True # This is invalid
return False # Things are OK.

View File

@ -0,0 +1,53 @@
# Copyright (c) 2005-2006 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
# Ali Saidi
### If we are not compiling on an alpha, we must use cross tools ###
ifneq ($(shell uname -m), alpha)
CROSS_COMPILE?=alpha-unknown-linux-gnu-
endif
CC=$(CROSS_COMPILE)gcc
AS=$(CROSS_COMPILE)as
LD=$(CROSS_COMPILE)ld
CFLAGS=-O2
OBJS=m5.o m5op_alpha.o
all: m5
%.o: %.S
$(CC) $(CFLAGS) -o $@ -c $<
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
m5: $(OBJS)
$(CC) -o $@ $(OBJS)
clean:
rm -f *.o m5

View File

@ -0,0 +1,81 @@
# Copyright (c) 2010 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2005-2006 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
# Ali Saidi
### If we are not compiling on an arm, we must use cross tools ###
ifneq ($(shell uname -m), arm)
CROSS_COMPILE?=arm-none-linux-gnueabi-
endif
CC=$(CROSS_COMPILE)gcc
AS=$(CROSS_COMPILE)as
LD=$(CROSS_COMPILE)ld
JC=javac
JH=javah
JR=jar
### JDK_PATH must be set to build gem5OpJni
#JDK_PATH=/path/to/jdk/version_number
CFLAGS=-O2 -I $(JDK_PATH)/include/ -I $(JDK_PATH)/include/linux
OBJS=m5.o m5op_arm.o
JNI_OBJS=m5op_arm.o jni_gem5Op.o
all: m5
%.o: %.S
$(CC) $(CFLAGS) -o $@ -c $<
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
m5: $(OBJS)
$(CC) -o $@ $(OBJS)
gem5OpJni: gem5OpJni.jar $(JNI_OBJS)
$(CC) --shared -o lib$@.so $(JNI_OBJS)
gem5OpJni.jar:
$(JC) jni/gem5Op.java; \
$(JH) jni.gem5Op; \
$(JR) cvf $@ jni/*.class
clean:
rm -f *.o m5 libgemOpJni.so gem5OpJni.jar jni/*.class

View File

@ -0,0 +1,53 @@
# Copyright (c) 2005-2006 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
# Ali Saidi
### If we are not compiling on an alpha, we must use cross tools ###
ifneq ($(shell uname -m), sun4v)
CROSS_COMPILE?=sparc64-sun-solaris2.10-
endif
CC=$(CROSS_COMPILE)gcc
AS=$(CROSS_COMPILE)as
LD=$(CROSS_COMPILE)ld
CFLAGS=-O2 -m64
OBJS=m5.o m5op_sparc.o
all: m5
%.o: %.S
$(CC) $(CFLAGS) -o $@ -c $<
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
m5: $(OBJS)
$(CC) -m64 -o $@ $(OBJS)
clean:
rm -f *.o m5

View File

@ -0,0 +1,67 @@
# Copyright (c) 2010 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2005-2006 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
# Ali Saidi
# Chander Sudanthi
### If we are not compiling on an arm, we must use cross tools ###
ifneq ($(shell uname -m), arm)
CROSS_COMPILE?=arm-none-linux-gnueabi-
endif
CC=$(CROSS_COMPILE)gcc
AS=$(CROSS_COMPILE)as
LD=$(CROSS_COMPILE)ld
#CFLAGS=-O2 -march=armv7 -mthumb
CFLAGS=-O2 -mthumb
OBJS=m5.o m5op_arm.o
all: m5
%.o: %.S
$(CC) $(CFLAGS) -o $@ -c $<
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
m5: $(OBJS)
$(CC) -o $@ -march=armv7 -mthumb $(OBJS)
clean:
rm -f *.o m5

View File

@ -0,0 +1,49 @@
# Copyright (c) 2005-2006 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
# Ali Saidi
CC=gcc
AS=as
LD=ld
CFLAGS=-O2
OBJS=m5.o m5op_x86.o
all: m5
%.o: %.S
$(CC) $(CFLAGS) -o $@ -c $<
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
m5: $(OBJS)
$(CC) -o $@ $(OBJS)
clean:
rm -f *.o m5

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Prakash Ramrakhyani
*/
package jni;
/**
* Java class to implement JNI for m5Ops
*/
public class gem5Op {
public native void arm(long address);
public native void quiesce();
public native void quiesceNs(long ns);
public native void quiesceCycle(long cycles);
public native long quiesceTime();
public native long rpns();
public native void wakeCPU(long cpuid);
public native void exit(long ns_delay);
public native long initparam();
public native void checkpoint(long ns_delay, long ns_period);
public native void reset_stats(long ns_delay, long ns_period);
public native void dump_stats(long ns_delay, long ns_period);
public native void dumpreset_stats(long ns_delay, long ns_period);
public native void debugbreak();
public native void switchcpu();
public native void panic();
public native void work_begin(long workid, long threadid);
public native void work_end(long workid, long threadid);
}

View File

@ -0,0 +1,172 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Prakash Ramrakhyani
*/
#include <stdint.h>
#include "jni_gem5Op.h"
#include "m5op.h"
/**
C library interface for gem5Op JNI
*/
JNIEXPORT void JNICALL
Java_jni_gem5Op_arm(JNIEnv *env, jobject obj, jlong j_address)
{
arm(j_address);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_quiesce(JNIEnv *env, jobject obj)
{
quiesce();
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_quiesceNs(JNIEnv *env, jobject obj, jlong j_ns)
{
quiesceNs(j_ns);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_quiesceCycle(JNIEnv *env, jobject obj, jlong j_cycles)
{
quiesceCycle(j_cycles);
}
JNIEXPORT jlong JNICALL
Java_jni_gem5Op_quiesceTime(JNIEnv *env, jobject obj)
{
uint64_t time = quiesceTime();
if (time & 0x8000000000000000ULL)
printf("Truncated return value from quiesceTime() to 63 bits\n");
return (time & 0x7FFFFFFFFFFFFFFFULL);
}
JNIEXPORT jlong JNICALL
Java_jni_gem5Op_rpns(JNIEnv *env, jobject obj)
{
uint64_t time = rpns();
if (time & 0x8000000000000000ULL)
printf("Truncated return value from rpns() to 63 bits\n");
return (time & 0x7FFFFFFFFFFFFFFFULL);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_wakeCPU(JNIEnv *env, jobject obj, jlong j_cpuid)
{
wakeCPU(j_cpuid);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_exit(JNIEnv *env, jobject obj, jlong j_ns_delay)
{
m5_exit(j_ns_delay);
}
JNIEXPORT jlong JNICALL
Java_jni_gem5Op_initparam(JNIEnv *env, jobject obj)
{
uint64_t param = m5_initparam();
if (param & 0x8000000000000000ULL)
printf("Truncated return value from m_initparam() to 63 bits\n");
return (param & 0x7FFFFFFFFFFFFFFFULL);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_checkpoint(JNIEnv *env, jobject obj,
jlong j_ns_delay, jlong j_ns_period)
{
m5_checkpoint(j_ns_delay, j_ns_period);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_reset_1stats(JNIEnv *env, jobject obj,
jlong j_ns_delay, jlong j_ns_period)
{
m5_reset_stats(j_ns_delay, j_ns_period);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_dump_1stats(JNIEnv *env, jobject obj,
jlong j_ns_delay, jlong j_ns_period)
{
m5_dump_stats(j_ns_delay, j_ns_period);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_dumpreset_1stats(JNIEnv *env, jobject obj,
jlong j_ns_delay, jlong j_ns_period)
{
m5_dumpreset_stats(j_ns_delay, j_ns_period);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_debugbreak(JNIEnv *env, jobject obj)
{
m5_debugbreak();
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_switchcpu (JNIEnv *env, jobject obj)
{
m5_switchcpu();
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_panic(JNIEnv *env, jobject obj)
{
m5_panic();
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_work_1begin(JNIEnv *env, jobject obj,
jlong j_workid, jlong j_threadid)
{
m5_work_begin(j_workid, j_threadid);
}
JNIEXPORT void JNICALL
Java_jni_gem5Op_work_1end(JNIEnv *env, jobject obj,
jlong j_workid, jlong j_threadid)
{
m5_work_end(j_workid, j_threadid);
}

View File

@ -0,0 +1,319 @@
/*
* Copyright (c) 2011 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2003-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
*/
#ifdef linux
#define _GNU_SOURCE
#include <sched.h>
#endif
#include <err.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "m5op.h"
char *progname;
char *command = "unspecified";
void usage();
void
parse_int_args(int argc, char *argv[], uint64_t ints[], int len)
{
if (argc > len)
usage();
int i;
for (i = 0; i < len; ++i)
ints[i] = (i < argc) ? strtoul(argv[i], NULL, 0) : 0;
}
int
read_file(int dest_fid)
{
char buf[256*1024];
int offset = 0;
int len;
// Touch all buffer pages to ensure they are mapped in the
// page table. This is required in the case of X86_FS, where
// Linux does demand paging.
memset(buf, 0, sizeof(buf));
while ((len = m5_readfile(buf, sizeof(buf), offset)) > 0) {
write(dest_fid, buf, len);
offset += len;
}
}
int
write_file(const char *filename)
{
fprintf(stderr, "opening %s\n", filename);
int src_fid = open(filename, O_RDONLY);
if (src_fid < 0) {
fprintf(stderr, "error opening %s\n", filename);
return;
}
char buf[256*1024];
int offset = 0;
int len;
int bytes = 0;
memset(buf, 0, sizeof(buf));
while ((len = read(src_fid, buf, sizeof(buf))) > 0) {
bytes += m5_writefile(buf, len, offset, filename);
offset += len;
}
fprintf(stderr, "written %d bytes\n", bytes);
close(src_fid);
}
void
do_exit(int argc, char *argv[])
{
if (argc > 1)
usage();
m5_exit((argc > 0) ? strtoul(argv[0], NULL, 0) : 0);
}
void
do_reset_stats(int argc, char *argv[])
{
uint64_t ints[2];
parse_int_args(argc, argv, ints, 2);
m5_reset_stats(ints[0], ints[1]);
}
void
do_dump_stats(int argc, char *argv[])
{
uint64_t ints[2];
parse_int_args(argc, argv, ints, 2);
m5_dump_stats(ints[0], ints[1]);
}
void
do_dump_reset_stats(int argc, char *argv[])
{
uint64_t ints[2];
parse_int_args(argc, argv, ints, 2);
m5_dumpreset_stats(ints[0], ints[1]);
}
void
do_read_file(int argc, char *argv[])
{
if (argc > 0)
usage();
read_file(STDOUT_FILENO);
}
void
do_write_file(int argc, char *argv[])
{
if (argc != 1)
usage();
const char *filename = argv[0];
write_file(filename);
}
void
do_exec_file(int argc, char *argv[])
{
if (argc > 0)
usage();
const char *destname = "/tmp/execfile";
int fid = open(destname, O_WRONLY, 0777);
int len = read_file(fid);
close(fid);
if (len > 0) {
execl(destname, "execfile", NULL);
err(1, "execl failed!");
}
}
void
do_checkpoint(int argc, char *argv[])
{
uint64_t ints[2];
parse_int_args(argc, argv, ints, 2);
m5_checkpoint(ints[0], ints[1]);
}
void
do_load_symbol(int argc, char *argv[])
{
if (argc != 2)
usage();
uint64_t addr = strtoul(argv[0], NULL, 0);
char *symbol = argv[1];
m5_loadsymbol(addr, symbol);
}
void
do_initparam(int argc, char *argv[])
{
if (argc != 0)
usage();
uint64_t val = m5_initparam();
printf("%"PRIu64, val);
}
void
do_sw99param(int argc, char *argv[])
{
if (argc != 0)
usage();
uint64_t param = m5_initparam();
// run-time, rampup-time, rampdown-time, warmup-time, connections
printf("%d %d %d %d %d", (param >> 48) & 0xfff,
(param >> 36) & 0xfff, (param >> 24) & 0xfff,
(param >> 12) & 0xfff, (param >> 0) & 0xfff);
}
#ifdef linux
void
do_pin(int argc, char *argv[])
{
if (argc < 2)
usage();
cpu_set_t mask;
CPU_ZERO(&mask);
const char *sep = ",";
char *target = strtok(argv[0], sep);
while (target) {
CPU_SET(atoi(target), &mask);
target = strtok(NULL, sep);
}
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) < 0)
err(1, "setaffinity");
execvp(argv[1], &argv[1]);
err(1, "execvp failed!");
}
#endif
struct MainFunc
{
char *name;
void (*func)(int argc, char *argv[]);
char *usage;
};
struct MainFunc mainfuncs[] = {
{ "exit", do_exit, "[delay]" },
{ "resetstats", do_reset_stats, "[delay [period]]" },
{ "dumpstats", do_dump_stats, "[delay [period]]" },
{ "dumpresetstats", do_dump_reset_stats, "[delay [period]]" },
{ "readfile", do_read_file, "" },
{ "writefile", do_write_file, "<filename>" },
{ "execfile", do_exec_file, "" },
{ "checkpoint", do_checkpoint, "[delay [period]]" },
{ "loadsymbol", do_load_symbol, "<address> <symbol>" },
{ "initparam", do_initparam, "" },
{ "sw99param", do_sw99param, "" },
#ifdef linux
{ "pin", do_pin, "<cpu> <program> [args ...]" }
#endif
};
int numfuncs = sizeof(mainfuncs) / sizeof(mainfuncs[0]);
void
usage()
{
int i;
for (i = 0; i < numfuncs; ++i) {
char *header = i ? "" : "usage:";
fprintf(stderr, "%-6s %s %s %s\n",
header, progname, mainfuncs[i].name, mainfuncs[i].usage);
}
fprintf(stderr, "\n");
fprintf(stderr, "All times in nanoseconds!\n");
exit(1);
}
int
main(int argc, char *argv[])
{
progname = argv[0];
if (argc < 2)
usage(1);
command = argv[1];
argv += 2;
argc -= 2;
int i;
for (i = 0; i < numfuncs; ++i) {
if (strcmp(command, mainfuncs[i].name) != 0)
continue;
mainfuncs[i].func(argc, argv);
exit(0);
}
usage(1);
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2003-2006 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
* Ali Saidi
*/
#ifndef __M5OP_H__
#define __M5OP_H__
#include <stdint.h>
void arm(uint64_t address);
void quiesce(void);
void quiesceNs(uint64_t ns);
void quiesceCycle(uint64_t cycles);
uint64_t quiesceTime(void);
uint64_t rpns();
void wakeCPU(uint64_t cpuid);
void m5_exit(uint64_t ns_delay);
uint64_t m5_initparam(void);
void m5_checkpoint(uint64_t ns_delay, uint64_t ns_period);
void m5_reset_stats(uint64_t ns_delay, uint64_t ns_period);
void m5_dump_stats(uint64_t ns_delay, uint64_t ns_period);
void m5_dumpreset_stats(uint64_t ns_delay, uint64_t ns_period);
uint64_t m5_readfile(void *buffer, uint64_t len, uint64_t offset);
uint64_t m5_writefile(void *buffer, uint64_t len, uint64_t offset, const char *filename);
void m5_debugbreak(void);
void m5_switchcpu(void);
void m5_addsymbol(uint64_t addr, char *symbol);
void m5_panic(void);
void m5_work_begin(uint64_t workid, uint64_t threadid);
void m5_work_end(uint64_t workid, uint64_t threadid);
// These operations are for critical path annotation
void m5a_bsm(char *sm, const void *id, int flags);
void m5a_esm(char *sm);
void m5a_begin(int flags, char *st);
void m5a_end(void);
void m5a_q(const void *id, char *q, int count);
void m5a_dq(const void *id, char *q, int count);
void m5a_wf(const void *id, char *q, char *sm, int count);
void m5a_we(const void *id, char *q, char *sm, int count);
void m5a_ws(const void *id, char *q, char *sm);
void m5a_sq(const void *id, char *q, int count, int flags);
void m5a_aq(const void *id, char *q, int count);
void m5a_pq(const void *id, char *q, int count);
void m5a_l(char *lsm, const void *id, char *sm);
void m5a_identify(uint64_t id);
uint64_t m5a_getid(void);
#define M5_AN_FL_NONE 0x0
#define M5_AN_FL_BAD 0x2
#define M5_AN_FL_LINK 0x10
#define M5_AN_FL_RESET 0x20
#endif // __M5OP_H__

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2003-2006 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
* Ali Saidi
*/
#define m5_op 0x01
#include "m5ops.h"
#define INST(op, ra, rb, func) \
.long (((op) << 26) | ((ra) << 21) | ((rb) << 16) | (func))
#define LEAF(func) \
.align 3; \
.globl func; \
.ent func; \
func:
#define RET \
ret ($26)
#define END(func) \
.end func
#define SIMPLE_OP(_f, _o) \
LEAF(_f) \
_o; \
RET; \
END(_f)
#define ARM(reg) INST(m5_op, reg, 0, arm_func)
#define QUIESCE INST(m5_op, 0, 0, quiesce_func)
#define QUIESCENS(r1) INST(m5_op, r1, 0, quiescens_func)
#define QUIESCECYC(r1) INST(m5_op, r1, 0, quiescecycle_func)
#define QUIESCETIME INST(m5_op, 0, 0, quiescetime_func)
#define RPNS INST(m5_op, 0, 0, rpns_func)
#define WAKE_CPU(r1) INST(m5_op, r1, 0, wakecpu_func)
#define M5EXIT(reg) INST(m5_op, reg, 0, exit_func)
#define INITPARAM(reg) INST(m5_op, reg, 0, initparam_func)
#define LOADSYMBOL(reg) INST(m5_op, reg, 0, loadsymbol_func)
#define RESET_STATS(r1, r2) INST(m5_op, r1, r2, resetstats_func)
#define DUMP_STATS(r1, r2) INST(m5_op, r1, r2, dumpstats_func)
#define DUMPRST_STATS(r1, r2) INST(m5_op, r1, r2, dumprststats_func)
#define CHECKPOINT(r1, r2) INST(m5_op, r1, r2, ckpt_func)
#define READFILE INST(m5_op, 0, 0, readfile_func)
#define DEBUGBREAK INST(m5_op, 0, 0, debugbreak_func)
#define SWITCHCPU INST(m5_op, 0, 0, switchcpu_func)
#define ADDSYMBOL(r1,r2) INST(m5_op, r1, r2, addsymbol_func)
#define PANIC INST(m5_op, 0, 0, panic_func)
#define AN_BSM INST(m5_op, an_bsm, 0, annotate_func)
#define AN_ESM INST(m5_op, an_esm, 0, annotate_func)
#define AN_BEGIN INST(m5_op, an_begin, 0, annotate_func)
#define AN_END INST(m5_op, an_end, 0, annotate_func)
#define AN_Q INST(m5_op, an_q, 0, annotate_func)
#define AN_RQ INST(m5_op, an_rq, 0, annotate_func)
#define AN_DQ INST(m5_op, an_dq, 0, annotate_func)
#define AN_WF INST(m5_op, an_wf, 0, annotate_func)
#define AN_WE INST(m5_op, an_we, 0, annotate_func)
#define AN_WS INST(m5_op, an_ws, 0, annotate_func)
#define AN_SQ INST(m5_op, an_sq, 0, annotate_func)
#define AN_AQ INST(m5_op, an_aq, 0, annotate_func)
#define AN_PQ INST(m5_op, an_pq, 0, annotate_func)
#define AN_L INST(m5_op, an_l, 0, annotate_func)
#define AN_IDENTIFY INST(m5_op, an_identify, 0, annotate_func)
#define AN_GETID INST(m5_op, an_getid, 0, annotate_func)
.set noreorder
SIMPLE_OP(arm, ARM(16))
SIMPLE_OP(quiesce, QUIESCE)
SIMPLE_OP(quiesceNs, QUIESCENS(16))
SIMPLE_OP(quiesceCycle, QUIESCECYC(16))
SIMPLE_OP(quiesceTime, QUIESCETIME)
SIMPLE_OP(rpns, RPNS)
SIMPLE_OP(wakeCPU, WAKE_CPU(16))
SIMPLE_OP(m5_exit, M5EXIT(16))
SIMPLE_OP(m5_initparam, INITPARAM(0))
SIMPLE_OP(m5_loadsymbol, LOADSYMBOL(0))
SIMPLE_OP(m5_reset_stats, RESET_STATS(16, 17))
SIMPLE_OP(m5_dump_stats, DUMP_STATS(16, 17))
SIMPLE_OP(m5_dumpreset_stats, DUMPRST_STATS(16, 17))
SIMPLE_OP(m5_checkpoint, CHECKPOINT(16, 17))
SIMPLE_OP(m5_readfile, READFILE)
SIMPLE_OP(m5_debugbreak, DEBUGBREAK)
SIMPLE_OP(m5_switchcpu, SWITCHCPU)
SIMPLE_OP(m5_addsymbol, ADDSYMBOL(16, 17))
SIMPLE_OP(m5_panic, PANIC)
SIMPLE_OP(m5a_bsm, AN_BSM)
SIMPLE_OP(m5a_esm, AN_ESM)
SIMPLE_OP(m5a_begin, AN_BEGIN)
SIMPLE_OP(m5a_end, AN_END)
SIMPLE_OP(m5a_q, AN_Q)
SIMPLE_OP(m5a_rq, AN_RQ)
SIMPLE_OP(m5a_dq, AN_DQ)
SIMPLE_OP(m5a_wf, AN_WF)
SIMPLE_OP(m5a_we, AN_WE)
SIMPLE_OP(m5a_ws, AN_WS)
SIMPLE_OP(m5a_sq, AN_SQ)
SIMPLE_OP(m5a_aq, AN_AQ)
SIMPLE_OP(m5a_pq, AN_PQ)
SIMPLE_OP(m5a_l, AN_L)
SIMPLE_OP(m5a_identify, AN_IDENTIFY)
SIMPLE_OP(m5a_getid, AN_GETID)

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2003-2006 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
* Ali Saidi
* Chander Sudanthi
*/
.syntax unified
#ifdef __thumb__
.thumb
#endif
#define m5_op 0xEE
#include "m5ops.h"
#ifdef __thumb__
#define INST(op, ra, rb, func) \
.short (((op) << 8) | (func)); \
.short (((ra) << 12) | (0x1 << 8) | (0x1 << 4) | (rb))
/* m5ops m5func */
/* ra coproc 1 op=1 rb */
#else
#define INST(op, ra, rb, func) \
.long (((op) << 24) | ((func) << 16) | ((ra) << 12) | (0x1 << 8) | (0x1 << 4) | (rb))
/* m5ops m5func ra coproc 1 op=1 rb */
#endif
#define LEAF(func) \
.globl func; \
func:
#define RET \
mov pc,lr
#define END(func) \
#define SIMPLE_OP(_f, _o) \
LEAF(_f) \
_o; \
RET; \
END(_f)
#define ARM INST(m5_op, 0, 0, arm_func)
#define QUIESCE INST(m5_op, 0, 0, quiesce_func)
#define QUIESCENS INST(m5_op, 0, 0, quiescens_func)
#define QUIESCECYC INST(m5_op, 0, 0, quiescecycle_func)
#define QUIESCETIME INST(m5_op, 0, 0, quiescetime_func)
#define RPNS INST(m5_op, 0, 0, rpns_func)
#define WAKE_CPU INST(m5_op, 0, 0, wakecpu_func)
#define M5EXIT INST(m5_op, 0, 0, exit_func)
#define INITPARAM INST(m5_op, 0, 0, initparam_func)
#define LOADSYMBOL INST(m5_op, 0, 0, loadsymbol_func)
#define RESET_STATS INST(m5_op, 0, 0, resetstats_func)
#define DUMP_STATS INST(m5_op, 0, 0, dumpstats_func)
#define DUMPRST_STATS INST(m5_op, 0, 0, dumprststats_func)
#define CHECKPOINT INST(m5_op, 0, 0, ckpt_func)
#define READFILE INST(m5_op, 0, 0, readfile_func)
#define WRITEFILE INST(m5_op, 0, 0, writefile_func)
#define DEBUGBREAK INST(m5_op, 0, 0, debugbreak_func)
#define SWITCHCPU INST(m5_op, 0, 0, switchcpu_func)
#define ADDSYMBOL INST(m5_op, 0, 0, addsymbol_func)
#define PANIC INST(m5_op, 0, 0, panic_func)
#define WORK_BEGIN INST(m5_op, 0, 0, work_begin_func)
#define WORK_END INST(m5_op, 0, 0, work_end_func)
#define AN_BSM INST(m5_op, an_bsm, 0, annotate_func)
#define AN_ESM INST(m5_op, an_esm, 0, annotate_func)
#define AN_BEGIN INST(m5_op, an_begin, 0, annotate_func)
#define AN_END INST(m5_op, an_end, 0, annotate_func)
#define AN_Q INST(m5_op, an_q, 0, annotate_func)
#define AN_RQ INST(m5_op, an_rq, 0, annotate_func)
#define AN_DQ INST(m5_op, an_dq, 0, annotate_func)
#define AN_WF INST(m5_op, an_wf, 0, annotate_func)
#define AN_WE INST(m5_op, an_we, 0, annotate_func)
#define AN_WS INST(m5_op, an_ws, 0, annotate_func)
#define AN_SQ INST(m5_op, an_sq, 0, annotate_func)
#define AN_AQ INST(m5_op, an_aq, 0, annotate_func)
#define AN_PQ INST(m5_op, an_pq, 0, annotate_func)
#define AN_L INST(m5_op, an_l, 0, annotate_func)
#define AN_IDENTIFY INST(m5_op, an_identify, 0, annotate_func)
#define AN_GETID INST(m5_op, an_getid, 0, annotate_func)
.text
SIMPLE_OP(arm, ARM)
SIMPLE_OP(quiesce, QUIESCE)
SIMPLE_OP(quiesceNs, QUIESCENS)
SIMPLE_OP(quiesceCycle, QUIESCECYC)
SIMPLE_OP(quiesceTime, QUIESCETIME)
SIMPLE_OP(rpns, RPNS)
SIMPLE_OP(wakeCPU, WAKE_CPU)
SIMPLE_OP(m5_exit, M5EXIT)
SIMPLE_OP(m5_initparam, INITPARAM)
SIMPLE_OP(m5_loadsymbol, LOADSYMBOL)
SIMPLE_OP(m5_reset_stats, RESET_STATS)
SIMPLE_OP(m5_dump_stats, DUMP_STATS)
SIMPLE_OP(m5_dumpreset_stats, DUMPRST_STATS)
SIMPLE_OP(m5_checkpoint, CHECKPOINT)
SIMPLE_OP(m5_readfile, READFILE)
SIMPLE_OP(m5_writefile, WRITEFILE)
SIMPLE_OP(m5_debugbreak, DEBUGBREAK)
SIMPLE_OP(m5_switchcpu, SWITCHCPU)
SIMPLE_OP(m5_addsymbol, ADDSYMBOL)
SIMPLE_OP(m5_panic, PANIC)
SIMPLE_OP(m5_work_begin, WORK_BEGIN)
SIMPLE_OP(m5_work_end, WORK_END)
SIMPLE_OP(m5a_bsm, AN_BSM)
SIMPLE_OP(m5a_esm, AN_ESM)
SIMPLE_OP(m5a_begin, AN_BEGIN)
SIMPLE_OP(m5a_end, AN_END)
SIMPLE_OP(m5a_q, AN_Q)
SIMPLE_OP(m5a_rq, AN_RQ)
SIMPLE_OP(m5a_dq, AN_DQ)
SIMPLE_OP(m5a_wf, AN_WF)
SIMPLE_OP(m5a_we, AN_WE)
SIMPLE_OP(m5a_ws, AN_WS)
SIMPLE_OP(m5a_sq, AN_SQ)
SIMPLE_OP(m5a_aq, AN_AQ)
SIMPLE_OP(m5a_pq, AN_PQ)
SIMPLE_OP(m5a_l, AN_L)
SIMPLE_OP(m5a_identify, AN_IDENTIFY)
SIMPLE_OP(m5a_getid, AN_GETID)

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2003-2006 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
* Ali Saidi
*/
#define m5_op 0x2
#define m5_op3 0x37
#include "m5ops.h"
#define INST(func, rs1, rs2, rd) \
.long (m5_op) << 30 | (rd) << 25 | (m5_op3) << 19 | (func) << 7 | \
(rs1) << 14 | (rs2) << 0;
#define LEAF(func) \
.section ".text"; \
.align 4; \
.global func; \
.type func, #function; \
func:
#define END(func) \
.size func, (.-func)
#define DEBUGBREAK INST(debugbreak_func, 0, 0, 0)
#define M5EXIT INST(exit_func, 0, 0, 0)
#define PANIC INST(panic_func, 0, 0, 0)
#define READFILE INST(readfile_func, 0, 0, 0)
LEAF(m5_exit)
retl
M5EXIT
END(m5_exit)
LEAF(m5_panic)
retl
PANIC
END(m5_panic)
LEAF(m5_readfile)
retl
READFILE
END(m5_readfile)
LEAF(m5_debugbreak)
retl
DEBUGBREAK
END(m5_debugbreak)
/* !!!!!! All code below here just panics !!!!!! */
LEAF(arm)
retl
PANIC
END(arm)
LEAF(quiesce)
retl
PANIC
END(quiesce)
LEAF(quiesceNs)
retl
PANIC
END(quiesceNs)
LEAF(quiesceCycle)
retl
PANIC
END(quiesceCycle)
LEAF(quiesceTime)
retl
PANIC
END(quiesceTime)
LEAF(m5_initparam)
retl
PANIC
END(m5_initparam)
LEAF(m5_loadsymbol)
retl
PANIC
END(m5_loadsymbol)
LEAF(m5_reset_stats)
retl
PANIC
END(m5_reset_stats)
LEAF(m5_dump_stats)
retl
PANIC
END(m5_dump_stats)
LEAF(m5_dumpreset_stats)
retl
PANIC
END(m5_dumpreset_stats)
LEAF(m5_checkpoint)
retl
PANIC
END(m5_checkpoint)
LEAF(m5_switchcpu)
retl
PANIC
END(m5_switchcpu)
LEAF(m5_addsymbol)
retl
PANIC
END(m5_addsymbol)
LEAF(m5_anbegin)
retl
PANIC
END(m5_anbegin)
LEAF(m5_anwait)
retl
PANIC
END(m5_anwait)

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2003-2006 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: Gabe Black
* Nathan Binkert
* Ali Saidi
*/
#include "m5ops.h"
#define TWO_BYTE_OP(name, number) \
.globl name; \
.func name; \
name: \
.byte 0x0F, 0x04; \
.word number; \
ret; \
.endfunc;
TWO_BYTE_OP(arm, arm_func)
TWO_BYTE_OP(quiesce, quiesce_func)
TWO_BYTE_OP(quiesceNs, quiescens_func)
TWO_BYTE_OP(quiesceCycle, quiescecycle_func)
TWO_BYTE_OP(quiesceTime, quiescetime_func)
TWO_BYTE_OP(rpns, rpns_func)
TWO_BYTE_OP(m5_exit, exit_func)
TWO_BYTE_OP(m5_initparam, initparam_func)
TWO_BYTE_OP(m5_loadsymbol, loadsymbol_func)
TWO_BYTE_OP(m5_reset_stats, resetstats_func)
TWO_BYTE_OP(m5_dump_stats, dumpstats_func)
TWO_BYTE_OP(m5_dumpreset_stats, dumprststats_func)
TWO_BYTE_OP(m5_checkpoint, ckpt_func)
TWO_BYTE_OP(m5_readfile, readfile_func)
TWO_BYTE_OP(m5_debugbreak, debugbreak_func)
TWO_BYTE_OP(m5_switchcpu, switchcpu_func)
TWO_BYTE_OP(m5_addsymbol, addsymbol_func)
TWO_BYTE_OP(m5_panic, panic_func)
TWO_BYTE_OP(m5_work_begin, work_begin_func)
TWO_BYTE_OP(m5_work_end, work_end_func)

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2003-2006 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
* Ali Saidi
*/
#define arm_func 0x00
#define quiesce_func 0x01
#define quiescens_func 0x02
#define quiescecycle_func 0x03
#define quiescetime_func 0x04
#define rpns_func 0x07
#define wakecpu_func 0x09
#define deprecated1_func 0x10 // obsolete ivlb
#define deprecated2_func 0x11 // obsolete ivle
#define deprecated3_func 0x20 // deprecated exit function
#define exit_func 0x21
#define initparam_func 0x30
#define loadsymbol_func 0x31
#define resetstats_func 0x40
#define dumpstats_func 0x41
#define dumprststats_func 0x42
#define ckpt_func 0x43
#define writefile_func 0x4F
#define readfile_func 0x50
#define debugbreak_func 0x51
#define switchcpu_func 0x52
#define addsymbol_func 0x53
#define panic_func 0x54
#define reserved2_func 0x56 // Reserved for user
#define reserved3_func 0x57 // Reserved for user
#define reserved4_func 0x58 // Reserved for user
#define reserved5_func 0x59 // Reserved for user
#define work_begin_func 0x5a
#define work_end_func 0x5b
// These operations are for critical path annotation
#define annotate_func 0x55
#define an_bsm 0x1
#define an_esm 0x2
#define an_begin 0x3
#define an_end 0x4
#define an_q 0x6
#define an_dq 0x7
#define an_wf 0x8
#define an_we 0x9
#define an_rq 0xA
#define an_ws 0xB
#define an_sq 0xC
#define an_aq 0xD
#define an_pq 0xE
#define an_l 0xF
#define an_identify 0x10
#define an_getid 0x11

View File

@ -0,0 +1,253 @@
#! /usr/bin/env python
# Copyright (c) 2011 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# 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: Giacomo Gabrielli
# Pipeline activity viewer for the O3 CPU model.
import optparse
import os
import sys
def process_trace(trace, outfile, cycle_time, width, color, timestamps,
start_tick, stop_tick, start_sn, stop_sn):
line = None
fields = None
# Skip lines up to region of interest
if start_tick != 0:
while True:
line = trace.readline()
if not line: return
fields = line.split(':')
if fields[0] != 'O3PipeView': continue
if int(fields[2]) >= start_tick: break
elif start_sn != 0:
while True:
line = trace.readline()
if not line: return
fields = line.split(':')
if fields[0] != 'O3PipeView': continue
if fields[1] == 'fetch' and int(fields[5]) >= start_sn: break
else:
line = trace.readline()
if not line: return
fields = line.split(':')
# Skip lines up to next instruction fetch
while fields[0] != 'O3PipeView' or fields[1] != 'fetch':
line = trace.readline()
if not line: return
fields = line.split(':')
# Print header
outfile.write('// f = fetch, d = decode, n = rename, p = dispatch, '
'i = issue, c = complete, r = retire\n\n')
outfile.write(' ' + 'timeline'.center(width) +
' ' + 'tick'.center(15) +
' ' + 'pc.upc'.center(12) +
' ' + 'disasm'.ljust(25) +
' ' + 'seq_num'.center(15))
if timestamps:
outfile.write('timestamps'.center(25))
outfile.write('\n')
# Region of interest
curr_inst = {}
while True:
if fields[0] == 'O3PipeView':
curr_inst[fields[1]] = int(fields[2])
if fields[1] == 'fetch':
if ((stop_tick > 0 and int(fields[2]) > stop_tick) or
(stop_sn > 0 and int(fields[5]) > stop_sn)):
return
(curr_inst['pc'], curr_inst['upc']) = fields[3:5]
curr_inst['sn'] = int(fields[5])
curr_inst['disasm'] = ' '.join(fields[6][:-1].split())
elif fields[1] == 'retire':
print_inst(outfile, curr_inst, cycle_time, width, color,
timestamps)
line = trace.readline()
if not line: return
fields = line.split(':')
def print_inst(outfile, inst, cycle_time, width, color, timestamps):
if color:
from m5.util.terminal import termcap
else:
from m5.util.terminal import no_termcap as termcap
# Pipeline stages
stages = [{'name': 'fetch',
'color': termcap.Blue + termcap.Reverse,
'shorthand': 'f'},
{'name': 'decode',
'color': termcap.Yellow + termcap.Reverse,
'shorthand': 'd'},
{'name': 'rename',
'color': termcap.Magenta + termcap.Reverse,
'shorthand': 'n'},
{'name': 'dispatch',
'color': termcap.Green + termcap.Reverse,
'shorthand': 'p'},
{'name': 'issue',
'color': termcap.Red + termcap.Reverse,
'shorthand': 'i'},
{'name': 'complete',
'color': termcap.Cyan + termcap.Reverse,
'shorthand': 'c'},
{'name': 'retire',
'color': termcap.Blue + termcap.Reverse,
'shorthand': 'r'}]
# Print
time_width = width * cycle_time
base_tick = (inst['fetch'] / time_width) * time_width
num_lines = ((inst['retire'] - inst['fetch']) / time_width) + 1
curr_color = termcap.Normal
for i in range(num_lines):
start_tick = base_tick + i * time_width
end_tick = start_tick + time_width
if num_lines == 1: # compact form
end_tick += (inst['fetch'] - base_tick)
events = []
for stage_idx in range(len(stages)):
tick = inst[stages[stage_idx]['name']]
if tick >= start_tick and tick < end_tick:
events.append((tick % time_width,
stages[stage_idx]['name'],
stage_idx))
events.sort()
outfile.write('[')
pos = 0
if num_lines == 1 and events[0][2] != 0: # event is not fetch
curr_color = stages[events[0][2] - 1]['color']
for event in events:
if (stages[event[2]]['name'] == 'dispatch' and
inst['dispatch'] == inst['issue']):
continue
outfile.write(curr_color + '.' * ((event[0] / cycle_time) - pos))
outfile.write(stages[event[2]]['color'] +
stages[event[2]]['shorthand'])
if event[2] != len(stages) - 1: # event is not retire
curr_color = stages[event[2]]['color']
else:
curr_color = termcap.Normal
pos = (event[0] / cycle_time) + 1
outfile.write(curr_color + '.' * (width - pos) + termcap.Normal +
']-(' + str(base_tick + i * time_width).rjust(15) + ') ')
if i == 0:
outfile.write('%s.%s %s [%s]' % (
inst['pc'].rjust(10),
inst['upc'],
inst['disasm'].ljust(25),
str(inst['sn']).rjust(15)))
if timestamps:
outfile.write(' f=%s, r=%s' % (inst['fetch'], inst['retire']))
outfile.write('\n')
else:
outfile.write('...'.center(12) + '\n')
def validate_range(my_range):
my_range = [int(i) for i in my_range.split(':')]
if (len(my_range) != 2 or
my_range[0] < 0 or
my_range[1] > 0 and my_range[0] >= my_range[1]):
return None
return my_range
def main():
# Parse options
usage = ('%prog [OPTION]... TRACE_FILE')
parser = optparse.OptionParser(usage=usage)
parser.add_option(
'-o',
dest='outfile',
default=os.path.join(os.getcwd(), 'o3-pipeview.out'),
help="output file (default: '%default')")
parser.add_option(
'-t',
dest='tick_range',
default='0:-1',
help="tick range (default: '%default'; -1 == inf.)")
parser.add_option(
'-i',
dest='inst_range',
default='0:-1',
help="instruction range (default: '%default'; -1 == inf.)")
parser.add_option(
'-w',
dest='width',
type='int', default=80,
help="timeline width (default: '%default')")
parser.add_option(
'--color',
action='store_true', default=False,
help="enable colored output (default: '%default')")
parser.add_option(
'-c', '--cycle-time',
type='int', default=1000,
help="CPU cycle time in ticks (default: '%default')")
parser.add_option(
'--timestamps',
action='store_true', default=False,
help="print fetch and retire timestamps (default: '%default')")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.error('incorrect number of arguments')
sys.exit(1)
tick_range = validate_range(options.tick_range)
if not tick_range:
parser.error('invalid range')
sys.exit(1)
inst_range = validate_range(options.inst_range)
if not inst_range:
parser.error('invalid range')
sys.exit(1)
# Process trace
print 'Processing trace... ',
with open(args[0], 'r') as trace:
with open(options.outfile, 'w') as out:
process_trace(trace, out, options.cycle_time, options.width,
options.color, options.timestamps,
*(tick_range + inst_range))
print 'done!'
if __name__ == '__main__':
sys.path.append(os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'..', 'src', 'python'))
main()

View File

@ -0,0 +1,95 @@
#! /usr/bin/env python
# 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: Ali Saidi
# Nathan Binkert
# Parse sampled function profile output (quick hack).
import sys
import re
import getopt
from categories import *
def category(app,sym):
if re.search("vmlinux-2.6", app):
name = sym
else:
name = app
if categories.has_key(name):
return categories[name]
for regexp, cat in categories_re:
if regexp.match(name):
return cat
print "no match for symbol %s" % name
return 'other'
try:
(opts, files) = getopt.getopt(sys.argv[1:], 'i')
except getopt.GetoptError:
print "usage", sys.argv[0], "[-i] <files>"
sys.exit(2)
showidle = True
for o,v in opts:
if o == "-i":
showidle = False
print files
f = open(files.pop())
total = 0
prof = {}
linenum = 0
for line in f.readlines():
line = re.sub("\(no symbols\)", "nosym", line)
line = re.sub("anonymous.*", "nosym", line)
linenum += 1
if linenum < 4:
continue
(count, percent, app, sym) = line.split()
#total += int(count)
cat = category(app,sym)
if cat != 'idle' or showidle:
total += int(count)
prof[cat] = prof.get(cat,0) + int(count)
cats = ['other', 'user', 'copy', 'bufmgt', 'stack', 'driver', 'interrupt', 'alignment' ]
if showidle:
cats.insert(0,'idle')
#syms = [(i[1], i[0]) for i in prof.items()]
#syms.sort()
#for i in range(len(syms)):
# print "%s -- %5.1f%% " % (prof[i][1], 100 * float(prof[i][0])/float(total))
for d in cats:
if prof.has_key(d):
print "%s -- %5.1f%% " % (d, 100 * float(prof[d])/float(total))

241
simulators/gem5/util/pbs/job.py Executable file
View File

@ -0,0 +1,241 @@
#!/usr/bin/env python
# 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))

182
simulators/gem5/util/pbs/pbs.py Executable file
View File

@ -0,0 +1,182 @@
# 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
import os, popen2, re, sys
class MyPOpen(object):
def __init__(self, cmd, input = None, output = None, bufsize = -1):
self.status = -1
if input is None:
p2c_read, p2c_write = os.pipe()
self.tochild = os.fdopen(p2c_write, 'w', bufsize)
else:
p2c_write = None
if isinstance(input, file):
p2c_read = input.fileno()
elif isinstance(input, str):
input = file(input, 'r')
p2c_read = input.fileno()
elif isinstance(input, int):
p2c_read = input
else:
raise AttributeError
if output is None:
c2p_read, c2p_write = os.pipe()
self.fromchild = os.fdopen(c2p_read, 'r', bufsize)
else:
c2p_read = None
if isinstance(output, file):
c2p_write = output.fileno()
elif isinstance(output, str):
output = file(output, 'w')
c2p_write = output.fileno()
elif isinstance(output, int):
c2p_write = output
else:
raise AttributeError
self.pid = os.fork()
if self.pid == 0:
os.dup2(p2c_read, sys.stdin.fileno())
os.dup2(c2p_write, sys.stdout.fileno())
os.dup2(c2p_write, sys.stderr.fileno())
try:
os.execvp(cmd[0], cmd)
finally:
os._exit(1)
os.close(p2c_read)
os.close(c2p_write)
def poll(self):
if self.status < 0:
pid, status = os.waitpid(self.pid, os.WNOHANG)
if pid == self.pid:
self.status = status
return self.status
def wait(self):
if self.status < 0:
pid, status = os.waitpid(self.pid, 0)
if pid == self.pid:
self.status = status
return self.status
class qsub:
def __init__(self):
self.afterok = None
self.hold = False
self.join = False
self.keep_stdout = False
self.keep_stderr = False
self.node_type = None
self.mail_abort = False
self.mail_begin = False
self.mail_end = False
self.name = None
self.stdout = None
self.priority = None
self.queue = None
self.pbshost = None
self.qsub = 'qsub'
self.env = {}
def build(self, script, args = []):
self.cmd = [ self.qsub ]
if self.env:
arg = '-v'
arg += ','.join([ '%s=%s' % i for i in self.env.iteritems() ])
self.cmd.append(arg)
if self.hold:
self.cmd.append('-h')
if self.stdout:
self.cmd.append('-olocalhost:' + self.stdout)
if self.keep_stdout and self.keep_stderr:
self.cmd.append('-koe')
elif self.keep_stdout:
self.cmd.append('-ko')
elif self.keep_stderr:
self.cmd.append('-ke')
else:
self.cmd.append('-kn')
if self.join:
self.cmd.append('-joe')
if self.node_type:
self.cmd.append('-lnodes=' + self.node_type)
if self.mail_abort or self.mail_begin or self.mail_end:
flags = ''
if self.mail_abort:
flags.append('a')
if self.mail_begin:
flags.append('b')
if self.mail_end:
flags.append('e')
if len(flags):
self.cmd.append('-m ' + flags)
else:
self.cmd.append('-mn')
if self.name:
self.cmd.append("-N%s" % self.name)
if self.priority:
self.cmd.append('-p' + self.priority)
if self.queue:
self.cmd.append('-q' + self.queue)
if self.afterok:
self.cmd.append('-Wdepend=afterok:%s' % self.afterok)
self.cmd.extend(args)
self.script = script
self.command = ' '.join(self.cmd + [ self.script ])
def do(self):
pbs = MyPOpen(self.cmd + [ self.script ])
self.result = pbs.fromchild.read()
ec = pbs.wait()
if ec != 0 and self.pbshost:
cmd = ' '.join(self.cmd + [ '-' ])
cmd = [ 'ssh', '-x', self.pbshost, cmd ]
self.command = ' '.join(cmd)
ssh = MyPOpen(cmd, input = self.script)
self.result = ssh.fromchild.read()
ec = ssh.wait()
return ec

292
simulators/gem5/util/pbs/send.py Executable file
View File

@ -0,0 +1,292 @@
#!/usr/bin/env python
# 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: Ali Saidi
# Nathan Binkert
import os, os.path, re, socket, sys
from os import environ as env, listdir
from os.path import basename, isdir, isfile, islink, join as joinpath, normpath
from filecmp import cmp as filecmp
from shutil import copy
def nfspath(dir):
if dir.startswith('/.automount/'):
dir = '/n/%s' % dir[12:]
elif not dir.startswith('/n/'):
dir = '/n/%s%s' % (socket.gethostname().split('.')[0], dir)
return dir
def syncdir(srcdir, destdir):
srcdir = normpath(srcdir)
destdir = normpath(destdir)
if not isdir(destdir):
sys.exit('destination directory "%s" does not exist' % destdir)
for root, dirs, files in os.walk(srcdir):
root = normpath(root)
prefix = os.path.commonprefix([root, srcdir])
root = root[len(prefix):]
if root.startswith('/'):
root = root[1:]
for rem in [ d for d in dirs if d.startswith('.') or d == 'SCCS']:
dirs.remove(rem)
for entry in dirs:
newdir = joinpath(destdir, root, entry)
if not isdir(newdir):
os.mkdir(newdir)
print 'mkdir', newdir
for i,d in enumerate(dirs):
if islink(joinpath(srcdir, root, d)):
dirs[i] = joinpath(d, '.')
for entry in files:
dest = normpath(joinpath(destdir, root, entry))
src = normpath(joinpath(srcdir, root, entry))
if not isfile(dest) or not filecmp(src, dest):
print 'copy %s %s' % (dest, src)
copy(src, dest)
progpath = nfspath(sys.path[0])
progname = basename(sys.argv[0])
usage = """\
Usage:
%(progname)s [-c] [-e] [-f] [-j <jobfile>] [-q queue] [-v] <regexp>
-c clean directory if job can be run
-C submit the checkpointing runs
-d Make jobs be dependent on the completion of the checkpoint runs
-e only echo pbs command info, don't actually send the job
-f force the job to run regardless of state
-q <queue> submit job to the named queue
-j <jobfile> specify the jobfile (default is <rootdir>/Test.py)
-v be verbose
%(progname)s [-j <jobfile>] -l [-v] <regexp>
-j <jobfile> specify the jobfile (default is <rootdir>/Test.py)
-l list job names, don't submit
-v be verbose (list job parameters)
%(progname)s -h
-h display this help
""" % locals()
try:
import getopt
opts, args = getopt.getopt(sys.argv[1:], '-Ccdefhj:lnq:Rt:v')
except getopt.GetoptError:
sys.exit(usage)
depend = False
clean = False
onlyecho = False
exprs = []
force = False
listonly = False
queue = ''
verbose = False
jfile = 'Test.py'
docpts = False
doruns = True
runflag = False
node_type = 'FAST'
update = True
for opt,arg in opts:
if opt == '-C':
docpts = True
if opt == '-c':
clean = True
if opt == '-d':
depend = True
if opt == '-e':
onlyecho = True
if opt == '-f':
force = True
if opt == '-h':
print usage
sys.exit(0)
if opt == '-j':
jfile = arg
if opt == '-l':
listonly = True
if opt == '-n':
update = False
if opt == '-q':
queue = arg
if opt == '-R':
runflag = True
if opt == '-t':
node_type = arg
if opt == '-v':
verbose = True
if docpts:
doruns = runflag
for arg in args:
exprs.append(re.compile(arg))
import jobfile, pbs
from job import JobDir, date
conf = jobfile.JobFile(jfile)
if update and not listonly and not onlyecho and isdir(conf.linkdir):
if verbose:
print 'Checking for outdated files in Link directory'
if not isdir(conf.basedir):
os.mkdir(conf.basedir)
syncdir(conf.linkdir, conf.basedir)
jobnames = {}
joblist = []
if docpts and doruns:
gen = conf.alljobs()
elif docpts:
gen = conf.checkpoints()
elif doruns:
gen = conf.jobs()
for job in gen:
if job.name in jobnames:
continue
if exprs:
for expr in exprs:
if expr.match(job.name):
joblist.append(job)
break
else:
joblist.append(job)
if listonly:
if verbose:
for job in joblist:
job.printinfo()
else:
for job in joblist:
print job.name
sys.exit(0)
if not onlyecho:
newlist = []
for job in joblist:
jobdir = JobDir(joinpath(conf.rootdir, job.name))
if jobdir.exists():
if not force:
status = jobdir.getstatus()
if status == 'queued':
continue
if status == 'running':
continue
if status == 'success':
continue
if not clean:
sys.exit('job directory %s not clean!' % jobdir)
jobdir.clean()
newlist.append(job)
joblist = newlist
class NameHack(object):
def __init__(self, host='pbs.pool', port=24465):
self.host = host
self.port = port
self.socket = None
def setname(self, jobid, jobname):
try:
jobid = int(jobid)
except ValueError:
jobid = int(jobid.strip().split('.')[0])
jobname = jobname.strip()
# since pbs can handle jobnames of 15 characters or less,
# don't use the raj hack.
if len(jobname) <= 15:
return
if self.socket is None:
import socket
self.socket = socket.socket()
# Connect to pbs.pool and send the jobid/jobname pair to port
# 24465 (Raj didn't realize that there are only 64k ports and
# setup inetd to point to port 90001)
self.socket.connect((self.host, self.port))
self.socket.send("%s %s\n" % (jobid, jobname))
namehack = NameHack()
for job in joblist:
jobdir = JobDir(joinpath(conf.rootdir, job.name))
if depend:
cptdir = JobDir(joinpath(conf.rootdir, job.checkpoint.name))
cptjob = cptdir.readval('.pbs_jobid')
if not onlyecho:
jobdir.create()
print 'Job name: %s' % job.name
print 'Job directory: %s' % jobdir
qsub = pbs.qsub()
qsub.pbshost = 'simpool.eecs.umich.edu'
qsub.stdout = jobdir.file('jobout')
qsub.name = job.name[:15]
qsub.join = True
qsub.node_type = node_type
qsub.env['ROOTDIR'] = conf.rootdir
qsub.env['JOBNAME'] = job.name
if depend:
qsub.afterok = cptjob
if queue:
qsub.queue = queue
qsub.build(joinpath(progpath, 'job.py'))
if verbose:
print 'PBS Command: %s' % qsub.command
if not onlyecho:
ec = qsub.do()
if ec == 0:
jobid = qsub.result
print 'PBS Jobid: %s' % jobid
namehack.setname(jobid, job.name)
queued = date()
jobdir.echofile('.pbs_jobid', jobid)
jobdir.echofile('.pbs_jobname', job.name)
jobdir.echofile('.queued', queued)
jobdir.setstatus('queued on %s' % queued)
else:
print 'PBS Failed'

238
simulators/gem5/util/qdo Executable file
View File

@ -0,0 +1,238 @@
#! /usr/bin/env python
# Copyright (c) 2004-2005, 2007 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: Steve Reinhardt
# Ali Saidi
# Important!
# This script expects a simple $ prompt, if you are using a shell other than
# sh which defaults to this you'll need to add something like the following
# to your bashrc/bash_profile script:
#if [ "$OAR_USER" = "xxxx" ]; then
# PS1='$ '
import sys
import os
import re
import time
import optparse
import pexpect
progname = os.path.basename(sys.argv[0])
usage = "%prog [options] command [command arguments]"
optparser = optparse.OptionParser(usage=usage)
optparser.allow_interspersed_args=False
optparser.add_option('-e', dest='stderr_file',
help='command stderr output file')
optparser.add_option('-o', dest='stdout_file',
help='command stdout output file')
optparser.add_option('-l', dest='save_log', action='store_true',
help='save oarsub output log file')
optparser.add_option('-N', dest='job_name',
help='oarsub job name')
optparser.add_option('-q', dest='dest_queue',
help='oarsub destination queue')
optparser.add_option('--qwait', dest='oarsub_timeout', type='int',
help='oarsub queue wait timeout', default=30*60)
optparser.add_option('-t', dest='cmd_timeout', type='int',
help='command execution timeout', default=600*60)
(options, cmd) = optparser.parse_args()
if cmd == []:
print >>sys.stderr, "%s: missing command" % progname
sys.exit(1)
# If we want to do this, need to add check here to make sure cmd[0] is
# a valid PBS job name, else oarsub will die on us.
#
#if not options.job_name:
# options.job_name = cmd[0]
cwd = os.getcwd()
# Deal with systems where /n is a symlink to /.automount
if cwd.startswith('/.automount/'):
cwd = cwd.replace('/.automount/', '/n/', 1)
if not cwd.startswith('/n/poolfs/'):
print >>sys.stderr, "Error: current directory must be under /n/poolfs."
sys.exit(1)
# The Shell class wraps pexpect.spawn with some handy functions that
# assume the thing on the other end is a Bourne/bash shell.
class Shell(pexpect.spawn):
# Regexp to match the shell prompt. We change the prompt to
# something fixed and distinctive to make it easier to match
# reliably.
prompt_re = re.compile('qdo\$ ')
def __init__(self, cmd):
# initialize base pexpect.spawn object
try:
pexpect.spawn.__init__(self, cmd)
except pexpect.ExceptionPexpect, exc:
print "%s:" % progname, exc
sys.exit(1)
# full_output accumulates the full output of the session
self.full_output = ""
self.quick_timeout = 15
# wait for a prompt, then change it
try:
self.expect('\$ ', options.oarsub_timeout)
except pexpect.TIMEOUT:
print >>sys.stderr, "%s: oarsub timed out." % progname
self.kill(9)
self.safe_close()
sys.exit(1)
self.do_command('unset PROMPT_COMMAND; PS1="qdo$ "')
# version of expect that updates full_output too
def expect(self, regexp, timeout = -1):
pexpect.spawn.expect(self, regexp, timeout)
self.full_output += self.before + self.after
# Just issue a command and wait for the next prompt.
# Returns a string containing the output of the command.
def do_bare_command(self, cmd, timeout = -1):
global full_output
self.sendline(cmd)
# read back the echo of the command
self.readline()
# wait for the next prompt
self.expect(self.prompt_re, timeout)
output = self.before.rstrip()
return output
# Issue a command, then query its exit status.
# Returns a (string, int) tuple with the command output and the status.
def do_command(self, cmd, timeout = -1):
# do the command itself
output = self.do_bare_command(cmd, timeout)
# collect status
status = int(self.do_bare_command("echo $?", self.quick_timeout))
return (output, status)
# Check to see if the given directory exists.
def dir_exists(self, dirname):
(output, status) = shell.do_command('[ -d %s ]' % dirname,
self.quick_timeout)
return status == 0
# Don't actually try to close it.. just wait until it closes by itself
# We can't actually kill the pid which is what it's trying to do, and if
# we call wait we could be in an unfortunate situation of it printing input
# right as we call wait, so the input is never read and the process never ends
def safe_close(self):
count = 0
while self.isalive() and count < 10:
time.sleep(1)
self.close(force=False)
# Spawn the interactive pool job.
# Hack to do link on poolfs... disabled for now since
# compiler/linker/library versioning problems between poolfs and
# nodes. May never work since poolfs is x86-64 and nodes are 32-bit.
if False and len(cmd) > 50:
shell_cmd = 'ssh -t poolfs /bin/sh -l'
print "%s: running %s on poolfs" % (progname, cmd[0])
else:
shell_cmd = 'oarsub -I'
if options.job_name:
shell_cmd += ' -n "%s"' % options.job_name
if options.dest_queue:
shell_cmd += ' -q ' + options.dest_queue
shell_cmd += ' -d %s' % cwd
shell = Shell(shell_cmd)
try:
# chdir to cwd
(output, status) = shell.do_command('cd ' + cwd)
if status != 0:
raise OSError, "Can't chdir to %s" % cwd
# wacky hack: sometimes scons will create an output directory then
# fork a job to generate files in that directory, and the job will
# get run before the directory creation propagates through NFS.
# This hack looks for a '-o' option indicating an output file and
# waits for the corresponding directory to appear if necessary.
try:
if 'cc' in cmd[0] or 'g++' in cmd[0]:
output_dir = os.path.dirname(cmd[cmd.index('-o')+1])
elif 'm5' in cmd[0]:
output_dir = cmd[cmd.index('-d')+1]
else:
output_dir = None
except (ValueError, IndexError):
# no big deal if there's no '-o'/'-d' or if it's the final argument
output_dir = None
if output_dir:
secs_waited = 0
while not shell.dir_exists(output_dir) and secs_waited < 90:
time.sleep(5)
secs_waited += 5
if secs_waited > 30:
print "waited", secs_waited, "seconds for", output_dir
# run command
if options.stdout_file:
cmd += ['>', options.stdout_file]
if options.stderr_file:
cmd += ['2>', options.stderr_file]
try:
(output, status) = shell.do_command(' '.join(cmd), options.cmd_timeout)
except pexpect.TIMEOUT:
print >>sys.stderr, "%s: command timed out after %d seconds." \
% (progname, options.cmd_timeout)
shell.sendline('~.') # oarsub/ssh termination escape sequence
shell.safe_close()
status = 3
if output:
print output
finally:
# end job
if shell.isalive():
shell.sendline('exit')
shell.expect('Disconnected from OAR job .*')
shell.safe_close()
# if there was an error, log the output even if not requested
if status != 0 or options.save_log:
log = file('qdo-log.' + str(os.getpid()), 'w')
log.write(shell.full_output)
log.close()
del shell
sys.exit(status)

163
simulators/gem5/util/regress Executable file
View File

@ -0,0 +1,163 @@
#! /usr/bin/env python
# Copyright (c) 2005-2007 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: Steve Reinhardt
import sys
import os
import optparse
import datetime
from subprocess import call
progname = os.path.basename(sys.argv[0])
optparser = optparse.OptionParser()
add_option = optparser.add_option
add_option('-v', '--verbose', action='store_true', default=False,
help='echo commands before executing')
add_option('--builds',
default='ALPHA,ALPHA_MOESI_hammer,' \
'ALPHA_MESI_CMP_directory,' \
'ALPHA_MOESI_CMP_directory,' \
'ALPHA_MOESI_CMP_token,' \
'MIPS,' \
'POWER,' \
'SPARC,' \
'X86,X86_MESI_CMP_directory,' \
'ARM',
help="comma-separated build targets to test (default: '%default')")
add_option('--modes',
default='se,fs',
help="comma-separated modes to test (default: '%default')")
add_option('--test-variants', default='opt',
help="comma-separated build variants to test (default: '%default')"\
", set to '' for none")
add_option('--compile-variants', default='debug,fast',
help="comma-separated build variants to compile only (not test) " \
"(default: '%default'), set to '' for none", metavar='VARIANTS')
add_option('--scons-opts', default='', metavar='OPTS',
help='scons options')
add_option('-j', '--jobs', type='int', default=1, metavar='N',
help='number of parallel jobs to use (0 to use all cores)')
add_option('-k', '--keep-going', action='store_true',
help='keep going after errors')
add_option('--update-ref', action='store_true',
help='update reference outputs')
add_option('-D', '--build-dir', default='', metavar='DIR',
help='build directory location')
add_option('-n', "--no-exec", default=False, action='store_true',
help="don't actually invoke scons, just echo SCons command line")
(options, tests) = optparser.parse_args()
# split a comma-separated list, but return an empty list if given the
# empty string
def split_if_nonempty(s):
if not s:
return []
return s.split(',')
# split list options on ',' to get Python lists
builds = split_if_nonempty(options.builds)
modes = split_if_nonempty(options.modes)
test_variants = split_if_nonempty(options.test_variants)
compile_variants = split_if_nonempty(options.compile_variants)
options.build_dir = os.path.join(options.build_dir, 'build')
# Call os.system() and raise exception if return status is non-zero
def system(cmd):
try:
retcode = call(cmd, shell=True)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
print >>sys.stderr, "When attemping to execute: %s" % cmd
sys.exit(1)
elif retcode > 0:
print >>sys.stderr, "Child returned", retcode
print >>sys.stderr, "When attemping to execute: %s" % cmd
sys.exit(1)
except OSError, e:
print >>sys.stderr, "Execution failed:", e
print >>sys.stderr, "When attemping to execute: %s" % cmd
sys.exit(1)
targets = []
# start with compile-only targets, if any
if compile_variants:
targets += ['%s/%s/gem5.%s' % (options.build_dir, build, variant)
for variant in compile_variants
for build in builds]
# By default run the 'quick' tests, all expands to quick and long
if not tests:
tests = ['quick']
elif 'all' in tests:
tests = ['quick', 'long']
# set up test targets for scons, since we don't have any quick SPARC
# full-system tests exclude it
targets += ['%s/%s/tests/%s/%s/%s' % (options.build_dir, build, variant, test,
mode)
for build in builds
for variant in test_variants
for test in tests
for mode in modes
if not (build == 'SPARC' and test == 'quick' and mode == 'fs')]
def cpu_count():
if 'bsd' in sys.platform or sys.platform == 'darwin':
try:
return int(os.popen('sysctl -n hw.ncpu').read())
except ValueError:
pass
else:
try:
return os.sysconf('SC_NPROCESSORS_ONLN')
except (ValueError, OSError, AttributeError):
pass
raise NotImplementedError('cannot determine number of cpus')
scons_opts = options.scons_opts
if options.jobs != 1:
if options.jobs == 0:
options.jobs = cpu_count()
scons_opts += ' -j %d' % options.jobs
if options.keep_going:
scons_opts += ' -k'
if options.update_ref:
scons_opts += ' --update-ref'
cmd = 'scons --ignore-style %s %s' % (scons_opts, ' '.join(targets))
if options.no_exec:
print cmd
else:
system(cmd)
sys.exit(0)

321
simulators/gem5/util/rundiff Executable file
View File

@ -0,0 +1,321 @@
#! /usr/bin/env perl
# Copyright (c) 2003 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
# Diff two streams.
#
# Unlike regular diff, this script does not read in the entire input
# before doing a diff, so it can be used on lengthy outputs piped from
# other programs (e.g., M5 traces). The best way to do this is to
# take advantage of the power of Perl's open function, which will
# automatically fork a subprocess if the last character in the
# "filename" is a pipe (|). Thus to compare the instruction traces
# from two versions of m5 (m5a and m5b), you can do this:
#
# rundiff 'm5a --traceflags=InstExec |' 'm5b --traceflags=InstExec |'
#
use strict;
use FileHandle;
use Getopt::Std;
#
# Options:
# -c <n> : print n lines of context before & after changes
# -l <n> : use n lines of lookahead
# -x : use "complex" diff from Algorithm::Diff (see below)
#
our ($opt_c, $opt_l, $opt_x);
getopts('c:l:x');
#
# For the highest-quality (minimal) diffs, we can use the
# Algorithm::Diff package. By default, a built-in, simple, and
# generally quite adequate algorithm will be used. If you have
# Algorithm::Diff installed on your system, and don't mind having the
# script go slower (like 3-4x slower, based on informal observation),
# then specify '-x' on the command line to use it.
my $use_complexdiff = defined($opt_x);
if ($use_complexdiff) {
# Don't use 'use', as that's a compile-time option and will fail
# on systems that don't have Algorithm::Diff installed even if
# $use_complexdiff is false. 'require' is evaluated at runtime,
# so it's OK.
require Algorithm::Diff;
import Algorithm::Diff qw(traverse_sequences);
};
my $lookahead_lines = $opt_l || 200;
# in theory you could have different amounts of context before and
# after a diff, but until someone needs that there's only one arg to
# set both.
my $precontext_lines = $opt_c || 3;
my $postcontext_lines = $precontext_lines;
my $file1 = $ARGV[0];
my $file2 = $ARGV[1];
die "Need two args." if (!(defined($file1) && defined($file2)));
my ($fh1, $fh2);
open($fh1, $file1) or die "Can't open $file1";
open($fh2, $file2) or die "Can't open $file2";
# print files to output so we know which is which
print "-$file1\n";
print "+$file2\n";
# buffer of matching lines for pre-diff context
my @precontext = ();
# number of post-diff matching lines remaining to print
my $postcontext = 0;
# lookahead buffers for $file1 and $file2 respectively
my @lines1 = ();
my @lines2 = ();
# Next line number available to print from each file. Generally this
# corresponds to the oldest line in @precontext, or the oldest line in
# @lines1 and @lines2 if @precontext is empty.
my $lineno1 = 1;
my $lineno2 = 1;
# Fill a lookahead buffer to $lookahead_lines lines (or until EOF).
sub fill
{
my ($fh, $array) = @_;
while (@$array < $lookahead_lines) {
my $line = <$fh>;
last if (!defined($line));
push @$array, $line;
}
}
# Print and delete n lines from front of given array with given prefix.
sub printlines
{
my ($array, $n, $prefix) = @_;
while ($n--) {
my $line = shift @$array;
last if (!defined($line));
print $prefix, $line;
}
}
# Print a difference region where n1 lines of file1 were replaced by
# n2 lines of file2 (where either n1 or n2 could be zero).
sub printdiff
{
my ($n1, $n2)= @_;
# If the precontext buffer is full or we're at the beginning of a
# file, then this is a new diff region, so we should print a
# header indicating the current line numbers. If we're past the
# beginning and the precontext buffer isn't full, then whatever
# we're about to print is contiguous with the end of the last
# region we printed, so we just concatenate them on the output.
if (@precontext == $precontext_lines || ($lineno1 == 0 && $lineno2 == 0)) {
print "@@ -$lineno1 +$lineno2 @@\n";
}
# Print and clear the precontext buffer.
if (@precontext) {
print ' ', join(' ', @precontext);
$lineno1 += scalar(@precontext);
$lineno2 += scalar(@precontext);
@precontext = ();
}
# Print the differing lines.
printlines(\@lines1, $n1, '-');
printlines(\@lines2, $n2, '+');
$lineno1 += $n1;
$lineno2 += $n2;
# Set $postcontext to print the next $postcontext_lines matching lines.
$postcontext = $postcontext_lines;
# Normally we flush after the postcontext lines are printed, but if
# the user has decreed that there aren't any we need to flush now
if ($postcontext == 0) {
STDOUT->flush();
}
}
########################
#
# Complex diff algorithm
#
########################
{
my $match_found;
my $discard_lines1;
my $discard_lines2;
sub match { $match_found = 1; }
sub discard1 { $discard_lines1++ unless $match_found; }
sub discard2 { $discard_lines2++ unless $match_found; }
sub complex_diff
{
$match_found = 0;
$discard_lines1 = 0;
$discard_lines2 = 0;
# See Diff.pm. Note that even though this call generates a
# complete diff of both lookahead buffers, all we use it for
# is to figure out how many lines to discard off the front of
# each buffer to resync the streams.
traverse_sequences( \@lines1, \@lines2,
{ MATCH => \&match,
DISCARD_A => \&discard1,
DISCARD_B => \&discard2 });
if (!$match_found) {
printdiff(scalar(@lines1), scalar(@lines2));
die "Lost sync!";
}
# Since we shouldn't get here unless the first lines of the
# buffers are different, then we must discard some lines off
# at least one of the buffers.
die if ($discard_lines1 == 0 && $discard_lines2 == 0);
printdiff($discard_lines1, $discard_lines2);
}
}
#######################
#
# Simple diff algorithm
#
#######################
# Check for a pair of matching lines; if found, generate appropriate
# diff output.
sub checkmatch
{
my ($n1, $n2) = @_;
# Check if two adjacent lines match, to reduce false resyncs
# (particularly on unrelated blank lines). This generates
# larger-than-necessary diffs when a single line really should be
# treated as common; if that bugs you, use Algorithm::Diff.
if ($lines1[$n1] eq $lines2[$n2] && $lines1[$n1+1] eq $lines2[$n2+1]) {
printdiff($n1, $n2);
return 1;
}
return 0;
}
sub simple_diff
{
# Look for differences of $cnt lines to resync,
# increasing $cnt from 1 to $lookahead_lines until we find
# something.
for (my $cnt = 1; $cnt < $lookahead_lines-1; ++$cnt) {
# Check for n lines in one file being replaced by
# n lines in the other.
return if checkmatch($cnt, $cnt);
# Find differences where n lines in one file were
# replaced by m lines in the other. We let m = $cnt
# and iterate for n = 0 to $cnt-1.
for (my $n = 0; $n < $cnt; ++$n) {
return if checkmatch($n, $cnt);
return if checkmatch($cnt, $n);
}
}
printdiff(scalar(@lines1), scalar(@lines2));
die "Lost sync!";
}
# Set the pointer to the appropriate diff function.
#
# Note that in either case the function determines how many lines to
# discard from the front of each lookahead buffer to resync the
# streams, then prints the appropriate diff output and discards them.
# After the function returns, it should always be the case that
# $lines1[0] eq $lines2[0].
my $find_diff = $use_complexdiff ? \&complex_diff : \&simple_diff;
# The main loop.
while (1) {
# keep lookahead buffers topped up
fill($fh1, \@lines1);
fill($fh2, \@lines2);
# peek at first line in each buffer
my $l1 = $lines1[0];
my $l2 = $lines2[0];
if (!defined($l1) && !defined($l2)) {
# reached EOF on both streams: exit
exit(1);
}
if ($l1 eq $l2) {
# matching lines: delete from lookahead buffer
shift @lines1;
shift @lines2;
# figure out what to do with this line
if ($postcontext > 0) {
# we're in the post-context of a diff: print it
print ' ', $l1;
$lineno1++;
$lineno2++;
if (--$postcontext == 0) {
STDOUT->flush();
}
}
else {
# we're in the middle of a matching region... save this
# line for precontext in case we run into a difference.
push @precontext, $l1;
# don't let precontext buffer get bigger than needed
while (@precontext > $precontext_lines) {
shift @precontext;
$lineno1++;
$lineno2++;
}
}
}
else {
# Mismatch. Deal with it.
&$find_diff();
}
}

38
simulators/gem5/util/slicc Executable file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env python
# Copyright (c) 2009 The Hewlett-Packard Development Company
# 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.
if __name__ == "__main__":
import sys
from os.path import dirname, join
base = dirname(__file__)
sys.path.insert(1, join(base, "../src/mem"))
sys.path.insert(1, join(base, "../src/python"))
sys.path.insert(1, join(base, "../ext/ply"))
import slicc.main
slicc.main.main()

View File

@ -0,0 +1,220 @@
#!/usr/bin/env python
import os
import re
import sys
from file_types import *
cpp_c_headers = {
'assert.h' : 'cassert',
'ctype.h' : 'cctype',
'errno.h' : 'cerrno',
'float.h' : 'cfloat',
'limits.h' : 'climits',
'locale.h' : 'clocale',
'math.h' : 'cmath',
'setjmp.h' : 'csetjmp',
'signal.h' : 'csignal',
'stdarg.h' : 'cstdarg',
'stddef.h' : 'cstddef',
'stdio.h' : 'cstdio',
'stdlib.h' : 'cstdlib',
'string.h' : 'cstring',
'time.h' : 'ctime',
'wchar.h' : 'cwchar',
'wctype.h' : 'cwctype',
}
include_re = re.compile(r'([#%])(include|import).*[<"](.*)[">]')
def include_key(line):
'''Mark directories with a leading space so directories
are sorted before files'''
match = include_re.match(line)
assert match, line
keyword = match.group(2)
include = match.group(3)
# Everything but the file part needs to have a space prepended
parts = include.split('/')
if len(parts) == 2 and parts[0] == 'dnet':
# Don't sort the dnet includes with respect to each other, but
# make them sorted with respect to non dnet includes. Python
# guarantees that sorting is stable, so just clear the
# basename part of the filename.
parts[1] = ' '
parts[0:-1] = [ ' ' + s for s in parts[0:-1] ]
key = '/'.join(parts)
return key
class SortIncludes(object):
# different types of includes for different sorting of headers
# <Python.h> - Python header needs to be first if it exists
# <*.h> - system headers (directories before files)
# <*> - STL headers
# <*.(hh|hxx|hpp|H)> - C++ Headers (directories before files)
# "*" - M5 headers (directories before files)
includes_re = (
('python', '<>', r'^(#include)[ \t]+<(Python.*\.h)>(.*)'),
('c', '<>', r'^(#include)[ \t]<(.+\.h)>(.*)'),
('stl', '<>', r'^(#include)[ \t]+<([0-9A-z_]+)>(.*)'),
('cc', '<>', r'^(#include)[ \t]+<([0-9A-z_]+\.(hh|hxx|hpp|H))>(.*)'),
('m5cc', '""', r'^(#include)[ \t]"(.+\.h{1,2})"(.*)'),
('swig0', '<>', r'^(%import)[ \t]<(.+)>(.*)'),
('swig1', '<>', r'^(%include)[ \t]<(.+)>(.*)'),
('swig2', '""', r'^(%import)[ \t]"(.+)"(.*)'),
('swig3', '""', r'^(%include)[ \t]"(.+)"(.*)'),
)
# compile the regexes
includes_re = tuple((a, b, re.compile(c)) for a,b,c in includes_re)
def __init__(self):
self.reset()
def reset(self):
# clear all stored headers
self.includes = {}
for include_type,_,_ in self.includes_re:
self.includes[include_type] = []
def dump_block(self):
'''dump the includes'''
first = True
for include,_,_ in self.includes_re:
if not self.includes[include]:
continue
if not first:
# print a newline between groups of
# include types
yield ''
first = False
# print out the includes in the current group
# and sort them according to include_key()
prev = None
for l in sorted(self.includes[include],
key=include_key):
if l != prev:
yield l
prev = l
def __call__(self, lines, filename, language):
leading_blank = False
blanks = 0
block = False
for line in lines:
if not line:
blanks += 1
if not block:
# if we're not in an include block, spit out the
# newline otherwise, skip it since we're going to
# control newlines withinin include block
yield ''
continue
# Try to match each of the include types
for include_type,(ldelim,rdelim),include_re in self.includes_re:
match = include_re.match(line)
if not match:
continue
# if we've got a match, clean up the #include line,
# fix up stl headers and store it in the proper category
groups = match.groups()
keyword = groups[0]
include = groups[1]
extra = groups[-1]
if include_type == 'c' and language == 'C++':
stl_inc = cpp_c_headers.get(include, None)
if stl_inc:
include = stl_inc
include_type = 'stl'
line = keyword + ' ' + ldelim + include + rdelim + extra
self.includes[include_type].append(line)
# We've entered a block, don't keep track of blank
# lines while in a block
block = True
blanks = 0
break
else:
# this line did not match a #include
assert not include_re.match(line)
# if we're not in a block and we didn't match an include
# to enter a block, just emit the line and continue
if not block:
yield line
continue
# We've exited an include block.
for block_line in self.dump_block():
yield block_line
# if there are any newlines after the include block,
# emit a single newline (removing extras)
if blanks and block:
yield ''
blanks = 0
block = False
self.reset()
# emit the line that ended the block
yield line
if block:
# We've exited an include block.
for block_line in self.dump_block():
yield block_line
# default language types to try to apply our sorting rules to
default_languages = frozenset(('C', 'C++', 'isa', 'python', 'scons', 'swig'))
def options():
import optparse
options = optparse.OptionParser()
add_option = options.add_option
add_option('-d', '--dir_ignore', metavar="DIR[,DIR]", type='string',
default=','.join(default_dir_ignore),
help="ignore directories")
add_option('-f', '--file_ignore', metavar="FILE[,FILE]", type='string',
default=','.join(default_file_ignore),
help="ignore files")
add_option('-l', '--languages', metavar="LANG[,LANG]", type='string',
default=','.join(default_languages),
help="languages")
add_option('-n', '--dry-run', action='store_true',
help="don't overwrite files")
return options
def parse_args(parser):
opts,args = parser.parse_args()
opts.dir_ignore = frozenset(opts.dir_ignore.split(','))
opts.file_ignore = frozenset(opts.file_ignore.split(','))
opts.languages = frozenset(opts.languages.split(','))
return opts,args
if __name__ == '__main__':
parser = options()
opts, args = parse_args(parser)
for base in args:
for filename,language in find_files(base, languages=opts.languages,
file_ignore=opts.file_ignore, dir_ignore=opts.dir_ignore):
if opts.dry_run:
print "%s: %s" % (filename, language)
else:
update_file(filename, filename, language, SortIncludes())

View File

@ -0,0 +1,39 @@
# Copyright (c) 2011 Gabe Black
# 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: Gabe Black
import os
Import('env', 'arch')
env.Append(CPPPATH=Dir('.'))
sources = [os.path.join('base', 'statetrace.cc'),
os.path.join('base', 'tracechild.cc'),
os.path.join('arch', arch, 'tracechild.cc')]
objects = [env.Object(source) for source in sources]
env.Program('statetrace', objects)

View File

@ -0,0 +1,67 @@
# Copyright (c) 2011 Gabe Black
# 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: Gabe Black
Help('''
To build a version of statetrace suitable to run on a particular ISA, use a
target of the form build/<arch>/statetrace. For example, to build statetrace
for ARM binaries, run:
scons build/arm/statetrace
You may need a cross compiler in order to build statetrace successfully. To
specify an alternative compiler, set the CXX scons argument on the command
line. The CXX environment variable is NOT considered when selecting the
compiler. To override the compiler for a particular target ISA, set the
<arch>CXX scons argument. For example, to build both the AMD64 version and
the ARM version at the same time using the system compiler for the AMD64
version and a cross compiler for arm, your command line would look like the
following:
scons ARMCXX=arm-cross-g++ build/amd64/statetrace build/arm/statetrace
After a successful build, the statetrace binary(binaries) will be located in
the build/<arch>/ directories you specified on the command line.
''')
arches = 'amd64', 'arm', 'i686', 'sparc'
import os
main = Environment()
main.SetOption('duplicate', 'soft-copy')
main['CXXFLAGS'] = "-O3 -ggdb $_CPPINCFLAGS"
main['CXX'] = ARGUMENTS.get('CXX', main['CXX'])
for arch in arches:
env = main.Clone()
env['CXX'] = ARGUMENTS.get(arch.upper() + 'CXX', env['CXX'])
env.Append(CPPFLAGS = '-D__STATETRACE_%s__' % arch.upper())
Export('env', 'arch')
env.SConscript('SConscript', variant_dir = os.path.join('build', arch))

View File

@ -0,0 +1,405 @@
/*
* Copyright (c) 2007 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: Gabe Black
*/
#include <sys/ptrace.h>
#include <stdint.h>
#include <cerrno>
#include <cstring>
#include <iomanip>
#include <iostream>
#include "arch/amd64/tracechild.hh"
using namespace std;
bool
AMD64TraceChild::sendState(int socket)
{
uint64_t regVal64 = 0;
uint32_t regVal32 = 0;
for (int x = 0; x <= R15; x++) {
regVal64 = getRegVal(x);
if (write(socket, &regVal64, sizeof(regVal64)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
}
regVal64 = getRegVal(RIP);
if (write(socket, &regVal64, sizeof(regVal64)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
for (int x = MMX0_0; x <= MMX7_1; x++) {
regVal32 = getRegVal(x);
if (write(socket, &regVal32, sizeof(regVal32)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
}
for (int x = XMM0_0; x <= XMM15_3; x++) {
regVal32 = getRegVal(x);
if (write(socket, &regVal32, sizeof(regVal32)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
}
return true;
}
int64_t
AMD64TraceChild::getRegs(user_regs_struct & myregs,
user_fpregs_struct & myfpregs, int num)
{
assert(num < numregs && num >= 0);
switch (num) {
//GPRs
case RAX: return myregs.rax;
case RBX: return myregs.rbx;
case RCX: return myregs.rcx;
case RDX: return myregs.rdx;
//Index registers
case RSI: return myregs.rsi;
case RDI: return myregs.rdi;
//Base pointer and stack pointer
case RBP: return myregs.rbp;
case RSP: return myregs.rsp;
//New 64 bit mode registers
case R8: return myregs.r8;
case R9: return myregs.r9;
case R10: return myregs.r10;
case R11: return myregs.r11;
case R12: return myregs.r12;
case R13: return myregs.r13;
case R14: return myregs.r14;
case R15: return myregs.r15;
//Segmentation registers
case CS: return myregs.cs;
case DS: return myregs.ds;
case ES: return myregs.es;
case FS: return myregs.fs;
case GS: return myregs.gs;
case SS: return myregs.ss;
case FS_BASE: return myregs.fs_base;
case GS_BASE: return myregs.gs_base;
//PC
case RIP: return myregs.rip;
//Flags
case EFLAGS: return myregs.eflags;
//MMX
case MMX0_0: return myfpregs.st_space[0];
case MMX0_1: return myfpregs.st_space[1];
case MMX1_0: return myfpregs.st_space[2];
case MMX1_1: return myfpregs.st_space[3];
case MMX2_0: return myfpregs.st_space[4];
case MMX2_1: return myfpregs.st_space[5];
case MMX3_0: return myfpregs.st_space[6];
case MMX3_1: return myfpregs.st_space[7];
case MMX4_0: return myfpregs.st_space[8];
case MMX4_1: return myfpregs.st_space[9];
case MMX5_0: return myfpregs.st_space[10];
case MMX5_1: return myfpregs.st_space[11];
case MMX6_0: return myfpregs.st_space[12];
case MMX6_1: return myfpregs.st_space[13];
case MMX7_0: return myfpregs.st_space[14];
case MMX7_1: return myfpregs.st_space[15];
//XMM
case XMM0_0: return myfpregs.xmm_space[0];
case XMM0_1: return myfpregs.xmm_space[1];
case XMM0_2: return myfpregs.xmm_space[2];
case XMM0_3: return myfpregs.xmm_space[3];
case XMM1_0: return myfpregs.xmm_space[4];
case XMM1_1: return myfpregs.xmm_space[5];
case XMM1_2: return myfpregs.xmm_space[6];
case XMM1_3: return myfpregs.xmm_space[7];
case XMM2_0: return myfpregs.xmm_space[8];
case XMM2_1: return myfpregs.xmm_space[9];
case XMM2_2: return myfpregs.xmm_space[10];
case XMM2_3: return myfpregs.xmm_space[11];
case XMM3_0: return myfpregs.xmm_space[12];
case XMM3_1: return myfpregs.xmm_space[13];
case XMM3_2: return myfpregs.xmm_space[14];
case XMM3_3: return myfpregs.xmm_space[15];
case XMM4_0: return myfpregs.xmm_space[16];
case XMM4_1: return myfpregs.xmm_space[17];
case XMM4_2: return myfpregs.xmm_space[18];
case XMM4_3: return myfpregs.xmm_space[19];
case XMM5_0: return myfpregs.xmm_space[20];
case XMM5_1: return myfpregs.xmm_space[21];
case XMM5_2: return myfpregs.xmm_space[22];
case XMM5_3: return myfpregs.xmm_space[23];
case XMM6_0: return myfpregs.xmm_space[24];
case XMM6_1: return myfpregs.xmm_space[25];
case XMM6_2: return myfpregs.xmm_space[26];
case XMM6_3: return myfpregs.xmm_space[27];
case XMM7_0: return myfpregs.xmm_space[28];
case XMM7_1: return myfpregs.xmm_space[29];
case XMM7_2: return myfpregs.xmm_space[30];
case XMM7_3: return myfpregs.xmm_space[31];
case XMM8_0: return myfpregs.xmm_space[32];
case XMM8_1: return myfpregs.xmm_space[33];
case XMM8_2: return myfpregs.xmm_space[34];
case XMM8_3: return myfpregs.xmm_space[35];
case XMM9_0: return myfpregs.xmm_space[36];
case XMM9_1: return myfpregs.xmm_space[37];
case XMM9_2: return myfpregs.xmm_space[38];
case XMM9_3: return myfpregs.xmm_space[39];
case XMM10_0: return myfpregs.xmm_space[40];
case XMM10_1: return myfpregs.xmm_space[41];
case XMM10_2: return myfpregs.xmm_space[42];
case XMM10_3: return myfpregs.xmm_space[43];
case XMM11_0: return myfpregs.xmm_space[44];
case XMM11_1: return myfpregs.xmm_space[45];
case XMM11_2: return myfpregs.xmm_space[46];
case XMM11_3: return myfpregs.xmm_space[47];
case XMM12_0: return myfpregs.xmm_space[48];
case XMM12_1: return myfpregs.xmm_space[49];
case XMM12_2: return myfpregs.xmm_space[50];
case XMM12_3: return myfpregs.xmm_space[51];
case XMM13_0: return myfpregs.xmm_space[52];
case XMM13_1: return myfpregs.xmm_space[53];
case XMM13_2: return myfpregs.xmm_space[54];
case XMM13_3: return myfpregs.xmm_space[55];
case XMM14_0: return myfpregs.xmm_space[56];
case XMM14_1: return myfpregs.xmm_space[57];
case XMM14_2: return myfpregs.xmm_space[58];
case XMM14_3: return myfpregs.xmm_space[59];
case XMM15_0: return myfpregs.xmm_space[60];
case XMM15_1: return myfpregs.xmm_space[61];
case XMM15_2: return myfpregs.xmm_space[62];
case XMM15_3: return myfpregs.xmm_space[63];
default:
assert(0);
return 0;
}
}
bool
AMD64TraceChild::update(int pid)
{
oldregs = regs;
oldfpregs = fpregs;
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0) {
cerr << "update: " << strerror(errno) << endl;
return false;
}
if (ptrace(PTRACE_GETFPREGS, pid, 0, &fpregs) != 0) {
cerr << "update: " << strerror(errno) << endl;
return false;
}
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
return true;
}
AMD64TraceChild::AMD64TraceChild()
{
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = false;
}
int64_t
AMD64TraceChild::getRegVal(int num)
{
return getRegs(regs, fpregs, num);
}
int64_t
AMD64TraceChild::getOldRegVal(int num)
{
return getRegs(oldregs, oldfpregs, num);
}
ostream &
AMD64TraceChild::outputStartState(ostream & os)
{
uint64_t sp = getSP();
uint64_t pc = getPC();
uint64_t highestInfo = 0;
char obuf[1024];
sprintf(obuf, "Initial stack pointer = 0x%016lx\n", sp);
os << obuf;
sprintf(obuf, "Initial program counter = 0x%016lx\n", pc);
os << obuf;
//Output the argument count
uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%016lx: Argc = 0x%016lx\n", sp, cargc);
os << obuf;
sp += 8;
//Output argv pointers
int argCount = 0;
uint64_t cargv;
do {
cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%016lx: argv[%d] = 0x%016lx\n",
sp, argCount++, cargv);
if (cargv)
if (highestInfo < cargv)
highestInfo = cargv;
os << obuf;
sp += 8;
} while(cargv);
//Output the envp pointers
int envCount = 0;
uint64_t cenvp;
do {
cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%016lx: envp[%d] = 0x%016lx\n",
sp, envCount++, cenvp);
os << obuf;
sp += 8;
} while(cenvp);
uint64_t auxType, auxVal;
do {
auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sp += 8;
auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sp += 8;
sprintf(obuf, "0x%016lx: Auxiliary vector = {0x%016lx, 0x%016lx}\n",
sp - 16, auxType, auxVal);
os << obuf;
} while(auxType != 0 || auxVal != 0);
//Print out the argument strings, environment strings, and file name.
string current;
uint64_t buf;
uint64_t currentStart = sp;
bool clearedInitialPadding = false;
do {
buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
char * cbuf = (char *)&buf;
for (int x = 0; x < sizeof(uint64_t); x++) {
if (cbuf[x])
current += cbuf[x];
else {
sprintf(obuf, "0x%016lx: \"%s\"\n",
currentStart, current.c_str());
os << obuf;
current = "";
currentStart = sp + x + 1;
}
}
sp += 8;
clearedInitialPadding = clearedInitialPadding || buf != 0;
} while (!clearedInitialPadding || buf != 0 || sp <= highestInfo);
return os;
}
uint64_t
AMD64TraceChild::findSyscall()
{
uint64_t rip = getPC();
bool foundOpcode = false;
bool twoByteOpcode = false;
for (;;) {
uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0);
for (int i = 0; i < sizeof(uint64_t); i++) {
unsigned char byte = buf & 0xFF;
if (!foundOpcode) {
if(!(byte == 0x66 || //operand override
byte == 0x67 || //address override
byte == 0x2E || //cs
byte == 0x3E || //ds
byte == 0x26 || //es
byte == 0x64 || //fs
byte == 0x65 || //gs
byte == 0x36 || //ss
byte == 0xF0 || //lock
byte == 0xF2 || //repe
byte == 0xF3 || //repne
(byte >= 0x40 && byte <= 0x4F) // REX
)) {
foundOpcode = true;
}
}
if (foundOpcode) {
if (twoByteOpcode) {
//SYSCALL or SYSENTER
if (byte == 0x05 || byte == 0x34)
return rip + 1;
else
return 0;
}
if (!twoByteOpcode) {
if (byte == 0xCC) // INT3
return rip + 1;
else if (byte == 0xCD) // INT with byte immediate
return rip + 2;
else if (byte == 0x0F) // two byte opcode prefix
twoByteOpcode = true;
else
return 0;
}
}
buf >>= 8;
rip++;
}
}
}
bool
AMD64TraceChild::step()
{
uint64_t ripAfterSyscall = findSyscall();
if (ripAfterSyscall) {
//Get the original contents of memory
uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0);
//Patch the first two bytes of the memory immediately after this with
//jmp -2. Either single stepping will take over before this
//instruction, leaving the rip where it should be, or it will take
//over after this instruction, -still- leaving the rip where it should
//be.
uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB;
//Write the patched memory to the processes address space
ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf);
//Step and hit it
ptraceSingleStep();
//Put things back to the way they started
ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf);
} else {
//Get all the way past repe and repne string instructions in one shot.
uint64_t newPC, origPC = getPC();
do {
ptraceSingleStep();
newPC = getPC();
} while(newPC == origPC);
}
}
TraceChild * genTraceChild()
{
return new AMD64TraceChild;
}

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2007 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: Gabe Black
*/
#ifndef REGSTATE_AMD64_HH
#define REGSTATE_AMD64_HH
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
#include <cassert>
#include <string>
#include "base/tracechild.hh"
class AMD64TraceChild : public TraceChild
{
public:
enum RegNum
{
//GPRs
RAX, RCX, RDX, RBX,
//Base pointer and stack pointer
RSP, RBP,
//Index registers
RSI, RDI,
//New 64 bit mode registers
R8, R9, R10, R11, R12, R13, R14, R15,
//Segmentation registers
CS, DS, ES, FS, GS, SS, FS_BASE, GS_BASE,
//PC
RIP,
//Flags
EFLAGS,
//MMX
MMX0_0, MMX0_1,
MMX1_0, MMX1_1,
MMX2_0, MMX2_1,
MMX3_0, MMX3_1,
MMX4_0, MMX4_1,
MMX5_0, MMX5_1,
MMX6_0, MMX6_1,
MMX7_0, MMX7_1,
//XMM
XMM0_0, XMM0_1, XMM0_2, XMM0_3,
XMM1_0, XMM1_1, XMM1_2, XMM1_3,
XMM2_0, XMM2_1, XMM2_2, XMM2_3,
XMM3_0, XMM3_1, XMM3_2, XMM3_3,
XMM4_0, XMM4_1, XMM4_2, XMM4_3,
XMM5_0, XMM5_1, XMM5_2, XMM5_3,
XMM6_0, XMM6_1, XMM6_2, XMM6_3,
XMM7_0, XMM7_1, XMM7_2, XMM7_3,
XMM8_0, XMM8_1, XMM8_2, XMM8_3,
XMM9_0, XMM9_1, XMM9_2, XMM9_3,
XMM10_0, XMM10_1, XMM10_2, XMM10_3,
XMM11_0, XMM11_1, XMM11_2, XMM11_3,
XMM12_0, XMM12_1, XMM12_2, XMM12_3,
XMM13_0, XMM13_1, XMM13_2, XMM13_3,
XMM14_0, XMM14_1, XMM14_2, XMM14_3,
XMM15_0, XMM15_1, XMM15_2, XMM15_3,
numregs
};
private:
int64_t getRegs(user_regs_struct & myregs,
user_fpregs_struct &myfpregs,int num);
user_regs_struct regs;
user_regs_struct oldregs;
user_fpregs_struct fpregs;
user_fpregs_struct oldfpregs;
bool regDiffSinceUpdate[numregs];
uint64_t findSyscall();
protected:
bool update(int pid);
public:
AMD64TraceChild();
bool sendState(int socket);
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
uint64_t getPC() {return getRegVal(RIP);}
uint64_t getSP() {return getRegVal(RSP);}
std::ostream & outputStartState(std::ostream & output);
bool step();
};
#endif

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2006-2009 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: Ali Saidi
* Gabe Black
*/
#include <stdint.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <iostream>
#include "arch/arm/tracechild.hh"
using namespace std;
ARMTraceChild::ARMTraceChild()
{
foundMvn = false;
memset(&regs, 0, sizeof(regs));
memset(&oldregs, 0, sizeof(regs));
memset(&fpregs, 0, sizeof(vfp_regs));
memset(&oldfpregs, 0, sizeof(vfp_regs));
for (int x = 0; x < numregs; x++) {
regDiffSinceUpdate[x] = false;
}
assert(sizeof(regs.uregs)/sizeof(regs.uregs[0]) > CPSR);
}
bool
ARMTraceChild::sendState(int socket)
{
uint32_t regVal = 0;
uint64_t message[numregs + 1];
int pos = 1;
message[0] = 0;
for (int x = 0; x < numregs; x++) {
if (regDiffSinceUpdate[x]) {
message[0] = message[0] | (1ULL << x);
message[pos++] = getRegVal(x);
}
}
size_t sent = 0;
size_t toSend = pos * sizeof(message[0]);
uint8_t *messagePtr = (uint8_t *)message;
while (toSend != 0) {
sent = write(socket, messagePtr, toSend);
if (sent == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
toSend -= sent;
messagePtr += sent;
}
return true;
}
uint32_t
ARMTraceChild::getRegs(user_regs &myregs, int num)
{
assert(num <= CPSR && num >= 0);
return myregs.uregs[num];
}
uint64_t
ARMTraceChild::getFpRegs(vfp_regs &my_fp_regs, int num)
{
assert(num >= F0 && num < numregs);
if (num == FPSCR)
return my_fp_regs.fpscr;
num -= F0;
return my_fp_regs.fpregs[num];
}
bool
ARMTraceChild::update(int pid)
{
oldregs = regs;
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0) {
cerr << "update: " << strerror(errno) << endl;
return false;
}
const uint32_t get_vfp_regs = 32;
oldfpregs = fpregs;
if (ptrace((__ptrace_request)get_vfp_regs, pid, 0, &fpregs) != 0) {
cerr << "update: " << strerror(errno) << endl;
return false;
}
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
return true;
}
int64_t
ARMTraceChild::getRegVal(int num)
{
if (num <= CPSR)
return getRegs(regs, num);
else
return (int64_t)getFpRegs(fpregs, num);
}
int64_t
ARMTraceChild::getOldRegVal(int num)
{
if (num <= CPSR)
return getRegs(oldregs, num);
else
return (int64_t)getFpRegs(oldfpregs, num);
}
ostream &
ARMTraceChild::outputStartState(ostream & os)
{
uint32_t sp = getSP();
uint32_t pc = getPC();
uint32_t highestInfo = 0;
char obuf[1024];
sprintf(obuf, "Initial stack pointer = 0x%08x\n", sp);
os << obuf;
sprintf(obuf, "Initial program counter = 0x%08x\n", pc);
os << obuf;
//Output the argument count
int32_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%08x: Argc = 0x%08x\n", sp, cargc);
os << obuf;
sp += 4;
//Output argv pointers
int argCount = 0;
int32_t cargv;
do {
cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%08x: argv[%d] = 0x%08x\n",
sp, argCount++, cargv);
if(cargv)
if(highestInfo < cargv)
highestInfo = cargv;
os << obuf;
sp += 4;
} while(cargv);
//Output the envp pointers
int envCount = 0;
uint32_t cenvp;
do {
cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sprintf(obuf, "0x%08x: envp[%d] = 0x%08x\n",
sp, envCount++, cenvp);
os << obuf;
sp += 4;
} while(cenvp);
uint32_t auxType, auxVal;
do {
auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sp += 4;
auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
sp += 4;
sprintf(obuf, "0x%08x: Auxiliary vector = {0x%08x, 0x%08x}\n",
sp - 8, auxType, auxVal);
os << obuf;
} while(auxType != 0 || auxVal != 0);
//Print out the argument strings, environment strings, and file name.
string current;
uint32_t buf;
uint32_t currentStart = sp;
bool clearedInitialPadding = false;
do {
buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
char * cbuf = (char *)&buf;
for (int x = 0; x < sizeof(uint32_t); x++) {
if (cbuf[x])
current += cbuf[x];
else {
sprintf(obuf, "0x%08x: \"%s\"\n",
currentStart, current.c_str());
os << obuf;
current = "";
currentStart = sp + x + 1;
}
}
sp += 4;
clearedInitialPadding = clearedInitialPadding || buf != 0;
} while(!clearedInitialPadding || buf != 0 || sp <= highestInfo);
return os;
}
bool
ARMTraceChild::step()
{
const uint32_t bkpt_inst = 0xe7f001f0;
uint32_t lr = getRegVal(14);
uint32_t pc = getPC();
uint32_t lrOp, subsOp;
char obuf[128];
bool patch = false;
// Since ARM uses software breakpoints behind the scenes, they don't work
// in read only areas like the page of routines provided by the kernel. The
// link register generally holds the address the process wants to the
// kernel to return to after it's done, so we'll install a software
// breakpoint there.
//
// Calls into the kernel user page always follow the form:
// MVN ...
// <possible MOV lr,...>
// SUB PC, ...
//
// So we look for this pattern and set a breakpoint on the LR at the SUB
// instruction.
subsOp = ptrace(PTRACE_PEEKDATA, pid, pc, 0);
if ((subsOp & 0xFFFF0FFF) == 0xe3e00a0f)
foundMvn = true;
if (foundMvn && ((subsOp & 0xFFF0F000) == 0xe240f000)) {
foundMvn = false;
lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0);
ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst);
patch = true;
}
ptraceSingleStep();
if (patch)
ptrace(PTRACE_POKEDATA, pid, lr, lrOp);
}
TraceChild *
genTraceChild()
{
return new ARMTraceChild;
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2009 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: Ali Saidi
* Gabe Black
*/
#ifndef TRACECHILD_ARM_HH
#define TRACECHILD_ARM_HH
#include <sys/ptrace.h>
#include <sys/user.h>
#include <cassert>
#include <string>
#include "base/tracechild.hh"
class ARMTraceChild : public TraceChild
{
public:
enum RegNum
{
// r0 - r3 argument, temp, caller save
// r4 - r10 callee save
// r11 - FP
// r12 - temp
// r13 - stack
// r14 - link
// r15 - pc
R0, R1, R2, R3, R4, R5, R6, R7,
R8, R9, R10, FP, R12, SP, LR, PC,
CPSR,
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,
F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29,
F30, F31, FPSCR,
numregs
};
struct vfp_regs {
uint64_t fpregs[32];
uint32_t fpscr;
};
private:
uint32_t getRegs(user_regs& myregs, int num);
uint64_t getFpRegs(vfp_regs &myfpregs, int num);
user_regs regs;
user_regs oldregs;
vfp_regs fpregs;
vfp_regs oldfpregs;
bool regDiffSinceUpdate[numregs];
bool foundMvn;
protected:
bool update(int pid);
public:
ARMTraceChild();
bool sendState(int socket);
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
bool step();
uint64_t
getPC()
{
return getRegVal(PC);
}
uint64_t
getSP()
{
return getRegVal(SP);
}
std::ostream & outputStartState(std::ostream & os);
};
#endif

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2006 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: Gabe Black
*/
#include <sys/ptrace.h>
#include <stdint.h>
#include <cerrno>
#include <iostream>
#include "arch/i686/tracechild.hh"
using namespace std;
int64_t
I686TraceChild::getRegs(user_regs_struct & myregs, int num)
{
assert(num < numregs && num >= 0);
switch (num) {
//GPRs
case EAX: return myregs.eax;
case EBX: return myregs.ebx;
case ECX: return myregs.ecx;
case EDX: return myregs.edx;
//Index registers
case ESI: return myregs.esi;
case EDI: return myregs.edi;
//Base pointer and stack pointer
case EBP: return myregs.ebp;
case ESP: return myregs.esp;
//Segmentation registers
case CS: return myregs.xcs;
case DS: return myregs.xds;
case ES: return myregs.xes;
case FS: return myregs.xfs;
case GS: return myregs.xgs;
case SS: return myregs.xss;
//PC
case EIP: return myregs.eip;
default:
assert(0);
return 0;
}
}
bool
I686TraceChild::update(int pid)
{
oldregs = regs;
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0)
return false;
for (unsigned int x = 0; x < numregs; x++) {
regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
}
}
I686TraceChild::I686TraceChild()
{
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = false;
}
int64_t
I686TraceChild::getRegVal(int num)
{
return getRegs(regs, num);
}
int64_t
I686TraceChild::getOldRegVal(int num)
{
return getRegs(oldregs, num);
}
bool
I686TraceChild::sendState(int socket)
{
return false;
}
TraceChild *
genTraceChild()
{
return new I686TraceChild;
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2006 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: Gabe Black
*/
#ifndef REGSTATE_I686_HH
#define REGSTATE_I686_HH
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
#include <cassert>
#include <string>
#include "base/tracechild.hh"
class I686TraceChild : public TraceChild
{
public:
enum RegNum
{
//GPRs
EAX, EBX, ECX, EDX,
//Index registers
ESI, EDI,
//Base pointer and stack pointer
EBP, ESP,
//Segmentation registers
CS, DS, ES, FS, GS, SS,
//PC
EIP,
numregs
};
private:
int64_t getRegs(user_regs_struct & myregs, int num);
user_regs_struct regs;
user_regs_struct oldregs;
bool regDiffSinceUpdate[numregs];
protected:
bool update(int pid);
public:
I686TraceChild();
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
uint64_t getPC() {return getRegVal(EIP);}
uint64_t getSP() {return getRegVal(ESP);}
bool sendState(int socket);
std::ostream &
outputStartState(std::ostream & output)
{
output << "Printing i686 initial state not yet implemented"
<< std::endl;
return output;
}
};
#endif

View File

@ -0,0 +1,473 @@
/*
* Copyright (c) 2006-2007 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: Gabe Black
*/
#include <sys/ptrace.h>
#include <stdint.h>
#include <cerrno>
#include <iostream>
#include "arch/sparc/tracechild.hh"
using namespace std;
bool
SparcTraceChild::sendState(int socket)
{
uint64_t regVal = 0;
for (int x = 0; x <= I7; x++) {
regVal = getRegVal(x);
if (write(socket, &regVal, sizeof(regVal)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
}
regVal = getRegVal(PC);
if (write(socket, &regVal, sizeof(regVal)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
regVal = getRegVal(NPC);
if (write(socket, &regVal, sizeof(regVal)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
regVal = getRegVal(CCR);
if (write(socket, &regVal, sizeof(regVal)) == -1) {
cerr << "Write failed! " << strerror(errno) << endl;
tracing = false;
return false;
}
return true;
}
int64_t
getRegs(regs & myregs, fpu & myfpu, uint64_t * locals,
uint64_t * inputs, int num)
{
assert(num < SparcTraceChild::numregs && num >= 0);
switch (num) {
//Global registers
case SparcTraceChild::G0: return 0;
case SparcTraceChild::G1: return myregs.r_g1;
case SparcTraceChild::G2: return myregs.r_g2;
case SparcTraceChild::G3: return myregs.r_g3;
case SparcTraceChild::G4: return myregs.r_g4;
case SparcTraceChild::G5: return myregs.r_g5;
case SparcTraceChild::G6: return myregs.r_g6;
case SparcTraceChild::G7: return myregs.r_g7;
//Output registers
case SparcTraceChild::O0: return myregs.r_o0;
case SparcTraceChild::O1: return myregs.r_o1;
case SparcTraceChild::O2: return myregs.r_o2;
case SparcTraceChild::O3: return myregs.r_o3;
case SparcTraceChild::O4: return myregs.r_o4;
case SparcTraceChild::O5: return myregs.r_o5;
case SparcTraceChild::O6: return myregs.r_o6;
case SparcTraceChild::O7: return myregs.r_o7;
//Local registers
case SparcTraceChild::L0: return locals[0];
case SparcTraceChild::L1: return locals[1];
case SparcTraceChild::L2: return locals[2];
case SparcTraceChild::L3: return locals[3];
case SparcTraceChild::L4: return locals[4];
case SparcTraceChild::L5: return locals[5];
case SparcTraceChild::L6: return locals[6];
case SparcTraceChild::L7: return locals[7];
//Input registers
case SparcTraceChild::I0: return inputs[0];
case SparcTraceChild::I1: return inputs[1];
case SparcTraceChild::I2: return inputs[2];
case SparcTraceChild::I3: return inputs[3];
case SparcTraceChild::I4: return inputs[4];
case SparcTraceChild::I5: return inputs[5];
case SparcTraceChild::I6: return inputs[6];
case SparcTraceChild::I7: return inputs[7];
//Floating point
case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0];
case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[1];
case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2];
case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3];
case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4];
case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5];
case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6];
case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7];
case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8];
case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9];
case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10];
case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11];
case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12];
case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13];
case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14];
case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15];
case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16];
case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17];
case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18];
case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19];
case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20];
case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21];
case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22];
case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23];
case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24];
case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25];
case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26];
case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27];
case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28];
case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29];
case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30];
case SparcTraceChild::F62: return myfpu.f_fpstatus.fpu_fr[31];
//Miscelaneous
case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr;
case SparcTraceChild::FPRS: return myregs.r_fprs;
case SparcTraceChild::PC: return myregs.r_tpc;
case SparcTraceChild::NPC: return myregs.r_tnpc;
case SparcTraceChild::Y: return myregs.r_y;
case SparcTraceChild::CWP:
return (myregs.r_tstate >> 0) & ((1 << 5) - 1);
case SparcTraceChild::PSTATE:
return (myregs.r_tstate >> 8) & ((1 << 13) - 1);
case SparcTraceChild::ASI:
return (myregs.r_tstate >> 24) & ((1 << 8) - 1);
case SparcTraceChild::CCR:
return (myregs.r_tstate >> 32) & ((1 << 8) - 1);
default:
assert(0);
return 0;
}
}
bool
SparcTraceChild::update(int pid)
{
memcpy(&oldregs, &theregs, sizeof(regs));
memcpy(&oldfpregs, &thefpregs, sizeof(fpu));
memcpy(oldLocals, locals, 8 * sizeof(uint64_t));
memcpy(oldInputs, inputs, 8 * sizeof(uint64_t));
if (ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0) {
cerr << "Update failed" << endl;
return false;
}
uint64_t stackPointer = getSP();
uint64_t stackBias = 2047;
bool v9 = stackPointer % 2;
for (unsigned int x = 0; x < 8; x++) {
uint64_t localAddr = stackPointer +
(v9 ? (stackBias + x * 8) : (x * 4));
locals[x] = ptrace(PTRACE_PEEKTEXT, pid, localAddr, 0);
if (!v9) locals[x] >>= 32;
uint64_t inputAddr = stackPointer +
(v9 ? (stackBias + x * 8 + (8 * 8)) : (x * 4 + 8 * 4));
inputs[x] = ptrace(PTRACE_PEEKTEXT, pid, inputAddr, 0);
if (!v9) inputs[x] >>= 32;
}
if (ptrace(PTRACE_GETFPREGS, pid, &thefpregs, 0) != 0)
return false;
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
return true;
}
SparcTraceChild::SparcTraceChild()
{
for (unsigned int x = 0; x < numregs; x++)
regDiffSinceUpdate[x] = false;
}
int
SparcTraceChild::getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
uint64_t &target1, uint64_t &target2)
{
//We can identify the instruction categories we care about using the top
//10 bits of the instruction, excluding the annul bit in the 3rd most
//significant bit position and the condition field. We'll call these
//bits the "sig" for signature.
uint32_t sig = (inst >> 22) & 0x307;
uint32_t cond = (inst >> 25) & 0xf;
bool annul = (inst & (1 << 29));
//Check if it's a ba...
bool ba = (cond == 0x8) &&
(sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
//or a bn...
bool bn = (cond == 0x0) &&
(sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
//or a bcc
bool bcc = (cond & 0x7) &&
(sig == 0x1 || sig == 0x2 || sig == 0x3 || sig == 0x5 || sig == 0x6);
if (annul) {
if (bcc) {
target1 = npc;
target2 = npc + 4;
return 2;
} else if(ba) {
//This branches immediately to the effective address of the branch
//which we'll have to calculate.
uint64_t disp = 0;
int64_t extender = 0;
//Figure out how big the displacement field is, and grab the bits
if (sig == 0x1 || sig == 0x5) {
disp = inst & ((1 << 19) - 1);
extender = 1 << 18;
} else {
disp = inst & ((1 << 22) - 1);
extender = 1 << 21;
}
//This does sign extension, believe it or not.
disp = (disp ^ extender) - extender;
//Multiply the displacement by 4. I'm assuming the compiler is
//smart enough to turn this into a shift.
disp *= 4;
target1 = pc + disp;
} else if(bn)
target1 = npc + 4;
else
target1 = npc;
return 1;
} else {
target1 = npc;
return 1;
}
}
bool
SparcTraceChild::step()
{
//Increment the count of the number of instructions executed
instructions++;
//Two important considerations are that the address of the instruction
//being breakpointed should be word (64bit) aligned, and that both the
//next instruction and the instruction after that need to be breakpointed
//so that annulled branches will still stop as well.
/*
* Useful constants
*/
const static uint64_t breakInst = 0x91d02001;
const static uint64_t lowBreakInst = breakInst;
const static uint64_t highBreakInst = breakInst << 32;
const static uint64_t breakWord = breakInst | (breakInst << 32);
const static uint64_t lowMask = 0xFFFFFFFFULL;
const static uint64_t highMask = lowMask << 32;
/*
* storage for the original contents of the child process's memory
*/
uint64_t originalInst, originalAnnulInst;
/*
* Get information about where the process is and is headed next.
*/
uint64_t currentPC = getRegVal(PC);
bool unalignedPC = currentPC & 7;
uint64_t alignedPC = currentPC & (~7);
uint64_t nextPC = getRegVal(NPC);
bool unalignedNPC = nextPC & 7;
uint64_t alignedNPC = nextPC & (~7);
//Get the current instruction
uint64_t curInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC);
curInst = unalignedPC ? (curInst & 0xffffffffULL) : (curInst >> 32);
uint64_t bp1, bp2;
int numTargets = getTargets(curInst, currentPC, nextPC, bp1, bp2);
assert(numTargets == 1 || numTargets == 2);
bool unalignedBp1 = bp1 & 7;
uint64_t alignedBp1 = bp1 & (~7);
bool unalignedBp2 = bp2 & 7;
uint64_t alignedBp2 = bp2 & (~7);
uint64_t origBp1, origBp2;
/*
* Set the first breakpoint
*/
origBp1 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp1, 0);
uint64_t newBp1 = origBp1;
newBp1 &= unalignedBp1 ? highMask : lowMask;
newBp1 |= unalignedBp1 ? lowBreakInst : highBreakInst;
if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, newBp1) != 0)
cerr << "Poke failed" << endl;
/*
* Set the second breakpoint if necessary
*/
if (numTargets == 2) {
origBp2 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp2, 0);
uint64_t newBp2 = origBp2;
newBp2 &= unalignedBp2 ? highMask : lowMask;
newBp2 |= unalignedBp2 ? lowBreakInst : highBreakInst;
if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, newBp2) != 0)
cerr << "Poke failed" << endl;
}
/*
* Restart the child process
*/
//Note that the "addr" parameter is supposed to be ignored, but in at
//least one version of the kernel, it must be 1 or it will set what
//pc to continue from
if (ptrace(PTRACE_CONT, pid, 1, 0) != 0)
cerr << "Cont failed" << endl;
doWait();
/*
* Update our record of the child's state
*/
update(pid);
/*
* Put back the original contents of the childs address space in the
* reverse order.
*/
if (numTargets == 2) {
if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, origBp2) != 0)
cerr << "Poke failed" << endl;
}
if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, origBp1) != 0)
cerr << "Poke failed" << endl;
}
int64_t
SparcTraceChild::getRegVal(int num)
{
return getRegs(theregs, thefpregs, locals, inputs, num);
}
int64_t
SparcTraceChild::getOldRegVal(int num)
{
return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num);
}
ostream &
SparcTraceChild::outputStartState(ostream & os)
{
bool v8 = false;
uint64_t sp = getSP();
if (sp % 2) {
os << "Detected a 64 bit executable.\n";
v8 = false;
} else {
os << "Detected a 32 bit executable.\n";
v8 = true;
}
uint64_t pc = getPC();
char obuf[1024];
sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
os << obuf;
sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
os << obuf;
if (!v8) {
//Take out the stack bias
sp += 2047;
}
//Output the window save area
for (unsigned int x = 0; x < 16; x++) {
uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) regspot = regspot >> 32;
sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n",
sp, x+1, regspot);
os << obuf;
sp += v8 ? 4 : 8;
}
//Output the argument count
uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) cargc = cargc >> 32;
sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
os << obuf;
sp += v8 ? 4 : 8;
//Output argv pointers
int argCount = 0;
uint64_t cargv;
do {
cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) cargv = cargv >> 32;
sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
sp, argCount++, cargv);
os << obuf;
sp += v8 ? 4 : 8;
} while(cargv);
//Output the envp pointers
int envCount = 0;
uint64_t cenvp;
do {
cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) cenvp = cenvp >> 32;
sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
sp, envCount++, cenvp);
os << obuf;
sp += v8 ? 4 : 8;
} while (cenvp);
uint64_t auxType, auxVal;
do {
auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) auxType = auxType >> 32;
sp += (v8 ? 4 : 8);
auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
if (v8) auxVal = auxVal >> 32;
sp += (v8 ? 4 : 8);
sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
sp - 8, auxType, auxVal);
os << obuf;
} while (auxType != 0 || auxVal != 0);
//Print out the argument strings, environment strings, and file name.
string current;
uint64_t buf;
uint64_t currentStart = sp;
bool clearedInitialPadding = false;
do {
buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
char * cbuf = (char *)&buf;
for (int x = 0; x < sizeof(uint32_t); x++) {
if (cbuf[x])
current += cbuf[x];
else {
sprintf(obuf, "0x%016llx: \"%s\"\n",
currentStart, current.c_str());
os << obuf;
current = "";
currentStart = sp + x + 1;
}
}
sp += (v8 ? 4 : 8);
clearedInitialPadding = clearedInitialPadding || buf != 0;
} while (!clearedInitialPadding || buf != 0);
return os;
}
TraceChild *
genTraceChild()
{
return new SparcTraceChild;
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2006-2007 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: Gabe Black
*/
#ifndef TRACECHILD_SPARC_HH
#define TRACECHILD_SPARC_HH
#include <asm-sparc64/reg.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <stdint.h>
#include <cassert>
#include <ostream>
#include <string>
#include "base/tracechild.hh"
struct regs;
class SparcTraceChild : public TraceChild
{
public:
enum RegNum
{
//Global registers
G0, G1, G2, G3, G4, G5, G6, G7,
//Output registers
O0, O1, O2, O3, O4, O5, O6, O7,
//Local registers
L0, L1, L2, L3, L4, L5, L6, L7,
//Input registers
I0, I1, I2, I3, I4, I5, I6, I7,
//Floating point
F0, F2, F4, F6, F8, F10, F12, F14,
F16, F18, F20, F22, F24, F26, F28, F30,
F32, F34, F36, F38, F40, F42, F44, F46,
F48, F50, F52, F54, F56, F58, F60, F62,
//Miscelaneous
FSR, FPRS, PC, NPC, Y, CWP, PSTATE, ASI, CCR,
numregs
};
private:
regs theregs;
regs oldregs;
fpu thefpregs;
fpu oldfpregs;
uint64_t locals[8];
uint64_t oldLocals[8];
uint64_t inputs[8];
uint64_t oldInputs[8];
bool regDiffSinceUpdate[numregs];
//This calculates where the pc might go after the current instruction.
//while this equals npc for most instructions, it doesn't for all of
//them. The return value is the number of actual potential targets.
int getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
uint64_t &target1, uint64_t &target2);
protected:
bool update(int pid);
public:
SparcTraceChild();
bool sendState(int socket);
int64_t getRegVal(int num);
int64_t getOldRegVal(int num);
bool step();
uint64_t
getPC()
{
return getRegVal(PC);
}
uint64_t
getSP()
{
return getRegVal(O6);
}
std::ostream & outputStartState(std::ostream & os);
};
#endif

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2006-2007 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: Gabe Black
*/
#if defined __STATETRACE_ALPHA__
#if !defined __alpha__
#error "Alpha toolchain required."
#endif
#elif defined __STATETRACE_AMD64__
#if !defined __amd64__
#error "Amd64 toolchain required."
#endif
#elif defined __STATETRACE_ARM__
#if !defined __arm__
#error "Arm toolchain required."
#endif
#elif defined __STATETRACE_HPPA__
#if !defined __hppa__
#error "Hppa toolchain required."
#endif
#elif defined __STATETRACE_I686__
#if !(defined __i386__ || defined __i486__ || \
defined __i586__ || defined __i686__)
#error "I686 toolchain required."
#endif
#elif defined __STATETRACE_IA64__
#if !defined __ia64__
#error "IA64 toolchain required."
#endif
#elif defined __STATETRACE_MIPS__
#if !defined __mips__
#error "Mips toolchain required."
#endif
#elif defined __STATETRACE_POWERPC__
#if !defined __powerpc__
#error "PowerPC toolchain required."
#endif
#elif defined __STATETRACE_SPARC__
#if !defined __sparc__
#error "Sparc toolchain required."
#endif
#elif defined __STATETRACE_SH__
#if !defined __sh__
#error "SuperH toolchain required."
#endif
#elif defined __STATETRACE__S390__
#if !defined __s390__
#error "System/390 toolchain required."
#endif
#else
#error "Couldn't determine architecture."
#endif

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2006 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: Gabe Black
*/
#ifndef REGSTATE_H
#define REGSTATE_H
#include <stdint.h>
#include <string>
class RegState
{
protected:
virtual bool update(int pid) = 0;
public:
virtual int64_t getRegVal(int num) = 0;
virtual int64_t getOldRegVal(int num) = 0;
};
#endif

View File

@ -0,0 +1,156 @@
/*
* Copyright (c) 2006-2007 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: Gabe Black
*/
#include <netinet/in.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netdb.h>
#include <unistd.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include "base/arch_check.h"
#include "tracechild.hh"
using namespace std;
void
printUsage(const char * execName)
{
cout << execName << " <options> -- <command> <arguments>" << endl;
cout << "options:" << endl;
cout << " -h print this help" << endl;
cout << " --host remote m5 host to connect to" << endl;
cout << " -i print initial stack state" << endl;
cout << " -nt don't trace execution" << endl;
}
int
main(int argc, char * argv[], char * envp[])
{
TraceChild * child = genTraceChild();
string args;
int startProgramArgs;
//Parse the command line arguments
bool printInitial = false;
bool printTrace = true;
string host = "localhost";
if (argc == 1) {
printUsage(argv[0]);
return 0;
}
for (int x = 1; x < argc; x++) {
if (!strcmp(argv[x], "-h")) {
printUsage(argv[0]);
return 0;
}
if (!strcmp(argv[x], "--host")) {
x++;
if (x >= argc) {
cerr << "Incorrect usage.\n" << endl;
printUsage(argv[0]);
return 1;
}
host = argv[x];
} else if (!strcmp(argv[x], "-i")) {
printInitial = true;
} else if (!strcmp(argv[x], "-nt")) {
printTrace = false;
} else if (!strcmp(argv[x], "--")) {
x++;
if (x >= argc) {
cerr << "Incorrect usage.\n" << endl;
printUsage(argv[0]);
return 1;
}
startProgramArgs = x;
break;
} else {
cerr << "Incorrect usage.\n" << endl;
printUsage(argv[0]);
return 1;
}
}
if (!child->startTracing(argv[startProgramArgs],
argv + startProgramArgs)) {
cerr << "Couldn't start target program" << endl;
return 1;
}
child->step();
if (printInitial)
child->outputStartState(cout);
if (printTrace) {
// Connect to m5
bool portSet = false;
int port;
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
cerr << "Error opening socket! " << strerror(errno) << endl;
return 1;
}
struct hostent *server;
server = gethostbyname(host.c_str());
if (!server) {
cerr << "Couldn't get host ip! " << strerror(errno) << endl;
return 1;
}
struct sockaddr_in serv_addr;
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(8000);
if (connect(sock, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
cerr << "Couldn't connect to server! " << strerror(errno) << endl;
return 1;
}
while (child->isTracing()) {
if (!child->sendState(sock))
break;
child->step();
}
}
if (!child->stopTracing()) {
cerr << "Couldn't stop child" << endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2006-2007 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: Gabe Black
*/
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <cerrno>
#include <cstring>
#include <iostream>
#include "tracechild.hh"
using namespace std;
bool
TraceChild::startTracing(const char * pathToFile, char * const argv[])
{
instructions = 0;
pid = fork();
if (pid == -1) {
cout << "fork failed" << endl;
return false;
} else if (pid == 0) {
//We're the child. Get things ready and then exec the program to trace.
//Let our parent trace us
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
cout << "Failure calling TRACEME\n" << strerror(errno) << endl;
return false;
}
//Set up an empty environment for the child... We would want to
//specify this somehow at some point
char * env[] = {NULL};
//Start the program to trace
execve(pathToFile, argv, env);
//We should never get here, so this is an error!
cout << "Exec failed\n" << strerror(errno) << endl;
return false;
}
//From this point forward, we know we're in the parent process.
if (!doWait()) {
cout << "Didn't wait successfully" << endl;
return false;
}
tracing = true;
return true;
}
bool
TraceChild::stopTracing()
{
if (ptrace(PTRACE_KILL, pid, 0, 0) != 0)
return false;
tracing = false;
return true;
}
bool
TraceChild::step()
{
ptraceSingleStep();
}
bool
TraceChild::ptraceSingleStep()
{
if (!tracing) {
cout << "Not tracing!" << endl;
return false;
}
if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0) != 0) {
switch (errno) {
case EBUSY: cout << "EBUSY" << endl; break;
case EFAULT: cout << "EFAULT" << endl; break;
case EIO: cout << "EIO" << endl; break;
case EPERM: cout << "EPERM" << endl; break;
case ESRCH: cout << "ESRCH" << endl; break;
default: cout << "Unknown error" << endl; break;
}
cout << "Not able to single step!" << endl;
tracing == false;
return false;
}
doWait();
update(pid);
}
bool
TraceChild::doWait()
{
int wait_val;
wait(&wait_val);
if (WIFEXITED(wait_val)) {
cerr << "Program exited! Exit status is "
<< WEXITSTATUS(wait_val) << endl;
cerr << "Executed " << instructions
<< " instructions." << endl;
tracing = false;
return false;
}
if (WIFSIGNALED(wait_val)) {
if (WTERMSIG(wait_val))
cerr << "Program terminated by signal "
<< WTERMSIG(wait_val) << endl;
if (WCOREDUMP(wait_val))
cerr << "Program core dumped!" << endl;
tracing = false;
cerr << "Executed " << instructions
<< " instructions." << endl;
return false;
}
if (WIFSTOPPED(wait_val) && WSTOPSIG(wait_val) != SIGTRAP) {
cerr << "Program stopped by signal " << WSTOPSIG(wait_val) << endl;
tracing = false;
cerr << "Executed " << instructions << " instructions." << endl;
return false;
}
return true;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2006-2007 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: Gabe Black
*/
#ifndef TRACECHILD_HH
#define TRACECHILD_HH
#include "base/regstate.hh"
class TraceChild : public RegState
{
protected:
int pid;
uint64_t instructions;
bool tracing;
public:
TraceChild() : tracing(false), instructions(0)
{;}
virtual bool sendState(int socket) = 0;
virtual bool startTracing(const char * pathToFile, char * const argv[]);
virtual bool stopTracing();
virtual bool step();
virtual std::ostream & outputStartState(std::ostream & os) = 0;
bool
isTracing()
{
return tracing;
}
protected:
bool ptraceSingleStep();
bool doWait();
};
TraceChild * genTraceChild();
#endif

View File

@ -0,0 +1,28 @@
# 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

View File

@ -0,0 +1,341 @@
# Copyright (c) 2005-2006 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
# Lisa Hsu
import matplotlib, pylab
from matplotlib.font_manager import FontProperties
from matplotlib.numerix import array, arange, reshape, shape, transpose, zeros
from matplotlib.numerix import Float
from matplotlib.ticker import NullLocator
matplotlib.interactive(False)
from chart import ChartOptions
class BarChart(ChartOptions):
def __init__(self, default=None, **kwargs):
super(BarChart, self).__init__(default, **kwargs)
self.inputdata = None
self.chartdata = None
self.inputerr = None
self.charterr = None
def gen_colors(self, count):
cmap = matplotlib.cm.get_cmap(self.colormap)
if count == 1:
return cmap([ 0.5 ])
if count < 5:
return cmap(arange(5) / float(4))[:count]
return cmap(arange(count) / float(count - 1))
# The input data format does not match the data format that the
# graph function takes because it is intuitive. The conversion
# from input data format to chart data format depends on the
# dimensionality of the input data. Check here for the
# dimensionality and correctness of the input data
def set_data(self, data):
if data is None:
self.inputdata = None
self.chartdata = None
return
data = array(data)
dim = len(shape(data))
if dim not in (1, 2, 3):
raise AttributeError, "Input data must be a 1, 2, or 3d matrix"
self.inputdata = data
# If the input data is a 1d matrix, then it describes a
# standard bar chart.
if dim == 1:
self.chartdata = array([[data]])
# If the input data is a 2d matrix, then it describes a bar
# chart with groups. The matrix being an array of groups of
# bars.
if dim == 2:
self.chartdata = transpose([data], axes=(2,0,1))
# If the input data is a 3d matrix, then it describes an array
# of groups of bars with each bar being an array of stacked
# values.
if dim == 3:
self.chartdata = transpose(data, axes=(1,2,0))
def get_data(self):
return self.inputdata
data = property(get_data, set_data)
def set_err(self, err):
if err is None:
self.inputerr = None
self.charterr = None
return
err = array(err)
dim = len(shape(err))
if dim not in (1, 2, 3):
raise AttributeError, "Input err must be a 1, 2, or 3d matrix"
self.inputerr = err
if dim == 1:
self.charterr = array([[err]])
if dim == 2:
self.charterr = transpose([err], axes=(2,0,1))
if dim == 3:
self.charterr = transpose(err, axes=(1,2,0))
def get_err(self):
return self.inputerr
err = property(get_err, set_err)
# Graph the chart data.
# Input is a 3d matrix that describes a plot that has multiple
# groups, multiple bars in each group, and multiple values stacked
# in each bar. The underlying bar() function expects a sequence of
# bars in the same stack location and same group location, so the
# organization of the matrix is that the inner most sequence
# represents one of these bar groups, then those are grouped
# together to make one full stack of bars in each group, and then
# the outer most layer describes the groups. Here is an example
# data set and how it gets plotted as a result.
#
# e.g. data = [[[10,11,12], [13,14,15], [16,17,18], [19,20,21]],
# [[22,23,24], [25,26,27], [28,29,30], [31,32,33]]]
#
# will plot like this:
#
# 19 31 20 32 21 33
# 16 28 17 29 18 30
# 13 25 14 26 15 27
# 10 22 11 23 12 24
#
# Because this arrangement is rather conterintuitive, the rearrange
# function takes various matricies and arranges them to fit this
# profile.
#
# This code deals with one of the dimensions in the matrix being
# one wide.
#
def graph(self):
if self.chartdata is None:
raise AttributeError, "Data not set for bar chart!"
dim = len(shape(self.inputdata))
cshape = shape(self.chartdata)
if self.charterr is not None and shape(self.charterr) != cshape:
raise AttributeError, 'Dimensions of error and data do not match'
if dim == 1:
colors = self.gen_colors(cshape[2])
colors = [ [ colors ] * cshape[1] ] * cshape[0]
if dim == 2:
colors = self.gen_colors(cshape[0])
colors = [ [ [ c ] * cshape[2] ] * cshape[1] for c in colors ]
if dim == 3:
colors = self.gen_colors(cshape[1])
colors = [ [ [ c ] * cshape[2] for c in colors ] ] * cshape[0]
colors = array(colors)
self.figure = pylab.figure(figsize=self.chart_size)
outer_axes = None
inner_axes = None
if self.xsubticks is not None:
color = self.figure.get_facecolor()
self.metaaxes = self.figure.add_axes(self.figure_size,
axisbg=color, frameon=False)
for tick in self.metaaxes.xaxis.majorTicks:
tick.tick1On = False
tick.tick2On = False
self.metaaxes.set_yticklabels([])
self.metaaxes.set_yticks([])
size = [0] * 4
size[0] = self.figure_size[0]
size[1] = self.figure_size[1] + .12
size[2] = self.figure_size[2]
size[3] = self.figure_size[3] - .12
self.axes = self.figure.add_axes(size)
outer_axes = self.metaaxes
inner_axes = self.axes
else:
self.axes = self.figure.add_axes(self.figure_size)
outer_axes = self.axes
inner_axes = self.axes
bars_in_group = len(self.chartdata)
width = 1.0 / ( bars_in_group + 1)
center = width / 2
bars = []
for i,stackdata in enumerate(self.chartdata):
bottom = array([0.0] * len(stackdata[0]), Float)
stack = []
for j,bardata in enumerate(stackdata):
bardata = array(bardata)
ind = arange(len(bardata)) + i * width + center
yerr = None
if self.charterr is not None:
yerr = self.charterr[i][j]
bar = self.axes.bar(ind, bardata, width, bottom=bottom,
color=colors[i][j], yerr=yerr)
if self.xsubticks is not None:
self.metaaxes.bar(ind, [0] * len(bardata), width)
stack.append(bar)
bottom += bardata
bars.append(stack)
if self.xlabel is not None:
outer_axes.set_xlabel(self.xlabel)
if self.ylabel is not None:
inner_axes.set_ylabel(self.ylabel)
if self.yticks is not None:
ymin, ymax = self.axes.get_ylim()
nticks = float(len(self.yticks))
ticks = arange(nticks) / (nticks - 1) * (ymax - ymin) + ymin
inner_axes.set_yticks(ticks)
inner_axes.set_yticklabels(self.yticks)
elif self.ylim is not None:
inner_axes.set_ylim(self.ylim)
if self.xticks is not None:
outer_axes.set_xticks(arange(cshape[2]) + .5)
outer_axes.set_xticklabels(self.xticks)
if self.xsubticks is not None:
numticks = (cshape[0] + 1) * cshape[2]
inner_axes.set_xticks(arange(numticks) * width + 2 * center)
xsubticks = list(self.xsubticks) + [ '' ]
inner_axes.set_xticklabels(xsubticks * cshape[2], fontsize=7,
rotation=30)
if self.legend is not None:
if dim == 1:
lbars = bars[0][0]
if dim == 2:
lbars = [ bars[i][0][0] for i in xrange(len(bars))]
if dim == 3:
number = len(bars[0])
lbars = [ bars[0][number - j - 1][0] for j in xrange(number)]
if self.fig_legend:
self.figure.legend(lbars, self.legend, self.legend_loc,
prop=FontProperties(size=self.legend_size))
else:
self.axes.legend(lbars, self.legend, self.legend_loc,
prop=FontProperties(size=self.legend_size))
if self.title is not None:
self.axes.set_title(self.title)
def savefig(self, name):
self.figure.savefig(name)
def savecsv(self, name):
f = file(name, 'w')
data = array(self.inputdata)
dim = len(data.shape)
if dim == 1:
#if self.xlabel:
# f.write(', '.join(list(self.xlabel)) + '\n')
f.write(', '.join([ '%f' % val for val in data]) + '\n')
if dim == 2:
#if self.xlabel:
# f.write(', '.join([''] + list(self.xlabel)) + '\n')
for i,row in enumerate(data):
ylabel = []
#if self.ylabel:
# ylabel = [ self.ylabel[i] ]
f.write(', '.join(ylabel + [ '%f' % v for v in row]) + '\n')
if dim == 3:
f.write("don't do 3D csv files\n")
pass
f.close()
if __name__ == '__main__':
from random import randrange
import random, sys
dim = 3
number = 5
args = sys.argv[1:]
if len(args) > 3:
sys.exit("invalid number of arguments")
elif len(args) > 0:
myshape = [ int(x) for x in args ]
else:
myshape = [ 3, 4, 8 ]
# generate a data matrix of the given shape
size = reduce(lambda x,y: x*y, myshape)
#data = [ random.randrange(size - i) + 10 for i in xrange(size) ]
data = [ float(i)/100.0 for i in xrange(size) ]
data = reshape(data, myshape)
# setup some test bar charts
if True:
chart1 = BarChart()
chart1.data = data
chart1.xlabel = 'Benchmark'
chart1.ylabel = 'Bandwidth (GBps)'
chart1.legend = [ 'x%d' % x for x in xrange(myshape[-1]) ]
chart1.xticks = [ 'xtick%d' % x for x in xrange(myshape[0]) ]
chart1.title = 'this is the title'
if len(myshape) > 2:
chart1.xsubticks = [ '%d' % x for x in xrange(myshape[1]) ]
chart1.graph()
chart1.savefig('/tmp/test1.png')
chart1.savefig('/tmp/test1.ps')
chart1.savefig('/tmp/test1.eps')
chart1.savecsv('/tmp/test1.csv')
if False:
chart2 = BarChart()
chart2.data = data
chart2.colormap = 'gray'
chart2.graph()
chart2.savefig('/tmp/test2.png')
chart2.savefig('/tmp/test2.ps')
# pylab.show()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
# Copyright (c) 2005-2006 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
# Lisa Hsu
class ChartOptions(object):
defaults = { 'chart_size' : (8, 4),
'figure_size' : [0.1, 0.1, 0.6, 0.85],
'title' : None,
'fig_legend' : True,
'legend' : None,
'legend_loc' : 'upper right',
'legend_size' : 6,
'colormap' : 'jet',
'xlabel' : None,
'ylabel' : None,
'xticks' : None,
'xsubticks' : None,
'yticks' : None,
'ylim' : None,
}
def __init__(self, options=None, **kwargs):
self.init(options, **kwargs)
def clear(self):
self.options = {}
def init(self, options=None, **kwargs):
self.clear()
self.update(options, **kwargs)
def update(self, options=None, **kwargs):
if options is not None:
if not isinstance(options, ChartOptions):
raise AttributeError, \
'attribute options of type %s should be %s' % \
(type(options), ChartOptions)
self.options.update(options.options)
for key,value in kwargs.iteritems():
if key not in ChartOptions.defaults:
raise AttributeError, \
"%s instance has no attribute '%s'" % (type(self), key)
self.options[key] = value
def __getattr__(self, attr):
if attr in self.options:
return self.options[attr]
if attr in ChartOptions.defaults:
return ChartOptions.defaults[attr]
raise AttributeError, \
"%s instance has no attribute '%s'" % (type(self), attr)
def __setattr__(self, attr, value):
if attr in ChartOptions.defaults:
self.options[attr] = value
else:
super(ChartOptions, self).__setattr__(attr, value)

View File

@ -0,0 +1,436 @@
# Copyright (c) 2003-2004 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
import MySQLdb, re, string
def statcmp(a, b):
v1 = a.split('.')
v2 = b.split('.')
last = min(len(v1), len(v2)) - 1
for i,j in zip(v1[0:last], v2[0:last]):
if i != j:
return cmp(i, j)
# Special compare for last element.
if len(v1) == len(v2):
return cmp(v1[last], v2[last])
else:
return cmp(len(v1), len(v2))
class RunData:
def __init__(self, row):
self.run = int(row[0])
self.name = row[1]
self.user = row[2]
self.project = row[3]
class SubData:
def __init__(self, row):
self.stat = int(row[0])
self.x = int(row[1])
self.y = int(row[2])
self.name = row[3]
self.descr = row[4]
class Data:
def __init__(self, row):
if len(row) != 5:
raise 'stat db error'
self.stat = int(row[0])
self.run = int(row[1])
self.x = int(row[2])
self.y = int(row[3])
self.data = float(row[4])
def __repr__(self):
return '''Data(['%d', '%d', '%d', '%d', '%f'])''' % ( self.stat,
self.run, self.x, self.y, self.data)
class StatData(object):
def __init__(self, row):
self.stat = int(row[0])
self.name = row[1]
self.desc = row[2]
self.type = row[3]
self.prereq = int(row[5])
self.precision = int(row[6])
import flags
self.flags = 0
if int(row[4]): self.flags |= flags.printable
if int(row[7]): self.flags |= flags.nozero
if int(row[8]): self.flags |= flags.nonan
if int(row[9]): self.flags |= flags.total
if int(row[10]): self.flags |= flags.pdf
if int(row[11]): self.flags |= flags.cdf
if self.type == 'DIST' or self.type == 'VECTORDIST':
self.min = float(row[12])
self.max = float(row[13])
self.bktsize = float(row[14])
self.size = int(row[15])
if self.type == 'FORMULA':
self.formula = self.db.allFormulas[self.stat]
class Node(object):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class Result(object):
def __init__(self, x, y):
self.data = {}
self.x = x
self.y = y
def __contains__(self, run):
return run in self.data
def __getitem__(self, run):
if run not in self.data:
self.data[run] = [ [ 0.0 ] * self.y for i in xrange(self.x) ]
return self.data[run]
class Database(object):
def __init__(self):
self.host = 'zizzer.pool'
self.user = ''
self.passwd = ''
self.db = 'm5stats'
self.cursor = None
self.allStats = []
self.allStatIds = {}
self.allStatNames = {}
self.allSubData = {}
self.allRuns = []
self.allRunIds = {}
self.allRunNames = {}
self.allFormulas = {}
self.stattop = {}
self.statdict = {}
self.statlist = []
self.mode = 'sum';
self.runs = None
self.ticks = None
self.method = 'sum'
self._method = type(self).sum
def get(self, job, stat, system=None):
run = self.allRunNames.get(str(job), None)
if run is None:
return None
from info import ProxyError, scalar, vector, value, values, total, len
if system is None and hasattr(job, 'system'):
system = job.system
if system is not None:
stat.system = self[system]
try:
if scalar(stat):
return value(stat, run.run)
if vector(stat):
return values(stat, run.run)
except ProxyError:
return None
return None
def query(self, sql):
self.cursor.execute(sql)
def update_dict(self, dict):
dict.update(self.stattop)
def append(self, stat):
statname = re.sub(':', '__', stat.name)
path = string.split(statname, '.')
pathtop = path[0]
fullname = ''
x = self
while len(path) > 1:
name = path.pop(0)
if not x.__dict__.has_key(name):
x.__dict__[name] = Node(fullname + name)
x = x.__dict__[name]
fullname = '%s%s.' % (fullname, name)
name = path.pop(0)
x.__dict__[name] = stat
self.stattop[pathtop] = self.__dict__[pathtop]
self.statdict[statname] = stat
self.statlist.append(statname)
def connect(self):
# connect
self.thedb = MySQLdb.connect(db=self.db,
host=self.host,
user=self.user,
passwd=self.passwd)
# create a cursor
self.cursor = self.thedb.cursor()
self.query('''select rn_id,rn_name,rn_sample,rn_user,rn_project
from runs''')
for result in self.cursor.fetchall():
run = RunData(result);
self.allRuns.append(run)
self.allRunIds[run.run] = run
self.allRunNames[run.name] = run
self.query('select sd_stat,sd_x,sd_y,sd_name,sd_descr from subdata')
for result in self.cursor.fetchall():
subdata = SubData(result)
if self.allSubData.has_key(subdata.stat):
self.allSubData[subdata.stat].append(subdata)
else:
self.allSubData[subdata.stat] = [ subdata ]
self.query('select * from formulas')
for id,formula in self.cursor.fetchall():
self.allFormulas[int(id)] = formula.tostring()
StatData.db = self
self.query('select * from stats')
import info
for result in self.cursor.fetchall():
stat = info.NewStat(self, StatData(result))
self.append(stat)
self.allStats.append(stat)
self.allStatIds[stat.stat] = stat
self.allStatNames[stat.name] = stat
# Name: listruns
# Desc: Prints all runs matching a given user, if no argument
# is given all runs are returned
def listRuns(self, user=None):
print '%-40s %-10s %-5s' % ('run name', 'user', 'id')
print '-' * 62
for run in self.allRuns:
if user == None or user == run.user:
print '%-40s %-10s %-10d' % (run.name, run.user, run.run)
# Name: listTicks
# Desc: Prints all samples for a given run
def listTicks(self, runs=None):
print "tick"
print "----------------------------------------"
sql = 'select distinct dt_tick from data where dt_stat=1180 and ('
if runs != None:
first = True
for run in runs:
if first:
# sql += ' where'
first = False
else:
sql += ' or'
sql += ' dt_run=%s' % run.run
sql += ')'
self.query(sql)
for r in self.cursor.fetchall():
print r[0]
# Name: retTicks
# Desc: Prints all samples for a given run
def retTicks(self, runs=None):
sql = 'select distinct dt_tick from data where dt_stat=1180 and ('
if runs != None:
first = True
for run in runs:
if first:
first = False
else:
sql += ' or'
sql += ' dt_run=%s' % run.run
sql += ')'
self.query(sql)
ret = []
for r in self.cursor.fetchall():
ret.append(r[0])
return ret
# Name: liststats
# Desc: Prints all statistics that appear in the database,
# the optional argument is a regular expression that can
# be used to prune the result set
def listStats(self, regex=None):
print '%-60s %-8s %-10s' % ('stat name', 'id', 'type')
print '-' * 80
rx = None
if regex != None:
rx = re.compile(regex)
stats = [ stat.name for stat in self.allStats ]
stats.sort(statcmp)
for stat in stats:
stat = self.allStatNames[stat]
if rx == None or rx.match(stat.name):
print '%-60s %-8s %-10s' % (stat.name, stat.stat, stat.type)
# Name: liststats
# Desc: Prints all statistics that appear in the database,
# the optional argument is a regular expression that can
# be used to prune the result set
def listFormulas(self, regex=None):
print '%-60s %s' % ('formula name', 'formula')
print '-' * 80
rx = None
if regex != None:
rx = re.compile(regex)
stats = [ stat.name for stat in self.allStats ]
stats.sort(statcmp)
for stat in stats:
stat = self.allStatNames[stat]
if stat.type == 'FORMULA' and (rx == None or rx.match(stat.name)):
print '%-60s %s' % (stat.name, self.allFormulas[stat.stat])
def getStat(self, stats):
if type(stats) is not list:
stats = [ stats ]
ret = []
for stat in stats:
if type(stat) is int:
ret.append(self.allStatIds[stat])
if type(stat) is str:
rx = re.compile(stat)
for stat in self.allStats:
if rx.match(stat.name):
ret.append(stat)
return ret
#########################################
# get the data
#
def query(self, op, stat, ticks, group=False):
sql = 'select '
sql += 'dt_stat as stat, '
sql += 'dt_run as run, '
sql += 'dt_x as x, '
sql += 'dt_y as y, '
if group:
sql += 'dt_tick as tick, '
sql += '%s(dt_data) as data ' % op
sql += 'from data '
sql += 'where '
if isinstance(stat, list):
val = ' or '.join([ 'dt_stat=%d' % s.stat for s in stat ])
sql += ' (%s)' % val
else:
sql += ' dt_stat=%d' % stat.stat
if self.runs != None and len(self.runs):
val = ' or '.join([ 'dt_run=%d' % r for r in self.runs ])
sql += ' and (%s)' % val
if ticks != None and len(ticks):
val = ' or '.join([ 'dt_tick=%d' % s for s in ticks ])
sql += ' and (%s)' % val
sql += ' group by dt_stat,dt_run,dt_x,dt_y'
if group:
sql += ',dt_tick'
return sql
# Name: sum
# Desc: given a run, a stat and an array of samples, total the samples
def sum(self, *args, **kwargs):
return self.query('sum', *args, **kwargs)
# Name: avg
# Desc: given a run, a stat and an array of samples, average the samples
def avg(self, stat, ticks):
return self.query('avg', *args, **kwargs)
# Name: stdev
# Desc: given a run, a stat and an array of samples, get the standard
# deviation
def stdev(self, stat, ticks):
return self.query('stddev', *args, **kwargs)
def __setattr__(self, attr, value):
super(Database, self).__setattr__(attr, value)
if attr != 'method':
return
if value == 'sum':
self._method = self.sum
elif value == 'avg':
self._method = self.avg
elif value == 'stdev':
self._method = self.stdev
else:
raise AttributeError, "can only set get to: sum | avg | stdev"
def data(self, stat, ticks=None):
if ticks is None:
ticks = self.ticks
sql = self._method(self, stat, ticks)
self.query(sql)
runs = {}
xmax = 0
ymax = 0
for x in self.cursor.fetchall():
data = Data(x)
if not runs.has_key(data.run):
runs[data.run] = {}
if not runs[data.run].has_key(data.x):
runs[data.run][data.x] = {}
xmax = max(xmax, data.x)
ymax = max(ymax, data.y)
runs[data.run][data.x][data.y] = data.data
results = Result(xmax + 1, ymax + 1)
for run,data in runs.iteritems():
result = results[run]
for x,ydata in data.iteritems():
for y,data in ydata.iteritems():
result[x][y] = data
return results
def __getitem__(self, key):
return self.stattop[key]

View File

@ -0,0 +1,385 @@
# Copyright (c) 2003-2004 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
import MySQLdb
class MyDB(object):
def __init__(self, options):
self.name = options.db
self.host = options.host
self.user = options.user
self.passwd = options.passwd
self.mydb = None
self.cursor = None
def admin(self):
self.close()
self.mydb = MySQLdb.connect(db='mysql', host=self.host, user=self.user,
passwd=self.passwd)
self.cursor = self.mydb.cursor()
def connect(self):
self.close()
self.mydb = MySQLdb.connect(db=self.name, host=self.host,
user=self.user, passwd=self.passwd)
self.cursor = self.mydb.cursor()
def close(self):
if self.mydb is not None:
self.mydb.close()
self.cursor = None
def query(self, sql):
self.cursor.execute(sql)
def drop(self):
self.query('DROP DATABASE IF EXISTS %s' % self.name)
def create(self):
self.query('CREATE DATABASE %s' % self.name)
def populate(self):
#
# Each run (or simulation) gets its own entry in the runs table to
# group stats by where they were generated
#
# COLUMNS:
# 'id' is a unique identifier for each run to be used in other
# tables.
# 'name' is the user designated name for the data generated. It is
# configured in the simulator.
# 'user' identifies the user that generated the data for the given
# run.
# 'project' another name to identify runs for a specific goal
# 'date' is a timestamp for when the data was generated. It can be
# used to easily expire data that was generated in the past.
# 'expire' is a timestamp for when the data should be removed from
# the database so we don't have years worth of junk.
#
# INDEXES:
# 'run' is indexed so you can find out details of a run if the run
# was retreived from the data table.
# 'name' is indexed so that two all run names are forced to be unique
#
self.query('''
CREATE TABLE runs(
rn_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
rn_name VARCHAR(200) NOT NULL,
rn_sample VARCHAR(32) NOT NULL,
rn_user VARCHAR(32) NOT NULL,
rn_project VARCHAR(100) NOT NULL,
rn_date TIMESTAMP NOT NULL,
rn_expire TIMESTAMP NOT NULL,
PRIMARY KEY (rn_id),
UNIQUE (rn_name,rn_sample)
) TYPE=InnoDB''')
#
# The stat table gives us all of the data for a particular stat.
#
# COLUMNS:
# 'stat' is a unique identifier for each stat to be used in other
# tables for references.
# 'name' is simply the simulator derived name for a given
# statistic.
# 'descr' is the description of the statistic and what it tells
# you.
# 'type' defines what the stat tells you. Types are:
# SCALAR: A simple scalar statistic that holds one value
# VECTOR: An array of statistic values. Such a something that
# is generated per-thread. Vectors exist to give averages,
# pdfs, cdfs, means, standard deviations, etc across the
# stat values.
# DIST: Is a distribution of data. When the statistic value is
# sampled, its value is counted in a particular bucket.
# Useful for keeping track of utilization of a resource.
# (e.g. fraction of time it is 25% used vs. 50% vs. 100%)
# VECTORDIST: Can be used when the distribution needs to be
# factored out into a per-thread distribution of data for
# example. It can still be summed across threads to find
# the total distribution.
# VECTOR2D: Can be used when you have a stat that is not only
# per-thread, but it is per-something else. Like
# per-message type.
# FORMULA: This statistic is a formula, and its data must be
# looked up in the formula table, for indicating how to
# present its values.
# 'subdata' is potentially used by any of the vector types to
# give a specific name to all of the data elements within a
# stat.
# 'print' indicates whether this stat should be printed ever.
# (Unnamed stats don't usually get printed)
# 'prereq' only print the stat if the prereq is not zero.
# 'prec' number of decimal places to print
# 'nozero' don't print zero values
# 'nonan' don't print NaN values
# 'total' for vector type stats, print the total.
# 'pdf' for vector type stats, print the pdf.
# 'cdf' for vector type stats, print the cdf.
#
# The Following are for dist type stats:
# 'min' is the minimum bucket value. Anything less is an underflow.
# 'max' is the maximum bucket value. Anything more is an overflow.
# 'bktsize' is the approximate number of entries in each bucket.
# 'size' is the number of buckets. equal to (min/max)/bktsize.
#
# INDEXES:
# 'stat' is indexed so that you can find out details about a stat
# if the stat id was retrieved from the data table.
# 'name' is indexed so that you can simply look up data about a
# named stat.
#
self.query('''
CREATE TABLE stats(
st_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
st_name VARCHAR(255) NOT NULL,
st_descr TEXT NOT NULL,
st_type ENUM("SCALAR", "VECTOR", "DIST", "VECTORDIST",
"VECTOR2D", "FORMULA") NOT NULL,
st_print BOOL NOT NULL,
st_prereq SMALLINT UNSIGNED NOT NULL,
st_prec TINYINT NOT NULL,
st_nozero BOOL NOT NULL,
st_nonan BOOL NOT NULL,
st_total BOOL NOT NULL,
st_pdf BOOL NOT NULL,
st_cdf BOOL NOT NULL,
st_min DOUBLE NOT NULL,
st_max DOUBLE NOT NULL,
st_bktsize DOUBLE NOT NULL,
st_size SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (st_id),
UNIQUE (st_name)
) TYPE=InnoDB''')
#
# This is the main table of data for stats.
#
# COLUMNS:
# 'stat' refers to the stat field given in the stat table.
#
# 'x' referrs to the first dimension of a multi-dimensional stat. For
# a vector, x will start at 0 and increase for each vector
# element.
# For a distribution:
# -1: sum (for calculating standard deviation)
# -2: sum of squares (for calculating standard deviation)
# -3: total number of samples taken (for calculating
# standard deviation)
# -4: minimum value
# -5: maximum value
# -6: underflow
# -7: overflow
# 'y' is used by a VECTORDIST and the VECTOR2D to describe the second
# dimension.
# 'run' is the run that the data was generated from. Details up in
# the run table
# 'tick' is a timestamp generated by the simulator.
# 'data' is the actual stat value.
#
# INDEXES:
# 'stat' is indexed so that a user can find all of the data for a
# particular stat. It is not unique, because that specific stat
# can be found in many runs and samples, in addition to
# having entries for the mulidimensional cases.
# 'run' is indexed to allow a user to remove all of the data for a
# particular execution run. It can also be used to allow the
# user to print out all of the data for a given run.
#
self.query('''
CREATE TABLE data(
dt_stat SMALLINT UNSIGNED NOT NULL,
dt_x SMALLINT NOT NULL,
dt_y SMALLINT NOT NULL,
dt_run SMALLINT UNSIGNED NOT NULL,
dt_tick BIGINT UNSIGNED NOT NULL,
dt_data DOUBLE NOT NULL,
INDEX (dt_stat),
INDEX (dt_run),
UNIQUE (dt_stat,dt_x,dt_y,dt_run,dt_tick)
) TYPE=InnoDB;''')
#
# Names and descriptions for multi-dimensional stats (vectors, etc.)
# are stored here instead of having their own entry in the statistics
# table. This allows all parts of a single stat to easily share a
# single id.
#
# COLUMNS:
# 'stat' is the unique stat identifier from the stat table.
# 'x' is the first dimension for multi-dimensional stats
# corresponding to the data table above.
# 'y' is the second dimension for multi-dimensional stats
# corresponding to the data table above.
# 'name' is the specific subname for the unique stat,x,y combination.
# 'descr' is the specific description for the uniqe stat,x,y
# combination.
#
# INDEXES:
# 'stat' is indexed so you can get the subdata for a specific stat.
#
self.query('''
CREATE TABLE subdata(
sd_stat SMALLINT UNSIGNED NOT NULL,
sd_x SMALLINT NOT NULL,
sd_y SMALLINT NOT NULL,
sd_name VARCHAR(255) NOT NULL,
sd_descr TEXT,
UNIQUE (sd_stat,sd_x,sd_y)
) TYPE=InnoDB''')
#
# The formula table is maintained separately from the data table
# because formula data, unlike other stat data cannot be represented
# there.
#
# COLUMNS:
# 'stat' refers to the stat field generated in the stat table.
# 'formula' is the actual string representation of the formula
# itself.
#
# INDEXES:
# 'stat' is indexed so that you can just look up a formula.
#
self.query('''
CREATE TABLE formulas(
fm_stat SMALLINT UNSIGNED NOT NULL,
fm_formula BLOB NOT NULL,
PRIMARY KEY(fm_stat)
) TYPE=InnoDB''')
#
# Each stat used in each formula is kept in this table. This way, if
# you want to print out a particular formula, you can simply find out
# which stats you need by looking in this table. Additionally, when
# you remove a stat from the stats table and data table, you remove
# any references to the formula in this table. When a formula is no
# longer referred to, you remove its entry.
#
# COLUMNS:
# 'stat' is the stat id from the stat table above.
# 'child' is the stat id of a stat that is used for this formula.
# There may be many children for any given 'stat' (formula)
#
# INDEXES:
# 'stat' is indexed so you can look up all of the children for a
# particular stat.
# 'child' is indexed so that you can remove an entry when a stat is
# removed.
#
self.query('''
CREATE TABLE formula_ref(
fr_stat SMALLINT UNSIGNED NOT NULL,
fr_run SMALLINT UNSIGNED NOT NULL,
UNIQUE (fr_stat,fr_run),
INDEX (fr_stat),
INDEX (fr_run)
) TYPE=InnoDB''')
# COLUMNS:
# 'event' is the unique event id from the event_desc table
# 'run' is simulation run id that this event took place in
# 'tick' is the tick when the event happened
#
# INDEXES:
# 'event' is indexed so you can look up all occurences of a
# specific event
# 'run' is indexed so you can find all events in a run
# 'tick' is indexed because we want the unique thing anyway
# 'event,run,tick' is unique combination
self.query('''
CREATE TABLE events(
ev_event SMALLINT UNSIGNED NOT NULL,
ev_run SMALLINT UNSIGNED NOT NULL,
ev_tick BIGINT UNSIGNED NOT NULL,
INDEX(ev_event),
INDEX(ev_run),
INDEX(ev_tick),
UNIQUE(ev_event,ev_run,ev_tick)
) TYPE=InnoDB''')
# COLUMNS:
# 'id' is the unique description id
# 'name' is the name of the event that occurred
#
# INDEXES:
# 'id' is indexed because it is the primary key and is what you use
# to look up the descriptions
# 'name' is indexed so one can find the event based on name
#
self.query('''
CREATE TABLE event_names(
en_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
en_name VARCHAR(255) NOT NULL,
PRIMARY KEY (en_id),
UNIQUE (en_name)
) TYPE=InnoDB''')
def clean(self):
self.query('''
DELETE data
FROM data
LEFT JOIN runs ON dt_run=rn_id
WHERE rn_id IS NULL''')
self.query('''
DELETE formula_ref
FROM formula_ref
LEFT JOIN runs ON fr_run=rn_id
WHERE rn_id IS NULL''')
self.query('''
DELETE formulas
FROM formulas
LEFT JOIN formula_ref ON fm_stat=fr_stat
WHERE fr_stat IS NULL''')
self.query('''
DELETE stats
FROM stats
LEFT JOIN data ON st_id=dt_stat
WHERE dt_stat IS NULL''')
self.query('''
DELETE subdata
FROM subdata
LEFT JOIN data ON sd_stat=dt_stat
WHERE dt_stat IS NULL''')
self.query('''
DELETE events
FROM events
LEFT JOIN runs ON ev_run=rn_id
WHERE rn_id IS NULL''')
self.query('''
DELETE event_names
FROM event_names
LEFT JOIN events ON en_id=ev_event
WHERE ev_event IS NULL''')

View File

@ -0,0 +1,151 @@
# Copyright (c) 2003-2004 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
class Value:
def __init__(self, value, precision, percent = False):
self.value = float(value)
self.precision = precision
self.percent = percent
def __str__(self):
if isinstance(self.value, str):
if self.value.lower() == 'nan':
value = 'NaN'
if self.value.lower() == 'inf':
value = 'Inf'
else:
if self.precision >= 0:
format = "%%.%df" % self.precision
elif self.value == 0.0:
format = "%.0f"
elif self.value % 1.0 == 0.0:
format = "%.0f"
else:
format = "%f"
value = self.value
if self.percent:
value = value * 100.0
value = format % value
if self.percent:
value = value + "%"
return value
class Print:
def __init__(self, **vals):
self.__dict__.update(vals)
def __str__(self):
value = Value(self.value, self.precision)
pdf = ''
cdf = ''
if self.__dict__.has_key('pdf'):
pdf = Value(self.pdf, 2, True)
if self.__dict__.has_key('cdf'):
cdf = Value(self.cdf, 2, True)
output = "%-40s %12s %8s %8s" % (self.name, value, pdf, cdf)
if descriptions and self.__dict__.has_key('desc') and self.desc:
output = "%s # %s" % (output, self.desc)
return output
def doprint(self):
if display_all:
return True
if self.value == 0.0 and (self.flags & flags_nozero):
return False
if isinstance(self.value, str):
if self.value == 'NaN' and (self.flags & flags_nonan):
return False
return True
def display(self):
if self.doprint():
print self
class VectorDisplay:
def display(self):
if not self.value:
return
p = Print()
p.flags = self.flags
p.precision = self.precision
if not isinstance(self.value, (list, tuple)):
p.name = self.name
p.desc = self.desc
p.value = self.value
p.display()
return
mytotal = reduce(lambda x,y: float(x) + float(y), self.value)
mycdf = 0.0
value = self.value
if display_all:
subnames = [ '[%d]' % i for i in range(len(value)) ]
else:
subnames = [''] * len(value)
if self.__dict__.has_key('subnames'):
for i,each in enumerate(self.subnames):
if len(each) > 0:
subnames[i] = '.%s' % each
subdescs = [self.desc]*len(value)
if self.__dict__.has_key('subdescs'):
for i in xrange(min(len(value), len(self.subdescs))):
subdescs[i] = self.subdescs[i]
for val,sname,sdesc in map(None, value, subnames, subdescs):
if mytotal > 0.0:
mypdf = float(val) / float(mytotal)
mycdf += mypdf
if (self.flags & flags_pdf):
p.pdf = mypdf
p.cdf = mycdf
if len(sname) == 0:
continue
p.name = self.name + sname
p.desc = sdesc
p.value = val
p.display()
if (self.flags & flags_total):
if (p.__dict__.has_key('pdf')): del p.__dict__['pdf']
if (p.__dict__.has_key('cdf')): del p.__dict__['cdf']
p.name = self.name + '.total'
p.desc = self.desc
p.value = mytotal
p.display()

View File

@ -0,0 +1,36 @@
# Copyright (c) 2004 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
init = 0x00000001
printable = 0x00000002
total = 0x00000010
pdf = 0x00000020
cdf = 0x00000040
dist = 0x00000080
nozero = 0x00000100
nonan = 0x00000200

View File

@ -0,0 +1,768 @@
# Copyright (c) 2003-2004 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
from __future__ import division
import operator, re, types
class ProxyError(Exception):
pass
def unproxy(proxy):
if hasattr(proxy, '__unproxy__'):
return proxy.__unproxy__()
return proxy
def scalar(stat):
stat = unproxy(stat)
assert(stat.__scalar__() != stat.__vector__())
return stat.__scalar__()
def vector(stat):
stat = unproxy(stat)
assert(stat.__scalar__() != stat.__vector__())
return stat.__vector__()
def value(stat, *args):
stat = unproxy(stat)
return stat.__value__(*args)
def values(stat, run):
stat = unproxy(stat)
result = []
for i in xrange(len(stat)):
val = value(stat, run, i)
if val is None:
return None
result.append(val)
return result
def total(stat, run):
return sum(values(stat, run))
def len(stat):
stat = unproxy(stat)
return stat.__len__()
class Value(object):
def __scalar__(self):
raise AttributeError, "must define __scalar__ for %s" % (type (self))
def __vector__(self):
raise AttributeError, "must define __vector__ for %s" % (type (self))
def __add__(self, other):
return BinaryProxy(operator.__add__, self, other)
def __sub__(self, other):
return BinaryProxy(operator.__sub__, self, other)
def __mul__(self, other):
return BinaryProxy(operator.__mul__, self, other)
def __div__(self, other):
return BinaryProxy(operator.__div__, self, other)
def __truediv__(self, other):
return BinaryProxy(operator.__truediv__, self, other)
def __floordiv__(self, other):
return BinaryProxy(operator.__floordiv__, self, other)
def __radd__(self, other):
return BinaryProxy(operator.__add__, other, self)
def __rsub__(self, other):
return BinaryProxy(operator.__sub__, other, self)
def __rmul__(self, other):
return BinaryProxy(operator.__mul__, other, self)
def __rdiv__(self, other):
return BinaryProxy(operator.__div__, other, self)
def __rtruediv__(self, other):
return BinaryProxy(operator.__truediv__, other, self)
def __rfloordiv__(self, other):
return BinaryProxy(operator.__floordiv__, other, self)
def __neg__(self):
return UnaryProxy(operator.__neg__, self)
def __pos__(self):
return UnaryProxy(operator.__pos__, self)
def __abs__(self):
return UnaryProxy(operator.__abs__, self)
class Scalar(Value):
def __scalar__(self):
return True
def __vector__(self):
return False
def __value__(self, run):
raise AttributeError, '__value__ must be defined'
class VectorItemProxy(Value):
def __init__(self, proxy, index):
self.proxy = proxy
self.index = index
def __scalar__(self):
return True
def __vector__(self):
return False
def __value__(self, run):
return value(self.proxy, run, self.index)
class Vector(Value):
def __scalar__(self):
return False
def __vector__(self):
return True
def __value__(self, run, index):
raise AttributeError, '__value__ must be defined'
def __getitem__(self, index):
return VectorItemProxy(self, index)
class ScalarConstant(Scalar):
def __init__(self, constant):
self.constant = constant
def __value__(self, run):
return self.constant
def __str__(self):
return str(self.constant)
class VectorConstant(Vector):
def __init__(self, constant):
self.constant = constant
def __value__(self, run, index):
return self.constant[index]
def __len__(self):
return len(self.constant)
def __str__(self):
return str(self.constant)
def WrapValue(value):
if isinstance(value, (int, long, float)):
return ScalarConstant(value)
if isinstance(value, (list, tuple)):
return VectorConstant(value)
if isinstance(value, Value):
return value
raise AttributeError, 'Only values can be wrapped'
class Statistic(object):
def __getattr__(self, attr):
if attr in ('data', 'x', 'y'):
result = self.source.data(self, self.ticks)
self.data = result.data
self.x = result.x
self.y = result.y
return super(Statistic, self).__getattribute__(attr)
def __setattr__(self, attr, value):
if attr == 'stat':
raise AttributeError, '%s is read only' % stat
if attr in ('source', 'ticks'):
if getattr(self, attr) != value:
if hasattr(self, 'data'):
delattr(self, 'data')
super(Statistic, self).__setattr__(attr, value)
def __str__(self):
return self.name
class ValueProxy(Value):
def __getattr__(self, attr):
if attr == '__value__':
if scalar(self):
return self.__scalarvalue__
if vector(self):
return self.__vectorvalue__
if attr == '__len__':
if vector(self):
return self.__vectorlen__
return super(ValueProxy, self).__getattribute__(attr)
class UnaryProxy(ValueProxy):
def __init__(self, op, arg):
self.op = op
self.arg = WrapValue(arg)
def __scalar__(self):
return scalar(self.arg)
def __vector__(self):
return vector(self.arg)
def __scalarvalue__(self, run):
val = value(self.arg, run)
if val is None:
return None
return self.op(val)
def __vectorvalue__(self, run, index):
val = value(self.arg, run, index)
if val is None:
return None
return self.op(val)
def __vectorlen__(self):
return len(unproxy(self.arg))
def __str__(self):
if self.op == operator.__neg__:
return '-%s' % str(self.arg)
if self.op == operator.__pos__:
return '+%s' % str(self.arg)
if self.op == operator.__abs__:
return 'abs(%s)' % self.arg
class BinaryProxy(ValueProxy):
def __init__(self, op, arg0, arg1):
super(BinaryProxy, self).__init__()
self.op = op
self.arg0 = WrapValue(arg0)
self.arg1 = WrapValue(arg1)
def __scalar__(self):
return scalar(self.arg0) and scalar(self.arg1)
def __vector__(self):
return vector(self.arg0) or vector(self.arg1)
def __scalarvalue__(self, run):
val0 = value(self.arg0, run)
val1 = value(self.arg1, run)
if val0 is None or val1 is None:
return None
try:
return self.op(val0, val1)
except ZeroDivisionError:
return None
def __vectorvalue__(self, run, index):
if scalar(self.arg0):
val0 = value(self.arg0, run)
if vector(self.arg0):
val0 = value(self.arg0, run, index)
if scalar(self.arg1):
val1 = value(self.arg1, run)
if vector(self.arg1):
val1 = value(self.arg1, run, index)
if val0 is None or val1 is None:
return None
try:
return self.op(val0, val1)
except ZeroDivisionError:
return None
def __vectorlen__(self):
if vector(self.arg0) and scalar(self.arg1):
return len(self.arg0)
if scalar(self.arg0) and vector(self.arg1):
return len(self.arg1)
len0 = len(self.arg0)
len1 = len(self.arg1)
if len0 != len1:
raise AttributeError, \
"vectors of different lengths %d != %d" % (len0, len1)
return len0
def __str__(self):
ops = { operator.__add__ : '+',
operator.__sub__ : '-',
operator.__mul__ : '*',
operator.__div__ : '/',
operator.__truediv__ : '/',
operator.__floordiv__ : '//' }
return '(%s %s %s)' % (str(self.arg0), ops[self.op], str(self.arg1))
class Proxy(Value):
def __init__(self, name, dict):
self.name = name
self.dict = dict
def __unproxy__(self):
return unproxy(self.dict[self.name])
def __getitem__(self, index):
return ItemProxy(self, index)
def __getattr__(self, attr):
return AttrProxy(self, attr)
def __str__(self):
return str(self.dict[self.name])
class ItemProxy(Proxy):
def __init__(self, proxy, index):
self.proxy = proxy
self.index = index
def __unproxy__(self):
return unproxy(unproxy(self.proxy)[self.index])
def __str__(self):
return '%s[%s]' % (self.proxy, self.index)
class AttrProxy(Proxy):
def __init__(self, proxy, attr):
self.proxy = proxy
self.attr = attr
def __unproxy__(self):
proxy = unproxy(self.proxy)
try:
attr = getattr(proxy, self.attr)
except AttributeError, e:
raise ProxyError, e
return unproxy(attr)
def __str__(self):
return '%s.%s' % (self.proxy, self.attr)
class ProxyGroup(object):
def __init__(self, dict=None, **kwargs):
self.__dict__['dict'] = {}
if dict is not None:
self.dict.update(dict)
if kwargs:
self.dict.update(kwargs)
def __getattr__(self, name):
return Proxy(name, self.dict)
def __setattr__(self, attr, value):
self.dict[attr] = value
class ScalarStat(Statistic,Scalar):
def __value__(self, run):
if run not in self.data:
return None
return self.data[run][0][0]
def display(self, run=None):
import display
p = display.Print()
p.name = self.name
p.desc = self.desc
p.value = value(self, run)
p.flags = self.flags
p.precision = self.precision
if display.all or (self.flags & flags.printable):
p.display()
class VectorStat(Statistic,Vector):
def __value__(self, run, item):
if run not in self.data:
return None
return self.data[run][item][0]
def __len__(self):
return self.x
def display(self, run=None):
import display
d = display.VectorDisplay()
d.name = self.name
d.desc = self.desc
d.value = [ value(self, run, i) for i in xrange(len(self)) ]
d.flags = self.flags
d.precision = self.precision
d.display()
class Formula(Value):
def __getattribute__(self, attr):
if attr not in ( '__scalar__', '__vector__', '__value__', '__len__' ):
return super(Formula, self).__getattribute__(attr)
formula = re.sub(':', '__', self.formula)
value = eval(formula, self.source.stattop)
return getattr(value, attr)
def __str__(self):
return self.name
class SimpleDist(Statistic):
def __init__(self, sums, squares, samples):
self.sums = sums
self.squares = squares
self.samples = samples
def display(self, name, desc, flags, precision):
import display
p = display.Print()
p.flags = flags
p.precision = precision
if self.samples > 0:
p.name = name + ".mean"
p.value = self.sums / self.samples
p.display()
p.name = name + ".stdev"
if self.samples > 1:
var = (self.samples * self.squares - self.sums ** 2) \
/ (self.samples * (self.samples - 1))
if var >= 0:
p.value = math.sqrt(var)
else:
p.value = 'NaN'
else:
p.value = 0.0
p.display()
p.name = name + ".samples"
p.value = self.samples
p.display()
def comparable(self, other):
return True
def __eq__(self, other):
return self.sums == other.sums and self.squares == other.squares and \
self.samples == other.samples
def __isub__(self, other):
self.sums -= other.sums
self.squares -= other.squares
self.samples -= other.samples
return self
def __iadd__(self, other):
self.sums += other.sums
self.squares += other.squares
self.samples += other.samples
return self
def __itruediv__(self, other):
if not other:
return self
self.sums /= other
self.squares /= other
self.samples /= other
return self
class FullDist(SimpleDist):
def __init__(self, sums, squares, samples, minval, maxval,
under, vec, over, min, max, bsize, size):
self.sums = sums
self.squares = squares
self.samples = samples
self.minval = minval
self.maxval = maxval
self.under = under
self.vec = vec
self.over = over
self.min = min
self.max = max
self.bsize = bsize
self.size = size
def display(self, name, desc, flags, precision):
import display
p = display.Print()
p.flags = flags
p.precision = precision
p.name = name + '.min_val'
p.value = self.minval
p.display()
p.name = name + '.max_val'
p.value = self.maxval
p.display()
p.name = name + '.underflow'
p.value = self.under
p.display()
i = self.min
for val in self.vec[:-1]:
p.name = name + '[%d:%d]' % (i, i + self.bsize - 1)
p.value = val
p.display()
i += self.bsize
p.name = name + '[%d:%d]' % (i, self.max)
p.value = self.vec[-1]
p.display()
p.name = name + '.overflow'
p.value = self.over
p.display()
SimpleDist.display(self, name, desc, flags, precision)
def comparable(self, other):
return self.min == other.min and self.max == other.max and \
self.bsize == other.bsize and self.size == other.size
def __eq__(self, other):
return self.sums == other.sums and self.squares == other.squares and \
self.samples == other.samples
def __isub__(self, other):
self.sums -= other.sums
self.squares -= other.squares
self.samples -= other.samples
if other.samples:
self.minval = min(self.minval, other.minval)
self.maxval = max(self.maxval, other.maxval)
self.under -= under
self.vec = map(lambda x,y: x - y, self.vec, other.vec)
self.over -= over
return self
def __iadd__(self, other):
if not self.samples and other.samples:
self = other
return self
self.sums += other.sums
self.squares += other.squares
self.samples += other.samples
if other.samples:
self.minval = min(self.minval, other.minval)
self.maxval = max(self.maxval, other.maxval)
self.under += other.under
self.vec = map(lambda x,y: x + y, self.vec, other.vec)
self.over += other.over
return self
def __itruediv__(self, other):
if not other:
return self
self.sums /= other
self.squares /= other
self.samples /= other
if self.samples:
self.under /= other
for i in xrange(len(self.vec)):
self.vec[i] /= other
self.over /= other
return self
class Dist(Statistic):
def display(self):
import display
if not display.all and not (self.flags & flags.printable):
return
self.dist.display(self.name, self.desc, self.flags, self.precision)
def comparable(self, other):
return self.name == other.name and \
self.dist.compareable(other.dist)
def __eq__(self, other):
return self.dist == other.dist
def __isub__(self, other):
self.dist -= other.dist
return self
def __iadd__(self, other):
self.dist += other.dist
return self
def __itruediv__(self, other):
if not other:
return self
self.dist /= other
return self
class VectorDist(Statistic):
def display(self):
import display
if not display.all and not (self.flags & flags.printable):
return
if isinstance(self.dist, SimpleDist):
return
for dist,sn,sd,i in map(None, self.dist, self.subnames, self.subdescs,
range(len(self.dist))):
if len(sn) > 0:
name = '%s.%s' % (self.name, sn)
else:
name = '%s[%d]' % (self.name, i)
if len(sd) > 0:
desc = sd
else:
desc = self.desc
dist.display(name, desc, self.flags, self.precision)
if (self.flags & flags.total) or 1:
if isinstance(self.dist[0], SimpleDist):
disttotal = SimpleDist( \
reduce(sums, [d.sums for d in self.dist]),
reduce(sums, [d.squares for d in self.dist]),
reduce(sums, [d.samples for d in self.dist]))
else:
disttotal = FullDist( \
reduce(sums, [d.sums for d in self.dist]),
reduce(sums, [d.squares for d in self.dist]),
reduce(sums, [d.samples for d in self.dist]),
min([d.minval for d in self.dist]),
max([d.maxval for d in self.dist]),
reduce(sums, [d.under for d in self.dist]),
reduce(sums, [d.vec for d in self.dist]),
reduce(sums, [d.over for d in self.dist]),
dist[0].min,
dist[0].max,
dist[0].bsize,
dist[0].size)
name = '%s.total' % (self.name)
desc = self.desc
disttotal.display(name, desc, self.flags, self.precision)
def comparable(self, other):
return self.name == other.name and \
alltrue(map(lambda x, y : x.comparable(y),
self.dist,
other.dist))
def __eq__(self, other):
return alltrue(map(lambda x, y : x == y, self.dist, other.dist))
def __isub__(self, other):
if isinstance(self.dist, (list, tuple)) and \
isinstance(other.dist, (list, tuple)):
for sd,od in zip(self.dist, other.dist):
sd -= od
else:
self.dist -= other.dist
return self
def __iadd__(self, other):
if isinstance(self.dist, (list, tuple)) and \
isinstance(other.dist, (list, tuple)):
for sd,od in zip(self.dist, other.dist):
sd += od
else:
self.dist += other.dist
return self
def __itruediv__(self, other):
if not other:
return self
if isinstance(self.dist, (list, tuple)):
for dist in self.dist:
dist /= other
else:
self.dist /= other
return self
class Vector2d(Statistic):
def display(self):
import display
if not display.all and not (self.flags & flags.printable):
return
d = display.VectorDisplay()
d.__dict__.update(self.__dict__)
if self.__dict__.has_key('ysubnames'):
ysubnames = list(self.ysubnames)
slack = self.x - len(ysubnames)
if slack > 0:
ysubnames.extend(['']*slack)
else:
ysubnames = range(self.x)
for x,sname in enumerate(ysubnames):
o = x * self.y
d.value = self.value[o:o+self.y]
d.name = '%s[%s]' % (self.name, sname)
d.display()
if self.flags & flags.total:
d.value = []
for y in range(self.y):
xtot = 0.0
for x in range(self.x):
xtot += self.value[y + x * self.x]
d.value.append(xtot)
d.name = self.name + '.total'
d.display()
def comparable(self, other):
return self.name == other.name and self.x == other.x and \
self.y == other.y
def __eq__(self, other):
return True
def __isub__(self, other):
return self
def __iadd__(self, other):
return self
def __itruediv__(self, other):
if not other:
return self
return self
def NewStat(source, data):
stat = None
if data.type == 'SCALAR':
stat = ScalarStat()
elif data.type == 'VECTOR':
stat = VectorStat()
elif data.type == 'DIST':
stat = Dist()
elif data.type == 'VECTORDIST':
stat = VectorDist()
elif data.type == 'VECTOR2D':
stat = Vector2d()
elif data.type == 'FORMULA':
stat = Formula()
stat.__dict__['source'] = source
stat.__dict__['ticks'] = None
stat.__dict__.update(data.__dict__)
return stat

View File

@ -0,0 +1,213 @@
# Copyright (c) 2005-2006 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
from chart import ChartOptions
class StatOutput(ChartOptions):
def __init__(self, jobfile, info, stat=None):
super(StatOutput, self).__init__()
self.jobfile = jobfile
self.stat = stat
self.invert = False
self.info = info
def display(self, name, printmode = 'G'):
import info
if printmode == 'G':
valformat = '%g'
elif printmode != 'F' and value > 1e6:
valformat = '%0.5e'
else:
valformat = '%f'
for job in self.jobfile.jobs():
value = self.info.get(job, self.stat)
if value is None:
return
if not isinstance(value, list):
value = [ value ]
if self.invert:
for i,val in enumerate(value):
if val != 0.0:
value[i] = 1 / val
valstring = ', '.join([ valformat % val for val in value ])
print '%-50s %s' % (job.name + ':', valstring)
def graph(self, name, graphdir, proxy=None):
from os.path import expanduser, isdir, join as joinpath
from barchart import BarChart
from matplotlib.numerix import Float, array, zeros
import os, re, urllib
from jobfile import crossproduct
confgroups = self.jobfile.groups()
ngroups = len(confgroups)
skiplist = [ False ] * ngroups
groupopts = []
baropts = []
groups = []
for i,group in enumerate(confgroups):
if group.flags.graph_group:
groupopts.append(group.subopts())
skiplist[i] = True
elif group.flags.graph_bars:
baropts.append(group.subopts())
skiplist[i] = True
else:
groups.append(group)
has_group = bool(groupopts)
if has_group:
groupopts = [ group for group in crossproduct(groupopts) ]
else:
groupopts = [ None ]
if baropts:
baropts = [ bar for bar in crossproduct(baropts) ]
else:
raise AttributeError, 'No group selected for graph bars'
directory = expanduser(graphdir)
if not isdir(directory):
os.mkdir(directory)
html = file(joinpath(directory, '%s.html' % name), 'w')
print >>html, '<html>'
print >>html, '<title>Graphs for %s</title>' % name
print >>html, '<body>'
html.flush()
for options in self.jobfile.options(groups):
chart = BarChart(self)
data = [ [ None ] * len(baropts) for i in xrange(len(groupopts)) ]
enabled = False
stacked = 0
for g,gopt in enumerate(groupopts):
for b,bopt in enumerate(baropts):
if gopt is None:
gopt = []
job = self.jobfile.job(options + gopt + bopt)
if not job:
continue
if proxy:
import db
proxy.dict['system'] = self.info[job.system]
val = self.info.get(job, self.stat)
if val is None:
print 'stat "%s" for job "%s" not found' % \
(self.stat, job)
if isinstance(val, (list, tuple)):
if len(val) == 1:
val = val[0]
else:
stacked = len(val)
data[g][b] = val
if stacked == 0:
for i in xrange(len(groupopts)):
for j in xrange(len(baropts)):
if data[i][j] is None:
data[i][j] = 0.0
else:
for i in xrange(len(groupopts)):
for j in xrange(len(baropts)):
val = data[i][j]
if val is None:
data[i][j] = [ 0.0 ] * stacked
elif len(val) != stacked:
raise ValueError, "some stats stacked, some not"
data = array(data)
if data.sum() == 0:
continue
dim = len(data.shape)
x = data.shape[0]
xkeep = [ i for i in xrange(x) if data[i].sum() != 0 ]
y = data.shape[1]
ykeep = [ i for i in xrange(y) if data[:,i].sum() != 0 ]
data = data.take(xkeep, axis=0)
data = data.take(ykeep, axis=1)
if not has_group:
data = data.take([ 0 ], axis=0)
chart.data = data
bopts = [ baropts[i] for i in ykeep ]
bdescs = [ ' '.join([o.desc for o in opt]) for opt in bopts]
if has_group:
gopts = [ groupopts[i] for i in xkeep ]
gdescs = [ ' '.join([o.desc for o in opt]) for opt in gopts]
if chart.legend is None:
if stacked:
try:
chart.legend = self.info.rcategories
except:
chart.legend = [ str(i) for i in xrange(stacked) ]
else:
chart.legend = bdescs
if chart.xticks is None:
if has_group:
chart.xticks = gdescs
else:
chart.xticks = []
chart.graph()
names = [ opt.name for opt in options ]
descs = [ opt.desc for opt in options ]
if names[0] == 'run':
names = names[1:]
descs = descs[1:]
basename = '%s-%s' % (name, ':'.join(names))
desc = ' '.join(descs)
pngname = '%s.png' % basename
psname = '%s.eps' % re.sub(':', '-', basename)
epsname = '%s.ps' % re.sub(':', '-', basename)
chart.savefig(joinpath(directory, pngname))
chart.savefig(joinpath(directory, epsname))
chart.savefig(joinpath(directory, psname))
html_name = urllib.quote(pngname)
print >>html, '''%s<br><img src="%s"><br>''' % (desc, html_name)
html.flush()
print >>html, '</body>'
print >>html, '</html>'
html.close()

View File

@ -0,0 +1,155 @@
# Copyright (c) 2003-2004 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
all = False
descriptions = False
class Value:
def __init__(self, value, precision, percent = False):
self.value = value
self.precision = precision
self.percent = percent
def __str__(self):
if isinstance(self.value, str):
if self.value.lower() == 'nan':
value = 'NaN'
if self.value.lower() == 'inf':
value = 'Inf'
else:
if self.precision >= 0:
format = "%%.%df" % self.precision
elif self.value == 0.0:
format = "%.0f"
elif self.value % 1.0 == 0.0:
format = "%.0f"
else:
format = "%f"
value = self.value
if self.percent:
value = value * 100.0
value = format % value
if self.percent:
value = value + "%"
return value
class Print:
def __init__(self, **vals):
self.__dict__.update(vals)
def __str__(self):
value = Value(self.value, self.precision)
pdf = ''
cdf = ''
if self.__dict__.has_key('pdf'):
pdf = Value(self.pdf, 2, True)
if self.__dict__.has_key('cdf'):
cdf = Value(self.cdf, 2, True)
output = "%-40s %12s %8s %8s" % (self.name, value, pdf, cdf)
if descriptions and self.__dict__.has_key('desc') and self.desc:
output = "%s # %s" % (output, self.desc)
return output
def doprint(self):
if display_all:
return True
if self.value == 0.0 and (self.flags & flags_nozero):
return False
if isinstance(self.value, str):
if self.value == 'NaN' and (self.flags & flags_nonan):
return False
return True
def display(self):
if self.doprint():
print self
class VectorDisplay:
def display(self):
p = Print()
p.flags = self.flags
p.precision = self.precision
if isinstance(self.value, (list, tuple)):
if not len(self.value):
return
mytotal = reduce(lambda x,y: float(x) + float(y), self.value)
mycdf = 0.0
value = self.value
if display_all:
subnames = [ '[%d]' % i for i in range(len(value)) ]
else:
subnames = [''] * len(value)
if self.__dict__.has_key('subnames'):
for i,each in enumerate(self.subnames):
if len(each) > 0:
subnames[i] = '.%s' % each
subdescs = [self.desc]*len(value)
if self.__dict__.has_key('subdescs'):
for i in xrange(min(len(value), len(self.subdescs))):
subdescs[i] = self.subdescs[i]
for val,sname,sdesc in map(None, value, subnames, subdescs):
if mytotal > 0.0:
mypdf = float(val) / float(mytotal)
mycdf += mypdf
if (self.flags & flags_pdf):
p.pdf = mypdf
p.cdf = mycdf
if len(sname) == 0:
continue
p.name = self.name + sname
p.desc = sdesc
p.value = val
p.display()
if (self.flags & flags_total):
if (p.__dict__.has_key('pdf')): del p.__dict__['pdf']
if (p.__dict__.has_key('cdf')): del p.__dict__['cdf']
p.name = self.name + '.total'
p.desc = self.desc
p.value = mytotal
p.display()
else:
p.name = self.name
p.desc = self.desc
p.value = self.value
p.display()

View File

@ -0,0 +1,504 @@
# 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
from orderdict import orderdict
import output
class FileData(dict):
def __init__(self, filename):
self.filename = filename
fd = file(filename)
current = []
for line in fd:
line = line.strip()
if line.startswith('>>>'):
current = []
self[line[3:]] = current
else:
current.append(line)
fd.close()
class RunData(dict):
def __init__(self, filename):
self.filename = filename
def __getattribute__(self, attr):
if attr == 'total':
total = 0.0
for value in self.itervalues():
total += value
return total
if attr == 'filedata':
return FileData(self.filename)
if attr == 'maxsymlen':
return max([ len(sym) for sym in self.iterkeys() ])
return super(RunData, self).__getattribute__(attr)
def display(self, output=None, limit=None, maxsymlen=None):
if not output:
import sys
output = sys.stdout
elif isinstance(output, str):
output = file(output, 'w')
total = float(self.total)
# swap (string,count) order so we can sort on count
symbols = [ (count,name) for name,count in self.iteritems() ]
symbols.sort(reverse=True)
if limit is not None:
symbols = symbols[:limit]
if not maxsymlen:
maxsymlen = self.maxsymlen
symbolf = "%-" + str(maxsymlen + 1) + "s %.2f%%"
for number,name in symbols:
print >>output, symbolf % (name, 100.0 * (float(number) / total))
class PCData(RunData):
def __init__(self, filename=None, categorize=None, showidle=True):
super(PCData, self).__init__(self, filename)
filedata = self.filedata['PC data']
for line in filedata:
(symbol, count) = line.split()
if symbol == "0x0":
continue
count = int(count)
if categorize is not None:
category = categorize(symbol)
if category is None:
category = 'other'
elif category == 'idle' and not showidle:
continue
self[category] = count
class FuncNode(object):
def __new__(cls, filedata=None):
if filedata is None:
return super(FuncNode, cls).__new__(cls)
nodes = {}
for line in filedata['function data']:
data = line.split(' ')
node_id = long(data[0], 16)
node = FuncNode()
node.symbol = data[1]
if node.symbol == '':
node.symbol = 'unknown'
node.count = long(data[2])
node.children = [ long(child, 16) for child in data[3:] ]
nodes[node_id] = node
for node in nodes.itervalues():
children = []
for cid in node.children:
child = nodes[cid]
children.append(child)
child.parent = node
node.children = tuple(children)
if not nodes:
print filedata.filename
print nodes
return nodes[0]
def total(self):
total = self.count
for child in self.children:
total += child.total()
return total
def aggregate(self, dict, categorize, incategory):
category = None
if categorize:
category = categorize(self.symbol)
total = self.count
for child in self.children:
total += child.aggregate(dict, categorize, category or incategory)
if category:
dict[category] = dict.get(category, 0) + total
return 0
elif not incategory:
dict[self.symbol] = dict.get(self.symbol, 0) + total
return total
def dump(self):
kids = [ child.symbol for child in self.children]
print '%s %d <%s>' % (self.symbol, self.count, ', '.join(kids))
for child in self.children:
child.dump()
def _dot(self, dot, threshold, categorize, total):
from pydot import Dot, Edge, Node
self.dot_node = None
value = self.total() * 100.0 / total
if value < threshold:
return
if categorize:
category = categorize(self.symbol)
if category and category != 'other':
return
label = '%s %.2f%%' % (self.symbol, value)
self.dot_node = Node(self, label=label)
dot.add_node(self.dot_node)
for child in self.children:
child._dot(dot, threshold, categorize, total)
if child.dot_node is not None:
dot.add_edge(Edge(self, child))
def _cleandot(self):
for child in self.children:
child._cleandot()
self.dot_node = None
del self.__dict__['dot_node']
def dot(self, dot, threshold=0.1, categorize=None):
self._dot(dot, threshold, categorize, self.total())
self._cleandot()
class FuncData(RunData):
def __init__(self, filename, categorize=None):
super(FuncData, self).__init__(filename)
tree = self.tree
tree.aggregate(self, categorize, incategory=False)
self.total = tree.total()
def __getattribute__(self, attr):
if attr == 'tree':
return FuncNode(self.filedata)
return super(FuncData, self).__getattribute__(attr)
def displayx(self, output=None, maxcount=None):
if output is None:
import sys
output = sys.stdout
items = [ (val,key) for key,val in self.iteritems() ]
items.sort(reverse=True)
for val,key in items:
if maxcount is not None:
if maxcount == 0:
return
maxcount -= 1
percent = val * 100.0 / self.total
print >>output, '%-30s %8s' % (key, '%3.2f%%' % percent)
class Profile(object):
# This list controls the order of values in stacked bar data output
default_categories = [ 'interrupt',
'driver',
'stack',
'buffer',
'copy',
'syscall',
'user',
'other',
'idle']
def __init__(self, datatype, categorize=None):
categories = Profile.default_categories
self.datatype = datatype
self.categorize = categorize
self.data = {}
self.categories = categories[:]
self.rcategories = categories[:]
self.rcategories.reverse()
self.cpu = 0
# Read in files
def inputdir(self, directory):
import os, os.path, re
from os.path import expanduser, join as joinpath
directory = expanduser(directory)
label_ex = re.compile(r'profile\.(.*).dat')
for root,dirs,files in os.walk(directory):
for name in files:
match = label_ex.match(name)
if not match:
continue
filename = joinpath(root, name)
prefix = os.path.commonprefix([root, directory])
dirname = root[len(prefix)+1:]
data = self.datatype(filename, self.categorize)
self.setdata(dirname, match.group(1), data)
def setdata(self, run, cpu, data):
if run not in self.data:
self.data[run] = {}
if cpu in self.data[run]:
raise AttributeError, \
'data already stored for run %s and cpu %s' % (run, cpu)
self.data[run][cpu] = data
def getdata(self, run, cpu):
try:
return self.data[run][cpu]
except KeyError:
print run, cpu
return None
def alldata(self):
for run,cpus in self.data.iteritems():
for cpu,data in cpus.iteritems():
yield run,cpu,data
def get(self, job, stat, system=None):
if system is None and hasattr('system', job):
system = job.system
if system is None:
raise AttributeError, 'The job must have a system set'
cpu = '%s.run%d' % (system, self.cpu)
data = self.getdata(str(job), cpu)
if not data:
return None
values = []
for category in self.categories:
val = float(data.get(category, 0.0))
if val < 0.0:
raise ValueError, 'value is %f' % val
values.append(val)
total = sum(values)
return [ v / total * 100.0 for v in values ]
def dump(self):
for run,cpu,data in self.alldata():
print 'run %s, cpu %s' % (run, cpu)
data.dump()
print
def write_dot(self, threshold, jobfile=None, jobs=None):
import pydot
if jobs is None:
jobs = [ job for job in jobfile.jobs() ]
for job in jobs:
cpu = '%s.run%d' % (job.system, self.cpu)
symbols = self.getdata(job.name, cpu)
if not symbols:
continue
dot = pydot.Dot()
symbols.tree.dot(dot, threshold=threshold)
dot.write(symbols.filename[:-3] + 'dot')
def write_txt(self, jobfile=None, jobs=None, limit=None):
if jobs is None:
jobs = [ job for job in jobfile.jobs() ]
for job in jobs:
cpu = '%s.run%d' % (job.system, self.cpu)
symbols = self.getdata(job.name, cpu)
if not symbols:
continue
output = file(symbols.filename[:-3] + 'txt', 'w')
symbols.display(output, limit)
def display(self, jobfile=None, jobs=None, limit=None):
if jobs is None:
jobs = [ job for job in jobfile.jobs() ]
maxsymlen = 0
thejobs = []
for job in jobs:
cpu = '%s.run%d' % (job.system, self.cpu)
symbols = self.getdata(job.name, cpu)
if symbols:
thejobs.append(job)
maxsymlen = max(maxsymlen, symbols.maxsymlen)
for job in thejobs:
cpu = '%s.run%d' % (job.system, self.cpu)
symbols = self.getdata(job.name, cpu)
print job.name
symbols.display(limit=limit, maxsymlen=maxsymlen)
print
from categories import func_categorize, pc_categorize
class PCProfile(Profile):
def __init__(self, categorize=pc_categorize):
super(PCProfile, self).__init__(PCData, categorize)
class FuncProfile(Profile):
def __init__(self, categorize=func_categorize):
super(FuncProfile, self).__init__(FuncData, categorize)
def usage(exitcode = None):
print '''\
Usage: %s [-bc] [-g <dir>] [-j <jobfile>] [-n <num>]
-c groups symbols into categories
-b dumps data for bar charts
-d generate dot output
-g <d> draw graphs and send output to <d>
-j <jobfile> specify a different jobfile (default is Test.py)
-n <n> selects number of top symbols to print (default 5)
''' % sys.argv[0]
if exitcode is not None:
sys.exit(exitcode)
if __name__ == '__main__':
import getopt, re, sys
from os.path import expanduser
from output import StatOutput
# default option values
numsyms = 10
graph = None
cpus = [ 0 ]
categorize = False
showidle = True
funcdata = True
jobfilename = 'Test.py'
dodot = False
dotfile = None
textout = False
threshold = 0.01
inputfile = None
try:
opts, args = getopt.getopt(sys.argv[1:], 'C:cdD:f:g:ij:n:pT:t')
except getopt.GetoptError:
usage(2)
for o,a in opts:
if o == '-C':
cpus = [ int(x) for x in a.split(',') ]
elif o == '-c':
categorize = True
elif o == '-D':
dotfile = a
elif o == '-d':
dodot = True
elif o == '-f':
inputfile = expanduser(a)
elif o == '-g':
graph = a
elif o == '-i':
showidle = False
elif o == '-j':
jobfilename = a
elif o == '-n':
numsyms = int(a)
elif o == '-p':
funcdata = False
elif o == '-T':
threshold = float(a)
elif o == '-t':
textout = True
if args:
print "'%s'" % args, len(args)
usage(1)
if inputfile:
catfunc = None
if categorize:
catfunc = func_categorize
data = FuncData(inputfile, categorize=catfunc)
if dodot:
import pydot
dot = pydot.Dot()
data.tree.dot(dot, threshold=threshold)
#dot.orientation = 'landscape'
#dot.ranksep='equally'
#dot.rank='samerank'
dot.write(dotfile, format='png')
else:
data.display(limit=numsyms)
else:
from jobfile import JobFile
jobfile = JobFile(jobfilename)
if funcdata:
profile = FuncProfile()
else:
profile = PCProfile()
if not categorize:
profile.categorize = None
profile.inputdir(jobfile.rootdir)
if graph:
for cpu in cpus:
profile.cpu = cpu
if funcdata:
name = 'funcstacks%d' % cpu
else:
name = 'stacks%d' % cpu
output = StatOutput(jobfile, info=profile)
output.xlabel = 'System Configuration'
output.ylabel = '% CPU utilization'
output.stat = name
output.graph(name, graph)
if dodot:
for cpu in cpus:
profile.cpu = cpu
profile.write_dot(jobfile=jobfile, threshold=threshold)
if textout:
for cpu in cpus:
profile.cpu = cpu
profile.write_txt(jobfile=jobfile)
if not graph and not textout and not dodot:
for cpu in cpus:
if not categorize:
profile.categorize = None
profile.cpu = cpu
profile.display(jobfile=jobfile, limit=numsyms)

View File

@ -0,0 +1,486 @@
#!/usr/bin/env python
# Copyright (c) 2003-2004 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
import re, sys, math
def usage():
print '''\
Usage: %s [-E] [-F] [ -G <get> ] [-d <db> ] [-g <graphdir> ] [-h <host>] [-p]
[-s <system>] [-r <runs> ] [-T <samples>] [-u <username>]
<command> [command args]
commands extra parameters description
----------- ------------------ ---------------------------------------
formula <formula> Evaluated formula specified
formulas [regex] List formulas (only matching regex)
runs none List all runs in database
samples none List samples present in database
stability <pairnum> <stats> Calculated statistical info about stats
stat <regex> Show stat data (only matching regex)
stats [regex] List all stats (only matching regex)
database <command> Where command is drop, init, or clean
''' % sys.argv[0]
sys.exit(1)
def getopts(list, flags):
import getopt
try:
opts, args = getopt.getopt(list, flags)
except getopt.GetoptError:
usage()
return opts, args
class CommandException(Exception):
pass
def commands(options, command, args):
if command == 'database':
if len(args) == 0: raise CommandException
import dbinit
mydb = dbinit.MyDB(options)
if args[0] == 'drop':
if len(args) > 2: raise CommandException
mydb.admin()
mydb.drop()
if len(args) == 2 and args[1] == 'init':
mydb.create()
mydb.connect()
mydb.populate()
mydb.close()
return
if args[0] == 'init':
if len(args) > 1: raise CommandException
mydb.admin()
mydb.create()
mydb.connect()
mydb.populate()
mydb.close()
return
if args[0] == 'clean':
if len(args) > 1: raise CommandException
mydb.connect()
mydb.clean()
return
raise CommandException
import db
source = db.Database()
source.host = options.host
source.db = options.db
source.passwd = options.passwd
source.user = options.user
source.connect()
#source.update_dict(globals())
if type(options.method) is str:
source.method = options.method
if options.runs is None:
runs = source.allRuns
else:
rx = re.compile(options.runs)
runs = []
for run in source.allRuns:
if rx.match(run.name):
runs.append(run)
if command == 'runs':
user = None
opts, args = getopts(args, '-u')
if len(args):
raise CommandException
for o,a in opts:
if o == '-u':
user = a
source.listRuns(user)
return
if command == 'stats':
if len(args) == 0:
source.listStats()
elif len(args) == 1:
source.listStats(args[0])
else:
raise CommandException
return
if command == 'formulas':
if len(args) == 0:
source.listFormulas()
elif len(args) == 1:
source.listFormulas(args[0])
else:
raise CommandException
return
if command == 'samples':
if len(args):
raise CommandException
source.listTicks(runs)
return
if command == 'stability':
if len(args) < 2:
raise CommandException
try:
merge = int(args[0])
except ValueError:
usage()
stats = source.getStat(args[1])
source.method = 'sum'
def disp(*args):
print "%-35s %12s %12s %4s %5s %5s %5s %10s" % args
# temporary variable containing a bunch of dashes
d = '-' * 100
#loop through all the stats selected
for stat in stats:
print "%s:" % stat.name
disp("run name", "average", "stdev", ">10%", ">1SDV", ">2SDV",
"SAMP", "CV")
disp(d[:35], d[:12], d[:12], d[:4], d[:5], d[:5], d[:5], d[:10])
#loop through all the selected runs
for run in runs:
runTicks = source.retTicks([ run ])
#throw away the first one, it's 0
runTicks.pop(0)
source.ticks = runTicks
avg = 0
stdev = 0
numoutsideavg = 0
numoutside1std = 0
numoutside2std = 0
pairRunTicks = []
if value(stat, run.run) == 1e300*1e300:
continue
for t in range(0, len(runTicks)-(merge-1), merge):
tempPair = []
for p in range(0,merge):
tempPair.append(runTicks[t+p])
pairRunTicks.append(tempPair)
#loop through all the various ticks for each run
for tick in pairRunTicks:
source.ticks = tick
avg += value(stat, run.run)
avg /= len(pairRunTicks)
for tick in pairRunTicks:
source.ticks = tick
val = value(stat, run.run)
stdev += pow((val-avg),2)
stdev = math.sqrt(stdev / len(pairRunTicks))
for tick in pairRunTicks:
source.ticks = tick
val = value(stat, run.run)
if (val < (avg * .9)) or (val > (avg * 1.1)):
numoutsideavg += 1
if (val < (avg - stdev)) or (val > (avg + stdev)):
numoutside1std += 1
if (val < (avg - (2*stdev))) or (val > (avg + (2*stdev))):
numoutside2std += 1
if avg > 1000:
disp(run.name, "%.1f" % avg, "%.1f" % stdev,
"%d" % numoutsideavg, "%d" % numoutside1std,
"%d" % numoutside2std, "%d" % len(pairRunTicks),
"%.3f" % (stdev/avg*100))
elif avg > 100:
disp(run.name, "%.1f" % avg, "%.1f" % stdev,
"%d" % numoutsideavg, "%d" % numoutside1std,
"%d" % numoutside2std, "%d" % len(pairRunTicks),
"%.5f" % (stdev/avg*100))
else:
disp(run.name, "%.5f" % avg, "%.5f" % stdev,
"%d" % numoutsideavg, "%d" % numoutside1std,
"%d" % numoutside2std, "%d" % len(pairRunTicks),
"%.7f" % (stdev/avg*100))
return
if command == 'all':
if len(args):
raise CommandException
all = [ 'bps', 'misses', 'mpkb', 'ipkb', 'pps', 'bpt' ]
for command in all:
commands(options, command, args)
if options.ticks:
if not options.graph:
print 'only displaying sample %s' % options.ticks
source.ticks = [ int(x) for x in options.ticks.split() ]
from output import StatOutput
output = StatOutput(options.jobfile, source)
output.xlabel = 'System Configuration'
output.colormap = 'RdYlGn'
if command == 'stat' or command == 'formula':
if len(args) != 1:
raise CommandException
if command == 'stat':
stats = source.getStat(args[0])
if command == 'formula':
stats = eval(args[0])
for stat in stats:
output.stat = stat
output.ylabel = stat.name
if options.graph:
output.graph(stat.name, options.graphdir)
else:
output.display(stat.name, options.printmode)
return
if len(args):
raise CommandException
from info import ProxyGroup
proxy = ProxyGroup(system = source[options.system])
system = proxy.system
etherdev = system.tsunami.etherdev0
bytes = etherdev.rxBytes + etherdev.txBytes
kbytes = bytes / 1024
packets = etherdev.rxPackets + etherdev.txPackets
def display():
if options.graph:
output.graph(command, options.graphdir, proxy)
else:
output.display(command, options.printmode)
if command == 'ticks':
output.stat = system.run0.numCycles
display()
return
if command == 'bytes':
output.stat = bytes
display()
return
if command == 'packets':
output.stat = packets
display()
return
if command == 'ppt' or command == 'tpp':
output.stat = packets / system.run0.numCycles
output.invert = command == 'tpp'
display()
return
if command == 'pps':
output.stat = packets / source['sim_seconds']
output.ylabel = 'Packets/s'
display()
return
if command == 'bpt' or command == 'tpb':
output.stat = bytes / system.run0.numCycles * 8
output.ylabel = 'bps / Hz'
output.invert = command == 'tpb'
display()
return
if command in ('rxbps', 'txbps', 'bps'):
if command == 'rxbps':
output.stat = etherdev.rxBandwidth / 1e9
if command == 'txbps':
output.stat = etherdev.txBandwidth / 1e9
if command == 'bps':
output.stat = (etherdev.rxBandwidth + etherdev.txBandwidth) / 1e9
output.ylabel = 'Bandwidth (Gbps)'
output.ylim = [ 0.0, 10.0 ]
display()
return
if command == 'bpp':
output.stat = bytes / packets
output.ylabel = 'Bytes / Packet'
display()
return
if command == 'rxbpp':
output.stat = etherdev.rxBytes / etherdev.rxPackets
output.ylabel = 'Receive Bytes / Packet'
display()
return
if command == 'txbpp':
output.stat = etherdev.txBytes / etherdev.txPackets
output.ylabel = 'Transmit Bytes / Packet'
display()
return
if command == 'rtp':
output.stat = etherdev.rxPackets / etherdev.txPackets
output.ylabel = 'rxPackets / txPackets'
display()
return
if command == 'rtb':
output.stat = etherdev.rxBytes / etherdev.txBytes
output.ylabel = 'rxBytes / txBytes'
display()
return
misses = system.l2.overall_mshr_misses
if command == 'misses':
output.stat = misses
output.ylabel = 'Overall MSHR Misses'
display()
return
if command == 'mpkb':
output.stat = misses / (bytes / 1024)
output.ylabel = 'Misses / KB'
display()
return
if command == 'ipkb':
interrupts = system.run0.kern.faults[4]
output.stat = interrupts / kbytes
output.ylabel = 'Interrupts / KB'
display()
return
if command == 'execute':
output.stat = system.run0.ISSUE__count
display()
return
if command == 'commit':
output.stat = system.run0.COM__count
display()
return
if command == 'fetch':
output.stat = system.run0.FETCH__count
display()
return
raise CommandException
class Options: pass
if __name__ == '__main__':
import getpass
options = Options()
options.host = None
options.db = None
options.passwd = ''
options.user = getpass.getuser()
options.runs = None
options.system = 'client'
options.method = None
options.graph = False
options.ticks = False
options.printmode = 'G'
jobfilename = None
options.jobfile = None
options.all = False
opts, args = getopts(sys.argv[1:], '-EFJad:g:h:j:m:pr:s:u:T:')
for o,a in opts:
if o == '-E':
options.printmode = 'E'
if o == '-F':
options.printmode = 'F'
if o == '-a':
options.all = True
if o == '-d':
options.db = a
if o == '-g':
options.graph = True;
options.graphdir = a
if o == '-h':
options.host = a
if o == '-J':
jobfilename = None
if o == '-j':
jobfilename = a
if o == '-m':
options.method = a
if o == '-p':
options.passwd = getpass.getpass()
if o == '-r':
options.runs = a
if o == '-u':
options.user = a
if o == '-s':
options.system = a
if o == '-T':
options.ticks = a
if jobfilename:
from jobfile import JobFile
options.jobfile = JobFile(jobfilename)
if not options.host:
options.host = options.jobfile.dbhost
if not options.db:
options.db = options.jobfile.statdb
if not options.host:
sys.exit('Database server must be provided from a jobfile or -h')
if not options.db:
sys.exit('Database name must be provided from a jobfile or -d')
if len(args) == 0:
usage()
command = args[0]
args = args[1:]
try:
commands(options, command, args)
except CommandException:
usage()

View File

@ -0,0 +1,551 @@
#! /usr/bin/env python
# Copyright (c) 2006 The Regents of The University of Michigan
# Copyright (c) 2007,2011 The Hewlett-Packard Development Company
# 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
import heapq
import os
import re
import sys
from os.path import dirname, join as joinpath
from itertools import count
from mercurial import bdiff, mdiff
current_dir = dirname(__file__)
sys.path.insert(0, current_dir)
sys.path.insert(1, joinpath(dirname(current_dir), 'src', 'python'))
from m5.util import neg_inf, pos_inf, Region, Regions
import sort_includes
from file_types import lang_type
all_regions = Regions(Region(neg_inf, pos_inf))
tabsize = 8
lead = re.compile(r'^([ \t]+)')
trail = re.compile(r'([ \t]+)$')
any_control = re.compile(r'\b(if|while|for)[ \t]*[(]')
good_control = re.compile(r'\b(if|while|for) [(]')
format_types = set(('C', 'C++'))
def modified_regions(old_data, new_data):
regions = Regions()
beg = None
for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data):
if beg is not None and beg != fbeg:
regions.append(beg, fbeg)
beg = fend
return regions
def modregions(wctx, fname):
fctx = wctx.filectx(fname)
pctx = fctx.parents()
file_data = fctx.data()
lines = mdiff.splitnewlines(file_data)
if len(pctx) in (1, 2):
mod_regions = modified_regions(pctx[0].data(), file_data)
if len(pctx) == 2:
m2 = modified_regions(pctx[1].data(), file_data)
# only the lines that are new in both
mod_regions &= m2
else:
mod_regions = Regions()
mod_regions.add(0, len(lines))
return mod_regions
class UserInterface(object):
def __init__(self, verbose=False, auto=False):
self.auto = auto
self.verbose = verbose
def prompt(self, prompt, results, default):
if self.auto:
return self.auto
while True:
result = self.do_prompt(prompt, results, default)
if result in results:
return result
class MercurialUI(UserInterface):
def __init__(self, ui, *args, **kwargs):
super(MercurialUI, self).__init__(*args, **kwargs)
self.ui = ui
def do_prompt(self, prompt, results, default):
return self.ui.prompt(prompt, default=default)
def write(self, string):
self.ui.write(string)
class StdioUI(UserInterface):
def do_prompt(self, prompt, results, default):
return raw_input(prompt) or default
def write(self, string):
sys.stdout.write(string)
class Verifier(object):
def __init__(self, ui, repo=None):
self.ui = ui
self.repo = repo
if repo is None:
self.wctx = None
def __getattr__(self, attr):
if attr in ('prompt', 'write'):
return getattr(self.ui, attr)
if attr == 'wctx':
try:
wctx = repo.workingctx()
except:
from mercurial import context
wctx = context.workingctx(repo)
self.wctx = wctx
return wctx
raise AttributeError
def open(self, filename, mode):
if self.repo:
filename = self.repo.wjoin(filename)
try:
f = file(filename, mode)
except OSError, msg:
print 'could not open file %s: %s' % (filename, msg)
return None
return f
def skip(self, filename):
return lang_type(filename) not in self.languages
def check(self, filename, regions=all_regions):
f = self.open(filename, 'r')
errors = 0
for num,line in enumerate(f):
if num not in regions:
continue
if not self.check_line(line):
self.write("invalid %s in %s:%d\n" % \
(self.test_name, filename, num + 1))
if self.ui.verbose:
self.write(">>%s<<\n" % line[-1])
errors += 1
return errors
def fix(self, filename, regions=all_regions):
f = self.open(filename, 'r+')
lines = list(f)
f.seek(0)
f.truncate()
for i,line in enumerate(lines):
if i in regions:
line = self.fix_line(line)
f.write(line)
f.close()
def apply(self, filename, prompt, regions=all_regions):
if not self.skip(filename):
errors = self.check(filename, regions)
if errors:
if prompt(filename, self.fix, regions):
return True
return False
class Whitespace(Verifier):
languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
test_name = 'whitespace'
def check_line(self, line):
match = lead.search(line)
if match and match.group(1).find('\t') != -1:
return False
match = trail.search(line)
if match:
return False
return True
def fix_line(self, line):
if lead.search(line):
newline = ''
for i,c in enumerate(line):
if c == ' ':
newline += ' '
elif c == '\t':
newline += ' ' * (tabsize - len(newline) % tabsize)
else:
newline += line[i:]
break
line = newline
return line.rstrip() + '\n'
class SortedIncludes(Verifier):
languages = sort_includes.default_languages
def __init__(self, *args, **kwargs):
super(SortedIncludes, self).__init__(*args, **kwargs)
self.sort_includes = sort_includes.SortIncludes()
def check(self, filename, regions=all_regions):
f = self.open(filename, 'r')
lines = [ l.rstrip('\n') for l in f.xreadlines() ]
old = ''.join(line + '\n' for line in lines)
f.close()
if len(lines) == 0:
return 0
language = lang_type(filename, lines[0])
sort_lines = list(self.sort_includes(lines, filename, language))
new = ''.join(line + '\n' for line in sort_lines)
mod = modified_regions(old, new)
modified = mod & regions
if modified:
self.write("invalid sorting of includes\n")
if self.ui.verbose:
for start, end in modified.regions:
self.write("bad region [%d, %d)\n" % (start, end))
return 1
return 0
def fix(self, filename, regions=all_regions):
f = self.open(filename, 'r+')
old = f.readlines()
lines = [ l.rstrip('\n') for l in old ]
language = lang_type(filename, lines[0])
sort_lines = list(self.sort_includes(lines, filename, language))
new = ''.join(line + '\n' for line in sort_lines)
f.seek(0)
f.truncate()
for i,line in enumerate(sort_lines):
f.write(line)
f.write('\n')
f.close()
def linelen(line):
tabs = line.count('\t')
if not tabs:
return len(line)
count = 0
for c in line:
if c == '\t':
count += tabsize - count % tabsize
else:
count += 1
return count
class ValidationStats(object):
def __init__(self):
self.toolong = 0
self.toolong80 = 0
self.leadtabs = 0
self.trailwhite = 0
self.badcontrol = 0
self.cret = 0
def dump(self):
print '''\
%d violations of lines over 79 chars. %d of which are 80 chars exactly.
%d cases of whitespace at the end of a line.
%d cases of tabs to indent.
%d bad parens after if/while/for.
%d carriage returns found.
''' % (self.toolong, self.toolong80, self.trailwhite, self.leadtabs,
self.badcontrol, self.cret)
def __nonzero__(self):
return self.toolong or self.toolong80 or self.leadtabs or \
self.trailwhite or self.badcontrol or self.cret
def validate(filename, stats, verbose, exit_code):
if lang_type(filename) not in format_types:
return
def msg(lineno, line, message):
print '%s:%d>' % (filename, lineno + 1), message
if verbose > 2:
print line
def bad():
if exit_code is not None:
sys.exit(exit_code)
try:
f = file(filename, 'r')
except OSError:
if verbose > 0:
print 'could not open file %s' % filename
bad()
return
for i,line in enumerate(f):
line = line.rstrip('\n')
# no carriage returns
if line.find('\r') != -1:
self.cret += 1
if verbose > 1:
msg(i, line, 'carriage return found')
bad()
# lines max out at 79 chars
llen = linelen(line)
if llen > 79:
stats.toolong += 1
if llen == 80:
stats.toolong80 += 1
if verbose > 1:
msg(i, line, 'line too long (%d chars)' % llen)
bad()
# no tabs used to indent
match = lead.search(line)
if match and match.group(1).find('\t') != -1:
stats.leadtabs += 1
if verbose > 1:
msg(i, line, 'using tabs to indent')
bad()
# no trailing whitespace
if trail.search(line):
stats.trailwhite +=1
if verbose > 1:
msg(i, line, 'trailing whitespace')
bad()
# for c++, exactly one space betwen if/while/for and (
if cpp:
match = any_control.search(line)
if match and not good_control.search(line):
stats.badcontrol += 1
if verbose > 1:
msg(i, line, 'improper spacing after %s' % match.group(1))
bad()
def do_check_style(hgui, repo, *files, **args):
"""check files for proper m5 style guidelines"""
from mercurial import mdiff, util
auto = args.get('auto', False)
if auto:
auto = 'f'
ui = MercurialUI(hgui, hgui.verbose, auto)
if files:
files = frozenset(files)
def skip(name):
return files and name in files
def prompt(name, func, regions=all_regions):
result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", 'aif', 'a')
if result == 'a':
return True
elif result == 'f':
func(repo.wjoin(name), regions)
return False
modified, added, removed, deleted, unknown, ignore, clean = repo.status()
whitespace = Whitespace(ui)
sorted_includes = SortedIncludes(ui)
for fname in added:
if skip(fname):
continue
fpath = joinpath(repo.root, fname)
if whitespace.apply(fpath, prompt):
return True
if sorted_includes.apply(fpath, prompt):
return True
try:
wctx = repo.workingctx()
except:
from mercurial import context
wctx = context.workingctx(repo)
for fname in modified:
if skip(fname):
continue
fpath = joinpath(repo.root, fname)
regions = modregions(wctx, fname)
if whitespace.apply(fpath, prompt, regions):
return True
if sorted_includes.apply(fpath, prompt, regions):
return True
return False
def do_check_format(hgui, repo, **args):
ui = MercurialUI(hgui, hgui.verbose, auto)
modified, added, removed, deleted, unknown, ignore, clean = repo.status()
verbose = 0
stats = ValidationStats()
for f in modified + added:
validate(joinpath(repo.root, f), stats, verbose, None)
if stats:
stats.dump()
result = ui.prompt("invalid formatting\n(i)gnore or (a)bort?",
'ai', 'a')
if result == 'a':
return True
return False
def check_hook(hooktype):
if hooktype not in ('pretxncommit', 'pre-qrefresh'):
raise AttributeError, \
"This hook is not meant for %s" % hooktype
def check_style(ui, repo, hooktype, **kwargs):
check_hook(hooktype)
args = {}
try:
return do_check_style(ui, repo, **args)
except Exception, e:
import traceback
traceback.print_exc()
return True
def check_format(ui, repo, hooktype, **kwargs):
check_hook(hooktype)
args = {}
try:
return do_check_format(ui, repo, **args)
except Exception, e:
import traceback
traceback.print_exc()
return True
try:
from mercurial.i18n import _
except ImportError:
def _(arg):
return arg
cmdtable = {
'^m5style' :
( do_check_style,
[ ('a', 'auto', False, _("automatically fix whitespace")) ],
_('hg m5style [-a] [FILE]...')),
'^m5format' :
( do_check_format,
[ ],
_('hg m5format [FILE]...')),
}
if __name__ == '__main__':
import getopt
progname = sys.argv[0]
if len(sys.argv) < 2:
sys.exit('usage: %s <command> [<command args>]' % progname)
fixwhite_usage = '%s fixwhite [-t <tabsize> ] <path> [...] \n' % progname
chkformat_usage = '%s chkformat <path> [...] \n' % progname
chkwhite_usage = '%s chkwhite <path> [...] \n' % progname
command = sys.argv[1]
if command == 'fixwhite':
flags = 't:'
usage = fixwhite_usage
elif command == 'chkwhite':
flags = 'nv'
usage = chkwhite_usage
elif command == 'chkformat':
flags = 'nv'
usage = chkformat_usage
else:
sys.exit(fixwhite_usage + chkwhite_usage + chkformat_usage)
opts, args = getopt.getopt(sys.argv[2:], flags)
code = 1
verbose = 1
for opt,arg in opts:
if opt == '-n':
code = None
if opt == '-t':
tabsize = int(arg)
if opt == '-v':
verbose += 1
if command == 'fixwhite':
for filename in args:
fixwhite(filename, tabsize)
elif command == 'chkwhite':
for filename in args:
for line,num in checkwhite(filename):
print 'invalid whitespace: %s:%d' % (filename, num)
if verbose:
print '>>%s<<' % line[:-1]
elif command == 'chkformat':
stats = ValidationStats()
for filename in args:
validate(filename, stats=stats, verbose=verbose, exit_code=code)
if verbose > 0:
stats.dump()
else:
sys.exit("command '%s' not found" % command)

View File

@ -0,0 +1,538 @@
/*
* Copyright (c) 2003-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
*/
extern "C" {
#include <pcap.h>
}
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <dnet.h>
#include <fcntl.h>
#include <libgen.h>
#include <netdb.h>
#include <poll.h>
#include <unistd.h>
#include <cerrno>
#include <csignal>
#include <list>
#include <string>
#include "base/cprintf.hh"
#define panic(arg...) \
do { cprintf("Panic: " arg); exit(1); } while (0)
char *program = "ethertap";
void
usage()
{
cprintf(
"usage: \n"
"\t%s [-b bufsize] [-d] [-f filter] [-p port] [-v] <device> <host>\n"
"\t%s [-b bufsize] [-d] [-f filter] [-l] [-p port] [-v] <device>\n",
program, program);
exit(2);
}
int verbose = 0;
#define DPRINTF(args...) do { \
if (verbose >= 1) \
cprintf(args); \
} while (0)
#define DDUMP(args...) do { \
if (verbose >= 2) \
dump((const u_char *)args); \
} while (0)
void
dump(const u_char *data, int len)
{
int c, i, j;
for (i = 0; i < len; i += 16) {
cprintf("%08x ", i);
c = len - i;
if (c > 16) c = 16;
for (j = 0; j < c; j++) {
cprintf("%02x ", data[i + j] & 0xff);
if ((j & 0xf) == 7 && j > 0)
cprintf(" ");
}
for (; j < 16; j++)
cprintf(" ");
cprintf(" ");
for (j = 0; j < c; j++) {
int ch = data[i + j] & 0x7f;
cprintf("%c", (char)(isprint(ch) ? ch : ' '));
}
cprintf("\n");
if (c < 16)
break;
}
}
bool quit = false;
void
quit_now(int sigtype)
{
DPRINTF("User requested exit\n");
quit = true;
}
int
Socket(int reuse)
{
int fd = ::socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0)
panic("Can't create socket!\n");
if (reuse) {
int i = 1;
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i,
sizeof(i)) < 0)
panic("setsockopt() SO_REUSEADDR failed!\n");
}
return fd;
}
void
Listen(int fd, int port)
{
struct sockaddr_in sockaddr;
sockaddr.sin_family = PF_INET;
sockaddr.sin_addr.s_addr = INADDR_ANY;
sockaddr.sin_port = htons(port);
int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr));
if (ret == -1)
panic("bind() failed!\n");
if (::listen(fd, 1) == -1)
panic("listen() failed!\n");
}
// Open a connection. Accept will block, so if you don't want it to,
// make sure a connection is ready before you call accept.
int
Accept(int fd, bool nodelay)
{
struct sockaddr_in sockaddr;
socklen_t slen = sizeof (sockaddr);
int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
if (sfd == -1)
panic("accept() failed!\n");
if (nodelay) {
int i = 1;
::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
}
return sfd;
}
void
Connect(int fd, const std::string &host, int port)
{
struct sockaddr_in sockaddr;
if (::inet_aton(host.c_str(), &sockaddr.sin_addr) == 0) {
struct hostent *hp;
hp = ::gethostbyname(host.c_str());
if (!hp)
panic("Host %s not found\n", host);
sockaddr.sin_family = hp->h_addrtype;
memcpy(&sockaddr.sin_addr, hp->h_addr, hp->h_length);
}
sockaddr.sin_port = htons(port);
if (::connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0)
panic("could not connect to %s on port %d\n", host, port);
DPRINTF("connected to %s on port %d\n", host, port);
}
class Ethernet
{
protected:
int fd;
public:
virtual ~Ethernet() {}
int getfd() const { return fd; }
virtual bool read(const char *&data, int &len) = 0;
virtual bool write(const char *data, int len) = 0;
};
class Tap : public Ethernet
{
private:
char buffer[65536];
int fd;
public:
Tap(char *device);
~Tap();
virtual bool read(const char *&data, int &len);
virtual bool write(const char *data, int len);
};
class PCap : public Ethernet
{
private:
pcap_t *pcap;
eth_t *ethernet;
public:
PCap(char *device, char *filter = NULL);
~PCap();
virtual bool read(const char *&data, int &len);
virtual bool write(const char *data, int len);
};
PCap::PCap(char *device, char *filter)
{
char errbuf[PCAP_ERRBUF_SIZE];
memset(errbuf, 0, sizeof errbuf);
pcap = pcap_open_live(device, 1500, 1, -1, errbuf);
if (pcap == NULL)
panic("pcap_open_live failed: %s\n", errbuf);
if (filter) {
bpf_program program;
bpf_u_int32 localnet, netmask;
if (pcap_lookupnet(device, &localnet, &netmask, errbuf) == -1) {
DPRINTF("pcap_lookupnet failed: %s\n", errbuf);
netmask = 0xffffff00;
}
if (pcap_compile(pcap, &program, filter, 1, netmask) == -1)
panic("pcap_compile failed, invalid filter:\n%s\n", filter);
if (pcap_setfilter(pcap, &program) == -1)
panic("pcap_setfilter failed\n");
}
ethernet = eth_open(device);
if (!ethernet)
panic("cannot open the ethernet device for writing\n");
fd = pcap_fileno(pcap);
}
PCap::~PCap()
{
pcap_close(pcap);
eth_close(ethernet);
}
bool
PCap::read(const char *&data, int &len)
{
pcap_pkthdr hdr;
data = (const char *)pcap_next(pcap, &hdr);
if (!data)
return false;
len = hdr.len;
return true;
}
bool
PCap::write(const char *data, int len)
{
eth_send(ethernet, data, len);
}
Tap::Tap(char *device)
{
fd = open(device, O_RDWR, 0);
if (fd < 0)
panic("could not open %s: %s\n", device, strerror(errno));
}
Tap::~Tap()
{
close(fd);
}
bool
Tap::read(const char *&data, int &len)
{
DPRINTF("tap read!\n");
data = buffer;
len = ::read(fd, buffer, sizeof(buffer));
if (len < 0)
return false;
return true;
}
bool
Tap::write(const char *data, int len)
{
int result = ::write(fd, data, len);
if (result < 0)
return false;
return true;
}
int
main(int argc, char *argv[])
{
int port = 3500;
int bufsize = 2000;
bool listening = false;
char *device = NULL;
char *filter = NULL;
Ethernet *tap = NULL;
bool usetap = false;
char c;
int daemon = false;
std::string host;
int devfd;
program = basename(argv[0]);
while ((c = getopt(argc, argv, "b:df:lp:tv")) != -1) {
switch (c) {
case 'b':
bufsize = atoi(optarg);
break;
case 'd':
daemon = true;
break;
case 'f':
filter = optarg;
break;
case 'l':
listening = true;
break;
case 'p':
port = atoi(optarg);
break;
case 't':
usetap = true;
break;
case 'v':
verbose++;
break;
default:
usage();
break;
}
}
signal(SIGINT, quit_now);
signal(SIGTERM, quit_now);
signal(SIGHUP, quit_now);
if (daemon) {
verbose = 0;
switch(fork()) {
case -1:
panic("Fork failed\n");
case 0:
break;
default:
exit(0);
}
}
char *buffer = new char[bufsize];
argc -= optind;
argv += optind;
if (argc-- == 0)
usage();
device = *argv++;
if (listening) {
if (argc)
usage();
} else {
if (argc != 1)
usage();
host = *argv;
}
if (usetap) {
if (filter)
panic("-f parameter not valid with a tap device!");
tap = new Tap(device);
} else {
tap = new PCap(device, filter);
}
pollfd pfds[3];
pfds[0].fd = Socket(true);
pfds[0].events = POLLIN;
pfds[0].revents = 0;
if (listening)
Listen(pfds[0].fd, port);
else
Connect(pfds[0].fd, host, port);
pfds[1].fd = tap->getfd();
pfds[1].events = POLLIN;
pfds[1].revents = 0;
pfds[2].fd = 0;
pfds[2].events = POLLIN|POLLERR;
pfds[2].revents = 0;
pollfd *listen_pfd = listening ? &pfds[0] : NULL;
pollfd *tap_pfd = &pfds[1];
pollfd *client_pfd = listening ? NULL : &pfds[0];
int npfds = 2;
int32_t buffer_offset = 0;
int32_t data_len = 0;
DPRINTF("Begin poll loop\n");
while (!quit) {
int ret = ::poll(pfds, npfds, INFTIM);
if (ret < 0)
continue;
if (listen_pfd && listen_pfd->revents) {
if (listen_pfd->revents & POLLIN) {
int fd = Accept(listen_pfd->fd, false);
if (client_pfd) {
DPRINTF("Connection rejected\n");
close(fd);
} else {
DPRINTF("Connection accepted\n");
client_pfd = &pfds[2];
client_pfd->fd = fd;
npfds++;
}
}
listen_pfd->revents = 0;
}
DPRINTF("tap events: %x\n", tap_pfd->revents);
if (tap_pfd && tap_pfd->revents) {
if (tap_pfd->revents & POLLIN) {
const char *data; int len;
if (tap->read(data, len) && client_pfd) {
DPRINTF("Received packet from ethernet len=%d\n", len);
DDUMP(data, len);
u_int32_t swaplen = htonl(len);
write(client_pfd->fd, &swaplen, sizeof(swaplen));
write(client_pfd->fd, data, len);
}
}
tap_pfd->revents = 0;
}
if (client_pfd && client_pfd->revents) {
if (client_pfd->revents & POLLIN) {
if (buffer_offset < data_len + sizeof(u_int32_t)) {
int len = read(client_pfd->fd, buffer + buffer_offset,
bufsize - buffer_offset);
if (len <= 0) {
perror("read");
goto error;
}
buffer_offset += len;
if (data_len == 0)
data_len = ntohl(*(u_int32_t *)buffer);
DPRINTF("Received data from peer: len=%d buffer_offset=%d "
"data_len=%d\n", len, buffer_offset, data_len);
}
while (data_len != 0 &&
buffer_offset >= data_len + sizeof(u_int32_t)) {
char *data = buffer + sizeof(u_int32_t);
tap->write(data, data_len);
DPRINTF("Sent packet to ethernet len = %d\n", data_len);
DDUMP(data, data_len);
buffer_offset -= data_len + sizeof(u_int32_t);
if (buffer_offset > 0 && data_len > 0) {
memmove(buffer, data + data_len, buffer_offset);
data_len = ntohl(*(u_int32_t *)buffer);
} else
data_len = 0;
}
}
if (client_pfd->revents & POLLERR) {
error:
DPRINTF("Error on client socket\n");
close(client_pfd->fd);
client_pfd = NULL;
if (listening)
npfds--;
else {
DPRINTF("Calling it quits because of poll error\n");
quit = true;
}
}
if (client_pfd)
client_pfd->revents = 0;
}
}
delete [] buffer;
delete tap;
if (listen_pfd)
close(listen_pfd->fd);
if (client_pfd)
close(client_pfd->fd);
return 0;
}

View File

@ -0,0 +1,321 @@
/* $OpenBSD: netcat.c,v 1.57 2002/12/30 18:00:18 stevesk Exp $ */
/*
* Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#include <arpa/telnet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/termios.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <poll.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
void readwrite(int);
int remote_connect(char *, char *, struct addrinfo);
struct termios saved_ios;
void raw_term();
void restore_term();
char progname[256];
void usage(int);
int
main(int argc, char *argv[])
{
int ch, s, ret;
char *host, *port, *endp;
struct addrinfo hints;
socklen_t len;
ret = 1;
s = 0;
host = NULL;
port = NULL;
endp = NULL;
strncpy(progname, argv[0], sizeof progname);
/* Cruft to make sure options are clean, and used properly. */
if (argc == 2) {
host = "localhost";
port = argv[1];
} else if (argc == 3) {
host = argv[1];
port = argv[2];
} else {
usage(1);
}
if (!isatty(STDIN_FILENO))
errx(1, "not attached to a terminal");
raw_term();
/* Initialize addrinfo structure */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
s = remote_connect(host, port, hints);
ret = 0;
readwrite(s);
if (s)
close(s);
exit(ret);
}
/*
* remote_connect()
* Return's a socket connected to a remote host. Properly bind's to a local
* port or source address if needed. Return's -1 on failure.
*/
int
remote_connect(char *host, char *port, struct addrinfo hints)
{
struct addrinfo *res, *res0;
int s, error;
if ((error = getaddrinfo(host, port, &hints, &res)))
errx(1, "getaddrinfo: %s", gai_strerror(error));
res0 = res;
do {
if ((s = socket(res0->ai_family, res0->ai_socktype,
res0->ai_protocol)) < 0)
continue;
if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
break;
close(s);
s = -1;
} while ((res0 = res0->ai_next) != NULL);
freeaddrinfo(res);
return (s);
}
/*
* readwrite()
* Loop that selects on the network file descriptor and stdin.
* Changed from poll() by Ali Saidi to make work on Mac OS X >= 10.4
*/
void
readwrite(int nfd)
{
fd_set read_fds;
char buf[BUFSIZ];
int wfd = fileno(stdin), n, ret, max_fd;
int lfd = fileno(stdout);
int escape = 0;
struct timeval timeout;
if (nfd == -1)
return;
max_fd = nfd + 1;
while (1) {
FD_ZERO(&read_fds);
FD_SET(wfd, &read_fds);
FD_SET(nfd, &read_fds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
n = select(max_fd, &read_fds, NULL, NULL, &timeout);
if (n < 0) {
close(nfd);
perror("Select Error:");
}
if (n == 0) {
if (read(nfd, buf, 0) < 0)
return;
continue;
}
if (read(nfd, buf, 0) < 0)
return;
if (FD_ISSET(nfd, &read_fds)) {
if ((n = read(nfd, buf, sizeof(buf))) < 0)
return;
else if (n == 0) {
shutdown(nfd, SHUT_RD);
return;
} else {
if ((ret = atomicio(write, lfd, buf, n)) != n)
return;
}
}
if (FD_ISSET(wfd, &read_fds)) {
if ((n = read(wfd, buf, sizeof(buf))) < 0)
return;
else if (n == 0) {
shutdown(nfd, SHUT_WR);
} else {
if (escape) {
char buf2[] = "~";
if (*buf == '.') {
printf("quit!\n");
return;
}
escape = 0;
if (*buf != '~' &&
(ret = atomicio(write, nfd, buf2, 1)) != n)
return;
} else {
escape = (*buf == '~');
if (escape)
continue;
}
if ((ret = atomicio(write, nfd, buf, n)) != n)
return;
}
}
} // while
}
void
usage(int ret)
{
fprintf(stderr, "usage: %s hostname port\n", progname);
if (ret)
exit(1);
}
/*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* ensure all of data on socket comes through. f==read || f==write
*/
ssize_t
atomicio(ssize_t (*f) (), int fd, void *_s, size_t n)
{
char *s = _s;
ssize_t res, pos = 0;
while (n > pos) {
res = (f) (fd, s + pos, n - pos);
switch (res) {
case -1:
if (errno == EINTR || errno == EAGAIN)
continue;
case 0:
return (res);
default:
pos += res;
}
}
return (pos);
}
/*
* Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
void
raw_term()
{
struct termios ios;
if (tcgetattr(STDIN_FILENO, &ios) < 0)
errx(1, "tcgetagttr\n");
memcpy(&saved_ios, &ios, sizeof(struct termios));
ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON);
ios.c_oflag &= ~(OPOST);
ios.c_oflag &= (ONLCR);
ios.c_lflag &= ~(ISIG|ICANON|ECHO);
ios.c_cc[VMIN] = 1;
ios.c_cc[VTIME] = 0;
if (tcsetattr(STDIN_FILENO, TCSANOW, &ios) < 0)
errx(1, "tcsetattr\n");
atexit(restore_term);
}
void
restore_term()
{
tcsetattr(STDIN_FILENO, TCSANOW, &saved_ios);
}

153
simulators/gem5/util/tracediff Executable file
View File

@ -0,0 +1,153 @@
#! /usr/bin/env perl
# Copyright (c) 2003-2007 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: Steve Reinhardt
# Script to simplify using rundiff on trace outputs from two
# invocations of m5. Takes a common m5 command line with embedded
# alternatives and executes the two alternative commands in separate
# subdirectories with output piped to rundiff.
#
# ******Note that you need to enable some trace flags in the args in order
# to do anything useful!******
#
# Script arguments are handled uniformly as follows:
# - If the argument does not contain a '|' character, it is appended
# to both command lines.
# - If the argument has a '|' character in it, the text on either side
# of the '|' is appended to the respective command lines. Note that
# you'll have to quote the arg or escape the '|' with a backslash
# so that the shell doesn't think you're doing a pipe.
# - Arguments with '#' characters are split at those characters,
# processed for alternatives ('|'s) as independent terms, then
# pasted back into a single argument (without the '#'s). (Sort of
# inspired by the C preprocessor '##' token pasting operator.)
#
# In other words, the arguments should look like the command line you
# want to run, with "|" used to list the alternatives for the parts
# that you want to differ between the two runs.
#
# For example:
#
# % tracediff m5.opt --opt1 '--opt2|--opt3' --opt4
# would compare these two runs:
# m5.opt --opt1 --opt2 --opt4
# m5.opt --opt1 --opt3 --opt4
#
# % tracediff 'path1|path2#/m5.opt' --opt1 --opt2
# would compare these two runs:
# path1/m5.opt --opt1 --opt2
# path2/m5.opt --opt1 --opt2
#
# If you want to add arguments to one run only, just put a '|' in with
# text only on one side ('--onlyOn1|'). You can do this with multiple
# arguments together too ('|-a -b -c' adds three args to the second
# run only).
#
# The '-n' argument to tracediff allows you to preview the two
# generated command lines without running them.
#
use FindBin;
$dryrun = 0;
if (@ARGV >= 1 && $ARGV[0] eq '-n') {
$dryrun = 1;
shift @ARGV;
}
if (@ARGV < 1) {
die "Usage: tracediff [-n] \"sim1|sim2\" [common-arg \"arg1|arg2\" ...]\n";
}
foreach $arg (@ARGV) {
$a1 = $a2 = '';
@subargs = split('#', $arg);
foreach $subarg (@subargs) {
if ($subarg eq '') {
next;
}
@pair = split('\|', $subarg, -1); # -1 enables null trailing fields
if (@pair == 1) {
$a1 .= $subarg;
$a2 .= $subarg;
} elsif (@pair == 2) {
$a1 .= $pair[0];
$a2 .= $pair[1];
} else {
print 'Parse error: too many |s in ', $arg, "\n";
exit(1);
}
}
push @cmd1, $a1;
push @cmd2, $a2;
}
if ($dryrun) {
print "CMD1: ", join(' ', @cmd1), "\n";
print "CMD2: ", join(' ', @cmd2), "\n";
exit(0);
}
# First two args are the two simulator binaries to compare
$sim1 = shift @cmd1;
$sim2 = shift @cmd2;
# Everything else is a simulator arg.
$args1 = join(' ', @cmd1);
$args2 = join(' ', @cmd2);
# Common mistake: if you don't set any debugflags this often isn't
# doing what you want.
if ($args1 !~ /--debug-flags/) {
print "****\n";
print "**** WARNING: no debug flags set... you may not be diffing much!\n";
print "****\n";
}
# Run individual invocations in separate dirs so output and intermediate
# files (particularly config.py and config.ini) don't conflict.
$dir1 = "tracediff-$$-1";
$dir2 = "tracediff-$$-2";
mkdir($dir1) or die "Can't create dir $dir1\n";
mkdir($dir2) or die "Can't create dir $dir2\n";
$cmd1 = "$sim1 -d $dir1 $args1 2>&1 |";
$cmd2 = "$sim2 -d $dir2 $args2 2>&1 |";
# Expect that rundiff is in the same dir as the tracediff script.
# FindBin figures that out for us.
$fullcmd = "$FindBin::Bin/rundiff '$cmd1' '$cmd2' 2>&1 > tracediff-$$.out";
print "Executing $fullcmd\n";
system($fullcmd);

View File

@ -0,0 +1,113 @@
{
python error
Memcheck:Cond
fun:PyObject_Free
}
{
python error
Memcheck:Addr1
fun:PyObject_Free
}
{
python error
Memcheck:Addr2
fun:PyObject_Free
}
{
python error
Memcheck:Addr4
fun:PyObject_Free
}
{
python error
Memcheck:Addr8
fun:PyObject_Free
}
{
python error
Memcheck:Addr16
fun:PyObject_Free
}
{
python error
Memcheck:Value1
fun:PyObject_Free
}
{
python error
Memcheck:Value2
fun:PyObject_Free
}
{
python error
Memcheck:Value4
fun:PyObject_Free
}
{
python error
Memcheck:Value8
fun:PyObject_Free
}
{
python error
Memcheck:Value16
fun:PyObject_Free
}
{
python error
Memcheck:Cond
fun:PyObject_Realloc
}
{
python error
Memcheck:Addr1
fun:PyObject_Realloc
}
{
python error
Memcheck:Addr2
fun:PyObject_Realloc
}
{
python error
Memcheck:Addr4
fun:PyObject_Realloc
}
{
python error
Memcheck:Addr8
fun:PyObject_Realloc
}
{
python error
Memcheck:Addr16
fun:PyObject_Realloc
}
{
python error
Memcheck:Value1
fun:PyObject_Realloc
}
{
python error
Memcheck:Value2
fun:PyObject_Realloc
}
{
python error
Memcheck:Value4
fun:PyObject_Realloc
}
{
python error
Memcheck:Value8
fun:PyObject_Realloc
}
{
python error
Memcheck:Value16
fun:PyObject_Realloc
}