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:
34
simulators/gem5/util/SConscript
Normal file
34
simulators/gem5/util/SConscript
Normal 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')
|
||||
249
simulators/gem5/util/batch/batch.py
Normal file
249
simulators/gem5/util/batch/batch.py
Normal 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
246
simulators/gem5/util/batch/job.py
Executable 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))
|
||||
306
simulators/gem5/util/batch/send.py
Executable file
306
simulators/gem5/util/batch/send.py
Executable 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
|
||||
197
simulators/gem5/util/ccdrv/devtime.c
Normal file
197
simulators/gem5/util/ccdrv/devtime.c
Normal 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
|
||||
18
simulators/gem5/util/ccdrv/readme.txt
Normal file
18
simulators/gem5/util/ccdrv/readme.txt
Normal 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.
|
||||
|
||||
|
||||
135
simulators/gem5/util/checkpoint-tester.py
Executable file
135
simulators/gem5/util/checkpoint-tester.py
Executable 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()
|
||||
|
||||
|
||||
182
simulators/gem5/util/checkpoint_aggregator.py
Executable file
182
simulators/gem5/util/checkpoint_aggregator.py
Executable 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)
|
||||
|
||||
38
simulators/gem5/util/checktrace.sh
Executable file
38
simulators/gem5/util/checktrace.sh
Executable 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
168
simulators/gem5/util/chkformat
Executable 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
323
simulators/gem5/util/compile
Executable 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()
|
||||
186
simulators/gem5/util/cpt_upgrader.py
Executable file
186
simulators/gem5/util/cpt_upgrader.py
Executable 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)
|
||||
|
||||
71
simulators/gem5/util/cscope-index.py
Executable file
71
simulators/gem5/util/cscope-index.py
Executable 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")
|
||||
41
simulators/gem5/util/emacs/m5-c-style.el
Normal file
41
simulators/gem5/util/emacs/m5-c-style.el
Normal 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)))))
|
||||
174
simulators/gem5/util/file_types.py
Normal file
174
simulators/gem5/util/file_types.py
Normal 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')
|
||||
273
simulators/gem5/util/find_copyrights.py
Normal file
273
simulators/gem5/util/find_copyrights.py
Normal 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
83
simulators/gem5/util/fixwhite
Executable 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
372
simulators/gem5/util/gem5img.py
Executable 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()
|
||||
34
simulators/gem5/util/hgfilesize.py
Normal file
34
simulators/gem5/util/hgfilesize.py
Normal 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.
|
||||
53
simulators/gem5/util/m5/Makefile.alpha
Normal file
53
simulators/gem5/util/m5/Makefile.alpha
Normal 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
|
||||
81
simulators/gem5/util/m5/Makefile.arm
Normal file
81
simulators/gem5/util/m5/Makefile.arm
Normal 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
|
||||
53
simulators/gem5/util/m5/Makefile.sparc
Normal file
53
simulators/gem5/util/m5/Makefile.sparc
Normal 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
|
||||
67
simulators/gem5/util/m5/Makefile.thumb
Normal file
67
simulators/gem5/util/m5/Makefile.thumb
Normal 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
|
||||
49
simulators/gem5/util/m5/Makefile.x86
Normal file
49
simulators/gem5/util/m5/Makefile.x86
Normal 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
|
||||
67
simulators/gem5/util/m5/jni/gem5Op.java
Normal file
67
simulators/gem5/util/m5/jni/gem5Op.java
Normal 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);
|
||||
|
||||
}
|
||||
172
simulators/gem5/util/m5/jni_gem5Op.c
Normal file
172
simulators/gem5/util/m5/jni_gem5Op.c
Normal 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);
|
||||
}
|
||||
|
||||
319
simulators/gem5/util/m5/m5.c
Normal file
319
simulators/gem5/util/m5/m5.c
Normal 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);
|
||||
}
|
||||
82
simulators/gem5/util/m5/m5op.h
Normal file
82
simulators/gem5/util/m5/m5op.h
Normal 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__
|
||||
133
simulators/gem5/util/m5/m5op_alpha.S
Normal file
133
simulators/gem5/util/m5/m5op_alpha.S
Normal 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)
|
||||
|
||||
161
simulators/gem5/util/m5/m5op_arm.S
Normal file
161
simulators/gem5/util/m5/m5op_arm.S
Normal 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)
|
||||
|
||||
153
simulators/gem5/util/m5/m5op_sparc.S
Normal file
153
simulators/gem5/util/m5/m5op_sparc.S
Normal 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)
|
||||
|
||||
|
||||
63
simulators/gem5/util/m5/m5op_x86.S
Normal file
63
simulators/gem5/util/m5/m5op_x86.S
Normal 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)
|
||||
82
simulators/gem5/util/m5/m5ops.h
Normal file
82
simulators/gem5/util/m5/m5ops.h
Normal 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
|
||||
|
||||
253
simulators/gem5/util/o3-pipeview.py
Executable file
253
simulators/gem5/util/o3-pipeview.py
Executable 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()
|
||||
95
simulators/gem5/util/oprofile-top.py
Executable file
95
simulators/gem5/util/oprofile-top.py
Executable 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
241
simulators/gem5/util/pbs/job.py
Executable 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
182
simulators/gem5/util/pbs/pbs.py
Executable 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
292
simulators/gem5/util/pbs/send.py
Executable 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
238
simulators/gem5/util/qdo
Executable 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
163
simulators/gem5/util/regress
Executable 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
321
simulators/gem5/util/rundiff
Executable 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
38
simulators/gem5/util/slicc
Executable 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()
|
||||
220
simulators/gem5/util/sort_includes.py
Normal file
220
simulators/gem5/util/sort_includes.py
Normal 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())
|
||||
39
simulators/gem5/util/statetrace/SConscript
Normal file
39
simulators/gem5/util/statetrace/SConscript
Normal 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)
|
||||
67
simulators/gem5/util/statetrace/SConstruct
Normal file
67
simulators/gem5/util/statetrace/SConstruct
Normal 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))
|
||||
405
simulators/gem5/util/statetrace/arch/amd64/tracechild.cc
Normal file
405
simulators/gem5/util/statetrace/arch/amd64/tracechild.cc
Normal 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, ®Val64, sizeof(regVal64)) == -1) {
|
||||
cerr << "Write failed! " << strerror(errno) << endl;
|
||||
tracing = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
regVal64 = getRegVal(RIP);
|
||||
if (write(socket, ®Val64, 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, ®Val32, 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, ®Val32, 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, ®s) != 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;
|
||||
}
|
||||
119
simulators/gem5/util/statetrace/arch/amd64/tracechild.hh
Normal file
119
simulators/gem5/util/statetrace/arch/amd64/tracechild.hh
Normal 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
|
||||
286
simulators/gem5/util/statetrace/arch/arm/tracechild.cc
Normal file
286
simulators/gem5/util/statetrace/arch/arm/tracechild.cc
Normal 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(®s, 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, ®s) != 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;
|
||||
}
|
||||
|
||||
123
simulators/gem5/util/statetrace/arch/arm/tracechild.hh
Normal file
123
simulators/gem5/util/statetrace/arch/arm/tracechild.hh
Normal 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
|
||||
|
||||
111
simulators/gem5/util/statetrace/arch/i686/tracechild.cc
Normal file
111
simulators/gem5/util/statetrace/arch/i686/tracechild.cc
Normal 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, ®s) != 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;
|
||||
}
|
||||
87
simulators/gem5/util/statetrace/arch/i686/tracechild.hh
Normal file
87
simulators/gem5/util/statetrace/arch/i686/tracechild.hh
Normal 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
|
||||
473
simulators/gem5/util/statetrace/arch/sparc/tracechild.cc
Normal file
473
simulators/gem5/util/statetrace/arch/sparc/tracechild.cc
Normal 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, ®Val, sizeof(regVal)) == -1) {
|
||||
cerr << "Write failed! " << strerror(errno) << endl;
|
||||
tracing = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
regVal = getRegVal(PC);
|
||||
if (write(socket, ®Val, sizeof(regVal)) == -1) {
|
||||
cerr << "Write failed! " << strerror(errno) << endl;
|
||||
tracing = false;
|
||||
return false;
|
||||
}
|
||||
regVal = getRegVal(NPC);
|
||||
if (write(socket, ®Val, sizeof(regVal)) == -1) {
|
||||
cerr << "Write failed! " << strerror(errno) << endl;
|
||||
tracing = false;
|
||||
return false;
|
||||
}
|
||||
regVal = getRegVal(CCR);
|
||||
if (write(socket, ®Val, 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;
|
||||
}
|
||||
|
||||
115
simulators/gem5/util/statetrace/arch/sparc/tracechild.hh
Normal file
115
simulators/gem5/util/statetrace/arch/sparc/tracechild.hh
Normal 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
|
||||
78
simulators/gem5/util/statetrace/base/arch_check.h
Normal file
78
simulators/gem5/util/statetrace/base/arch_check.h
Normal 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
|
||||
47
simulators/gem5/util/statetrace/base/regstate.hh
Normal file
47
simulators/gem5/util/statetrace/base/regstate.hh
Normal 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
|
||||
156
simulators/gem5/util/statetrace/base/statetrace.cc
Normal file
156
simulators/gem5/util/statetrace/base/statetrace.cc
Normal 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;
|
||||
}
|
||||
|
||||
149
simulators/gem5/util/statetrace/base/tracechild.cc
Normal file
149
simulators/gem5/util/statetrace/base/tracechild.cc
Normal 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;
|
||||
}
|
||||
62
simulators/gem5/util/statetrace/base/tracechild.hh
Normal file
62
simulators/gem5/util/statetrace/base/tracechild.hh
Normal 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
|
||||
28
simulators/gem5/util/stats/__init__.py
Normal file
28
simulators/gem5/util/stats/__init__.py
Normal 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
|
||||
|
||||
341
simulators/gem5/util/stats/barchart.py
Normal file
341
simulators/gem5/util/stats/barchart.py
Normal 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()
|
||||
1940
simulators/gem5/util/stats/categories.py
Normal file
1940
simulators/gem5/util/stats/categories.py
Normal file
File diff suppressed because it is too large
Load Diff
86
simulators/gem5/util/stats/chart.py
Normal file
86
simulators/gem5/util/stats/chart.py
Normal 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)
|
||||
|
||||
436
simulators/gem5/util/stats/db.py
Normal file
436
simulators/gem5/util/stats/db.py
Normal 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]
|
||||
385
simulators/gem5/util/stats/dbinit.py
Normal file
385
simulators/gem5/util/stats/dbinit.py
Normal 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''')
|
||||
151
simulators/gem5/util/stats/display.py
Normal file
151
simulators/gem5/util/stats/display.py
Normal 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()
|
||||
36
simulators/gem5/util/stats/flags.py
Normal file
36
simulators/gem5/util/stats/flags.py
Normal 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
|
||||
768
simulators/gem5/util/stats/info.py
Normal file
768
simulators/gem5/util/stats/info.py
Normal 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
|
||||
|
||||
213
simulators/gem5/util/stats/output.py
Normal file
213
simulators/gem5/util/stats/output.py
Normal 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()
|
||||
155
simulators/gem5/util/stats/print.py
Normal file
155
simulators/gem5/util/stats/print.py
Normal 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()
|
||||
|
||||
504
simulators/gem5/util/stats/profile.py
Normal file
504
simulators/gem5/util/stats/profile.py
Normal 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)
|
||||
486
simulators/gem5/util/stats/stats.py
Executable file
486
simulators/gem5/util/stats/stats.py
Executable 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()
|
||||
551
simulators/gem5/util/style.py
Normal file
551
simulators/gem5/util/style.py
Normal 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)
|
||||
538
simulators/gem5/util/tap/tap.cc
Normal file
538
simulators/gem5/util/tap/tap.cc
Normal 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;
|
||||
}
|
||||
321
simulators/gem5/util/term/term.c
Normal file
321
simulators/gem5/util/term/term.c
Normal 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
153
simulators/gem5/util/tracediff
Executable 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);
|
||||
|
||||
|
||||
|
||||
113
simulators/gem5/util/valgrind-suppressions
Normal file
113
simulators/gem5/util/valgrind-suppressions
Normal 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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user