1
0

Trace generator: updates and additions to the scripts directory.

(1) Introduce tracegen.py, a script that invokes the emulator (built
    with TraceGenConfig), sending a SIGTERM once all cores are finished.

(2) Update toaxe.py to gather some statistics about the trace.

(3) Introduce tracestats.py, which displays the stats in a useful way.

(4) Introduce tracegen+check.py, a top-level script that generates
    traces, checks them, and emits stats.  If this commit is pulled, it
    should be done after pulling my latest groundtest commit.
This commit is contained in:
Matthew Naylor 2016-03-18 12:24:12 +00:00 committed by Howard Mao
parent c989ec5813
commit 6da45e7f26
5 changed files with 454 additions and 133 deletions

@ -1 +1 @@
Subproject commit 82a6f060db93d71ff6d2d44bde9ff8e4e1bf4bef Subproject commit e711f7988fe5be7881406eb310501cc0a7efb098

View File

@ -27,44 +27,57 @@
import sys import sys
import re import re
import sets
if len(sys.argv) != 2: def main():
print "Usage: toaxe.py [FILE]"
sys.exit()
if sys.argv[1] == "-": if len(sys.argv) < 2:
sys.stderr.write("Usage: toaxe.py TRACE-FILE [STATS-OUT-FILE]\n")
sys.exit(-1)
if sys.argv[1] == "-":
f = sys.stdin f = sys.stdin
else: else:
f = open(sys.argv[1], 'r') f = open(sys.argv[1], 'r')
if f == None: if f == None:
print "File not found: ", sys.argv[1] sys.stderr.write("File not found: " + sys.argv[1] + "\n")
sys.exit() sys.exit(-1)
lineCount = 0 statsFile = None
def error(msg): if len(sys.argv) > 2:
print "Error at line ", lineCount, ": ", msg statsFile = open(sys.argv[2], 'a')
sys.exit()
# Mapping from address to axe address lineCount = 0
addrMap = {} def error(msg):
nextAddr = 0 sys.stderr.write("Error at line " + str(lineCount) + ": " + msg + "\n")
sys.exit(-1)
# Mapping from (thread id, tag id) to axe operation id # Mapping from address to axe address
tagMap = {} addrMap = {}
nextAddr = 0
# Mapping from thread id to operation id # Mapping from (thread id, tag id) to axe operation id
fenceReq = {} tagMap = {}
# Mapping from thread id to operation id # Mapping from thread id to operation id
loadReserve = {} fenceReq = {}
# Array of axe operations # Mapping from thread id to operation id
ops = [] loadReserve = {}
for line in f: # Array of axe operations
# Exit loop at end of trace ops = []
if line[0:9] == 'Completed': break
# Statistics
scCount = 0 # Number of store-conditionals
scSuccessCount = 0 # Number of store-conditionals that succeeded
loadCount = 0 # Number of loads
loadExtCount = 0 # Number of loads of value written by another core
# The previous write to each address by each thread
prevWrite = {}
for line in f:
# Parse thread id and command # Parse thread id and command
m = re.search(' *([0-9]+) *: *([^ ]*) (.*)', line) m = re.search(' *([0-9]+) *: *([^ ]*) (.*)', line)
if m == None: error("Expected: <thread-id> ':' <command>") if m == None: error("Expected: <thread-id> ':' <command>")
@ -114,6 +127,7 @@ for line in f:
ops.append((cmd, m.group(1), addrMap[m.group(2)], m.group(4), lr)) ops.append((cmd, m.group(1), addrMap[m.group(2)], m.group(4), lr))
tagMap[(tid, m.group(3))] = len(ops)-1 tagMap[(tid, m.group(3))] = len(ops)-1
if cmd == 'store-cond-req': loadReserve[tid] = None if cmd == 'store-cond-req': loadReserve[tid] = None
prevWrite[(tid, addrMap[m.group(2)])] = m.group(1)
elif cmd == 'resp': elif cmd == 'resp':
# Parse value and timestamp # Parse value and timestamp
m = re.search(' *([0-9]+) *# *([0-9]+) *@ *([0-9]+)', line) m = re.search(' *([0-9]+) *# *([0-9]+) *@ *([0-9]+)', line)
@ -121,9 +135,14 @@ for line in f:
# Find corresponding response # Find corresponding response
tag = m.group(2) tag = m.group(2)
if not ((tid, tag) in tagMap) or tagMap[(tid, tag)] == None: if not ((tid, tag) in tagMap) or tagMap[(tid, tag)] == None:
error("resp without associated req with tag " + tag + " on thread " + tid) error("resp without associated req with tag " + tag +
" on thread " + tid)
opId = tagMap[(tid, tag)] opId = tagMap[(tid, tag)]
(c, val, addr, start, lr) = ops[opId] (c, val, addr, start, lr) = ops[opId]
if c == 'load-req' or c == 'load-reserve-req':
loadCount = loadCount+1
if prevWrite.get((tid, addr), None) != m.group(1):
loadExtCount = loadExtCount+1
if c == 'load-req': if c == 'load-req':
op = tid + ": M[" + str(addr) + '] == ' + m.group(1) + ' @ ' op = tid + ": M[" + str(addr) + '] == ' + m.group(1) + ' @ '
op += start + ':' + m.group(3) op += start + ':' + m.group(3)
@ -137,15 +156,17 @@ for line in f:
elif c == 'store-cond-req': elif c == 'store-cond-req':
if lr == None: error("store conditional without load-reserve") if lr == None: error("store conditional without load-reserve")
(loadVal, loadStart, loadFin) = ops[lr] (loadVal, loadStart, loadFin) = ops[lr]
scCount = scCount + 1
if int(m.group(1)) != 0: if int(m.group(1)) != 0:
# SC fail # SC fail
op = tid + ": M[" + str(addr) + "] == " + loadVal op = tid + ": M[" + str(addr) + "] == " + loadVal
op += " @ " + loadStart + ":" + loadFin op += " @ " + loadStart + ":" + loadFin
else: else:
# SC success # SC success
scSuccessCount = scSuccessCount + 1
op = tid + ": { M[" + str(addr) + "] == " + loadVal + "; " op = tid + ": { M[" + str(addr) + "] == " + loadVal + "; "
op += "M[" + str(addr) + "] := " + val + "} @ " op += "M[" + str(addr) + "] := " + val + "} @ "
op += loadStart + ":" # + m.group(3) op += loadStart + ":" + loadFin
ops[lr] = (op,) ops[lr] = (op,)
ops[opId] = None ops[opId] = None
elif c == 'swap-req': elif c == 'swap-req':
@ -158,11 +179,25 @@ for line in f:
lineCount = lineCount+1 lineCount = lineCount+1
# Print address map in comments # Print statistics
for addr in addrMap: scSuccessRate = str(scSuccessCount/float(scCount))[0:6]
loadExtRate = str(loadExtCount/float(loadCount))[0:6]
print("# LRSC_Success_Rate=" + scSuccessRate)
if statsFile != None:
statsFile.write("LRSC_Success_Rate=" + scSuccessRate + "\n")
statsFile.write("Load_External_Rate=" + loadExtRate + "\n")
statsFile.close()
# Print address map in comments
for addr in addrMap:
print ("# &M[" + str(addrMap[addr]) + "] == " + addr) print ("# &M[" + str(addrMap[addr]) + "] == " + addr)
# Print axe trace # Print axe trace
for op in ops: for op in ops:
if op != None and isinstance(op, tuple) and len(op) == 1: if op != None and isinstance(op, tuple) and len(op) == 1:
print op[0] print op[0]
try:
main()
except KeyboardInterrupt:
sys.exit(-1)

148
scripts/tracegen+check.sh Executable file
View File

@ -0,0 +1,148 @@
#!/bin/bash
# This file was originally written by Matthew Naylor, University of
# Cambridge.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
# ("CTSRD"), as part of the DARPA CRASH research programme.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
# ("MRC2"), as part of the DARPA MRC research programme.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory as part of the Rigorous Engineering of
# Mainstream Systems (REMS) project, funded by EPSRC grant
# EP/K008528/1.
# This script can be used to test the memory consistency of rocket
# chip in simulation when compiled with the 'TraceGenConfig'
# configuation.
###############################################################################
# Parameters
# ==========
# Arguments are taken from environment variables where available.
# Elsewhere, defaults values are chosen.
START_SEED=${START_SEED-0}
NUM_TESTS=${NUM_TESTS-100}
EMU=${EMU-emulator-Top-TraceGenConfig}
TRACE_GEN=${TRACE_GEN-tracegen.py}
TO_AXE=${TO_AXE-toaxe.py}
AXE=${AXE-axe}
MODEL=${MODEL-WMO}
LOG_DIR=${LOG_DIR-tracegen-log}
TRACE_STATS=${TRACE_STATS-tracestats.py}
###############################################################################
# Inferred parameters
# ===================
END_SEED=`expr \( $START_SEED + $NUM_TESTS \) - 1`
LOG=$LOG_DIR
PATH=$PATH:.
# Sanity check
# ============
if [ ! `command -v $EMU` ]; then
echo Can\'t find emulator: \'$EMU\'
exit -1
fi
if [ ! `command -v $TO_AXE` ]; then
echo Please add \'toaxe.py\' to your PATH
exit -1
fi
if [ ! `command -v $TRACE_GEN` ]; then
echo Please add \'tracegen.py\' to your PATH
exit -1
fi
if [ ! `command -v $AXE` ]; then
echo Please add \'axe\' to your PATH
exit -1
fi
if [ ! `command -v $TRACE_STATS` ]; then
echo Please add \'tracestats.py\' to your PATH
exit -1
fi
if [ "$MODEL" != SC -a \
"$MODEL" != TSO -a \
"$MODEL" != PSO -a \
"$MODEL" != WMO -a \
"$MODEL" != POW ]; then
echo Unknown consistency model \'$MODEL\'
exit -1
fi
# Setup log directory
# ===================
if [ ! -d $LOG ]; then
echo Creating log directory: $LOG
mkdir $LOG
fi
rm -f $LOG/errors.txt
rm -f $LOG/stats.txt
# Test loop
# =========
echo Testing against $MODEL model:
for (( I = $START_SEED; I <= $END_SEED; I++ )); do
SPACE=`expr $I \% 10`
if [ $SPACE -eq 0 ]; then
echo -n " "
fi
NEWLINE=`expr $I \% 50`
if [ $NEWLINE -eq 0 ]; then
printf "\n%8i: " $I
fi
# Generate trace
$TRACE_GEN $EMU $I > $LOG/trace.txt
if [ ! $? -eq 0 ]; then
echo -e "\n\nError: emulator returned non-zero exit code"
echo See $LOG/trace.txt for details
exit -1
fi
# Convert to axe format
$TO_AXE $LOG/trace.txt $LOG/stats.txt 2>> $LOG/errors.txt > $LOG/trace.axe
if [ ! $? -eq 0 ]; then
echo -e "\n\nError during trace generation with seed $I"
echo "See $LOG/errors.txt"
exit -1
else
# Check trace
OUTCOME=`$AXE check $MODEL $LOG/trace.axe 2>> $LOG/errors.txt`
if [ "$OUTCOME" == "OK" ]; then
echo -n .
else
if [ "$OUTCOME" == "NO" ]; then
echo -e "\n\nFailed $MODEL with seed $I"
echo "See $LOG/trace.txt and $LOG/trace.axe for counterexample"
exit -1
else
echo -e "\n\nError during trace generation with seed $I"
echo "See $LOG/errors.txt for details"
exit -1
fi
fi
fi
done
echo -e "\n\nOK, passed $NUM_TESTS tests"
$TRACE_STATS $LOG/stats.txt

62
scripts/tracegen.py Executable file
View File

@ -0,0 +1,62 @@
#!/usr/bin/env python
# This file was originally written by Matthew Naylor, University of
# Cambridge.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
# ("CTSRD"), as part of the DARPA CRASH research programme.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
# ("MRC2"), as part of the DARPA MRC research programme.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory as part of the Rigorous Engineering of
# Mainstream Systems (REMS) project, funded by EPSRC grant
# EP/K008528/1.
# -------
# Outline
# -------
# Usage:
#
# tracegen.py EMULATOR SEED
#
# This script generates a trace using the given emulator (built
# with CONFIG=TraceGenConfig). It waits until all cores have
# completed trace generation before terminating the emulator.
import sys
import subprocess
import re
def main():
if len(sys.argv) != 3:
sys.stderr.write("Usage: tracegen.py EMULATOR SEED\n")
sys.exit(-1)
p = subprocess.Popen([sys.argv[1], "+verbose", "-s" + sys.argv[2]],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
if p == None:
sys.stderr.write("File not found: " + sys.argv[1] + "\n")
sys.exit(-1)
numFinished = 0
while True:
line = p.stderr.readline()
if line[0:9] == "FINISHED ":
total = int(line[9:-1])
numFinished = numFinished + 1
if numFinished == total:
break
else:
print line,
p.terminate()
try:
main()
except KeyboardInterrupt:
sys.exit(-1)

76
scripts/tracestats.py Executable file
View File

@ -0,0 +1,76 @@
#!/usr/bin/env python
# This file was originally written by Matthew Naylor, University of
# Cambridge.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
# ("CTSRD"), as part of the DARPA CRASH research programme.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
# ("MRC2"), as part of the DARPA MRC research programme.
#
# This software was partly developed by the University of Cambridge
# Computer Laboratory as part of the Rigorous Engineering of
# Mainstream Systems (REMS) project, funded by EPSRC grant
# EP/K008528/1.
# -------
# Outline
# -------
# Usage:
#
# tracegen-stats.py STATS-FILE
#
# This script produces some statistics about the traces generated
# using tracegen.py.
import sys
import subprocess
import re
def main():
if len(sys.argv) != 2:
sys.stderr.write("Usage: tracegen-stats.py STATS-FILE\n")
sys.exit(-1)
f = open(sys.argv[1], 'r')
if f == None:
sys.stderr.write("File not found: " + sys.argv[1] + "\n")
sys.exit(-1)
lrscSuccessSum = 0.0
lrscSuccessCount = 0
loadExtRateSum = 0.0
loadExtRateCount = 0
for line in f:
if line[0:18] == "LRSC_Success_Rate=":
val = float(line[18:-1])
lrscSuccessSum = lrscSuccessSum + val
lrscSuccessCount = lrscSuccessCount + 1
if line[0:19] == "Load_External_Rate=":
val = float(line[19:-1])
loadExtRateSum = loadExtRateSum + val
loadExtRateCount = loadExtRateCount + 1
if lrscSuccessCount > 0:
lrscSuccessAvg = lrscSuccessSum / float(lrscSuccessCount)
lrscSuccessRate = str(int(100.0*lrscSuccessAvg)) + "%"
print "LR/SC success rate:", lrscSuccessRate
else:
print "LR/SC success rate: none performed"
if loadExtRateCount > 0:
loadExtRateAvg = loadExtRateSum / float(loadExtRateCount)
loadExtRate = str(int(100.0*loadExtRateAvg)) + "%"
print "Load-external rate:", loadExtRate
else:
print "Load-external rate: none performed"
try:
main()
except KeyboardInterrupt:
sys.exit(-1)