From 52baab2d762011ce52164ccc3619bbf8fec60795 Mon Sep 17 00:00:00 2001 From: Michael Lenz Date: Mon, 8 Feb 2016 15:44:34 +0100 Subject: [PATCH] faultspaceplot as analysis tool This change adds the faultspace-plotting scripts into FAIL*'s tools/analysis/ folder and makes it CMake-configurable. Change-Id: I9364a448a33853520629291721a6ed6d4e82eb32 --- doc/how-to-build.txt | 1 + tools/CMakeLists.txt | 6 + tools/analysis/faultspaceplot/CMakeLists.txt | 1 + .../analysis/faultspaceplot/faultspaceplot.sh | 51 ++++++++ .../faultspaceplot/fsp.compact-horizontal.sh | 52 +++++++++ .../faultspaceplot/fsp.compact-vertical.sh | 63 ++++++++++ tools/analysis/faultspaceplot/fsp.compact.sh | 43 +++++++ tools/analysis/faultspaceplot/fsp.plot.py | 110 ++++++++++++++++++ 8 files changed, 327 insertions(+) create mode 100644 tools/analysis/faultspaceplot/CMakeLists.txt create mode 100755 tools/analysis/faultspaceplot/faultspaceplot.sh create mode 100755 tools/analysis/faultspaceplot/fsp.compact-horizontal.sh create mode 100755 tools/analysis/faultspaceplot/fsp.compact-vertical.sh create mode 100755 tools/analysis/faultspaceplot/fsp.compact.sh create mode 100755 tools/analysis/faultspaceplot/fsp.plot.py diff --git a/doc/how-to-build.txt b/doc/how-to-build.txt index 10553c35..b8e0acd5 100644 --- a/doc/how-to-build.txt +++ b/doc/how-to-build.txt @@ -33,6 +33,7 @@ Required for Fail*: * a MySQL 5.0+ or MariaDB 5.1+ (MariaDB 5.5 recommended) server * doxygen * cmake-curses-gui + * python-numpy and python-matplotlib for the faultspaceplot tool diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 269dc4b9..3f0b2f58 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -6,6 +6,8 @@ option(BUILD_CONVERT_TRACE "Build the trace converter tool?" OFF) option(BUILD_COMPUTE_HOPS "Build the compute hops tool?" OFF) option(BUILD_DUMP_HOPS "Build the hops dump tool?" OFF) +option(BUILD_FAULTSPACEPLOT "Build the faultspace plotting tool?" OFF) + ### Setup search paths for headers ## include_directories(${CMAKE_CURRENT_BINARY_DIR}/../src/core) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/core) @@ -33,3 +35,7 @@ endif(BUILD_COMPUTE_HOPS) if(BUILD_DUMP_HOPS) add_subdirectory(dump-hops) endif(BUILD_DUMP_HOPS) + +if(BUILD_FAULTSPACEPLOT) + add_subdirectory(analysis/faultspaceplot) +endif(BUILD_FAULTSPACEPLOT) diff --git a/tools/analysis/faultspaceplot/CMakeLists.txt b/tools/analysis/faultspaceplot/CMakeLists.txt new file mode 100644 index 00000000..d3c83219 --- /dev/null +++ b/tools/analysis/faultspaceplot/CMakeLists.txt @@ -0,0 +1 @@ +install(PROGRAMS faultspaceplot.sh fsp.compact-horizontal.sh fsp.compact.sh fsp.compact-vertical.sh fsp.plot.py DESTINATION bin) diff --git a/tools/analysis/faultspaceplot/faultspaceplot.sh b/tools/analysis/faultspaceplot/faultspaceplot.sh new file mode 100755 index 00000000..168ea168 --- /dev/null +++ b/tools/analysis/faultspaceplot/faultspaceplot.sh @@ -0,0 +1,51 @@ +#!/bin/bash +set -e + +if [ ! $# -eq 3 ]; then + echo "usage: $0 DATABASE VARIANT BENCHMARK" >&2 + exit 1 +fi + +DATABASE=$1 +VARIANT=$2 +BENCHMARK=$3 +# add "-t" for more readable output +MYSQL="mysql -B --quick $DATABASE" + +# get data +echo "getting faultspace data.." +$MYSQL < "$VARIANT"_"$BENCHMARK"-raw.csv + SELECT t.time1 - (SELECT MIN(t2.time1) FROM trace t2 WHERE t.variant_id = t2.variant_id) AS time1, + t.time2 - (SELECT MIN(t2.time1) FROM trace t2 WHERE t.variant_id = t2.variant_id) AS time2, + t.data_address, r.bitoffset, 1, + CASE + WHEN r.resulttype = 'OK_MARKER' THEN '#FFFFFF' + WHEN r.resulttype = 'FAIL_MARKER' THEN '#EE0000' + WHEN r.resulttype = 'DETECTED_MARKER' THEN '#00FF00' + WHEN r.resulttype = 'GROUP0_MARKER' THEN '#EAEAEA' + WHEN r.resulttype = 'GROUP1_MARKER' THEN '#EBEBEB' + WHEN r.resulttype = 'GROUP2_MARKER' THEN '#ECECEC' + WHEN r.resulttype = 'GROUP3_MARKER' THEN '#EDEDED' + WHEN r.resulttype = 'TIMEOUT' THEN '#00EE00' + WHEN r.resulttype = 'TRAP' THEN '#00DD00' + WHEN r.resulttype = 'WRITE_TEXTSEGMENT' THEN '#0000AA' + WHEN r.resulttype = 'WRITE_OUTERSPACE' THEN '#0000BB' + WHEN r.resulttype = 'SDC' THEN '#FF0000' + WHEN r.resulttype = 'UNKNOWN' THEN '#000000' + END AS color + FROM trace t + JOIN fspgroup g ON t.variant_id = g.variant_id AND t.data_address = g.data_address AND t.instr2 = g.instr2 + JOIN variant v ON v.id = t.variant_id + JOIN result_GenericExperimentMessage r ON r.pilot_id=g.pilot_id + WHERE + v.variant = '$VARIANT' AND v.benchmark = '$BENCHMARK' + AND t.accesstype = 'R'; +EOT + +# compact data +echo "compacting data.." +fsp.compact.sh "$VARIANT"_"$BENCHMARK"-raw.csv "$VARIANT"_"$BENCHMARK"-plot.csv + +# plot data +echo "plotting.." +fsp.plot.py "$VARIANT"_"$BENCHMARK"-plot.csv diff --git a/tools/analysis/faultspaceplot/fsp.compact-horizontal.sh b/tools/analysis/faultspaceplot/fsp.compact-horizontal.sh new file mode 100755 index 00000000..82710868 --- /dev/null +++ b/tools/analysis/faultspaceplot/fsp.compact-horizontal.sh @@ -0,0 +1,52 @@ +#!/bin/bash +set -e + +TMP=$(mktemp) + +read HEADER +echo "$HEADER" + +BASE='' +LAST='' +sort -snk 1 | sort -snk 4 | sort -snk 3 > $TMP + +while read CUR +do + a=($CUR) + C_I1=${a[0]} + C_I2=${a[1]} + C_ADDR=${a[2]} + C_BIT=${a[3]} + C_BW=${a[4]} + C_COL=${a[5]} + + if [ -z "$BASE" ] + then + BASE=$CUR + LAST=$CUR + elif (($C_I1 != $L_I2 + 1 || $L_ADDR != $C_ADDR || $L_BIT != $C_BIT || $L_BW != $C_BW)) || \ + [ "$C_COL" != "$L_COL" ] + then + a=($BASE) + B_I1=${a[0]} + + echo -e "$B_I1\t$L_I2\t$L_ADDR\t$L_BIT\t$L_BW\t$L_COL" + + BASE=$CUR + fi + + LAST="$CUR" + L_I1=$C_I1 + L_I2=$C_I2 + L_ADDR=$C_ADDR + L_BIT=$C_BIT + L_BW=$C_BW + L_COL=$C_COL +done < $TMP + +a=($BASE) +B_I1=${a[0]} + +echo -e "$B_I1\t$L_I2\t$L_ADDR\t$L_BIT\t$L_BW\t$L_COL" + +rm $TMP diff --git a/tools/analysis/faultspaceplot/fsp.compact-vertical.sh b/tools/analysis/faultspaceplot/fsp.compact-vertical.sh new file mode 100755 index 00000000..f819a643 --- /dev/null +++ b/tools/analysis/faultspaceplot/fsp.compact-vertical.sh @@ -0,0 +1,63 @@ +#!/bin/bash +set -e + +TMP=$(mktemp) + +read HEADER +echo "$HEADER" + +BASE='' +LAST='' +sort -snk 4 | sort -snk 3 | sort -snk 1 > $TMP + +while read CUR +do + a=($CUR) + C_I1=${a[0]} + C_I2=${a[1]} + C_ADDR=${a[2]} + C_BIT=${a[3]} + C_BW=${a[4]} + C_COL=${a[5]} + C_N=$(($C_ADDR*8 + $C_BIT)) + + if [ -z "$BASE" ] + then + BASE=$CUR + LAST=$CUR + elif (($C_I1 != $L_I1 || $C_I2 != $L_I2 || \ + $L_N + $L_BW != $C_N)) || \ + [ "$C_COL" != "$L_COL" ] + then + a=($BASE) + B_ADDR=${a[2]} + B_BIT=${a[3]} + B_N=$(($B_ADDR*8 + $B_BIT)) + + BW=$(($L_N + $L_BW - $B_N)) + + echo -e "$L_I1\t$L_I2\t$B_ADDR\t$B_BIT\t$BW\t$L_COL" + + BASE=$CUR + fi + + LAST="$CUR" + L_I1=$C_I1 + L_I2=$C_I2 + L_ADDR=$C_ADDR + L_BIT=$C_BIT + L_BW=$C_BW + L_COL=$C_COL + L_N=$C_N +done < $TMP + +a=($BASE) +B_ADDR=${a[2]} +B_BIT=${a[3]} +B_N=$(($B_ADDR*8 + $B_BIT)) + +BW=$(($L_N + $L_BW - $B_N)) + +echo -e "$L_I1\t$L_I2\t$B_ADDR\t$B_BIT\t$BW\t$L_COL" + +rm $TMP diff --git a/tools/analysis/faultspaceplot/fsp.compact.sh b/tools/analysis/faultspaceplot/fsp.compact.sh new file mode 100755 index 00000000..bd291339 --- /dev/null +++ b/tools/analysis/faultspaceplot/fsp.compact.sh @@ -0,0 +1,43 @@ +#!/bin/bash +set -e + +FIRST=vertical + +[ $# -lt 2 -o $# -gt 3 ] && echo "usage: $0 input.csv output.csv [vertical|horizontal]" >&2 && exit 1 + +if [ -z $3 ]; then + FIRST=vertical +else + FIRST=$3 +fi + +TMP1=$(mktemp) +TMP2=$(mktemp) + +cp $1 $TMP1 +COUNT=$(wc -l <$TMP1) + +NEXT=$FIRST + +while true +do + echo "at $COUNT, $NEXT ..." + fsp.compact-$NEXT.sh < $TMP1 > $TMP2 + + PREVCOUNT=$COUNT + COUNT=$(wc -l <$TMP2) + + if (($COUNT >= $PREVCOUNT)) + then + echo "no improvement (now $COUNT), stop." + cp $TMP1 $2 + break + fi + + mv $TMP2 $TMP1 + if [ $NEXT = vertical ]; then + NEXT=horizontal + else + NEXT=vertical + fi +done diff --git a/tools/analysis/faultspaceplot/fsp.plot.py b/tools/analysis/faultspaceplot/fsp.plot.py new file mode 100755 index 00000000..510b1eed --- /dev/null +++ b/tools/analysis/faultspaceplot/fsp.plot.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +# ------------------------------------------------------------------------- +# Import modules +import csv, sys +import matplotlib.pyplot as plt +import numpy as np +import matplotlib.patches as mpatches +import matplotlib.pylab as pylab + +ENTRY_COUNT_PER_LINE = 6 +RESULT_RECT_HEIGHT = 1.0/8 + +# ------------------------------------------------------------------------- +# Basic drawing class +class Rectangle: + def __init__(self, x, y, w, h, color): + # w + self.xpos = x # |-------------------| + self.ypos = y # | | h + self.width = w # | | + self.height = h # (x,y)---------------| + self.color = color # fill color + self.alpha = None # transparency level [0,1] + def draw(self): + """ Draw the rectangle. """ + if self.color == (1,1,1): + return + tmp = self.xpos, self.ypos, + p = mpatches.Rectangle(tmp, self.width, self.height, color=self.color, \ + alpha=self.alpha) + plt.gca().add_patch(p) + +# ------------------------------------------------------------------------- +# Check provided arguments: +if len(sys.argv) <= 1: + print "ERROR: Not enough arguments provided! See -h for more infos." + exit(1) +if sys.argv[1] == '-h': + print "Displays experiment results for the weather-monitor-experiment." + print " CALL-SYNTAX: fsp.plot.py DATA_FILE [USER_TAG_FILE]" + print "DATA_FILE is a CSV-file, storing the tab-separated values" + print "retrieved by the experiment run. USER_TAG_FILE is an optional" + print "CSV-file which can be used to add user-specific marks to the" + print "plot (not implemented yet)." # TODO: be more precise here + exit(0) + +print "WARNING: This script needs a newer version of Matplotlib for axis label rotation; run this on Ubuntu 12.10 or alike." + +print "Opening and processing \"" + sys.argv[1] + "\"..." +file = open(sys.argv[1], "r") +dialect = csv.Sniffer().sniff(file.read(1024)) +file.seek(0) +reader = csv.reader(file, dialect) +reader.next() # Move down a line to skip the header + +fig = plt.figure() + +xmin = 99999999 +xmax = 0 +ymin = 99999999 +ymax = 0 + +line_counter = 1 +for row in reader: + line_counter += 1 + # Check if there are at least ENTRY_COUNT_PER_LINE entries per line: + if len(row) != ENTRY_COUNT_PER_LINE: + print "ERROR: Line " + str(line_counter) + " is invalid (" +\ + str(ENTRY_COUNT_PER_LINE) + " entries expected)" + sys.exit(1) + + # Some constants to access the row-entries much easier: + IDX_INSTR1 = 0; IDX_INSTR2 = 1; IDX_DATA_ADDRESS = 2; + IDX_BITNR = 3; IDX_BITWIDTH = 4; IDX_COLOR = 5; + + # Update xmin/xmax/ymin/ymax + x1 = int(row[IDX_INSTR1]) + x2 = int(row[IDX_INSTR2]) + 1 # inclusive + width = x2 - x1 + if xmin > x1: + xmin = x1 + if xmax < x2: + xmax = x2 + + y1 = float(row[IDX_DATA_ADDRESS]) + float(row[IDX_BITNR]) / 8.0 + height = float(row[IDX_BITWIDTH]) / 8.0 + y2 = y1 + height + + if ymin > y1: + ymin = y1 + if ymax < y2: + ymax = y2 + + Rectangle(x1, y1, width, height, row[IDX_COLOR]).draw() + if line_counter == 50000: # debug stuff + pass + #break + +ymin = int(ymin / 1000) * 1000 + +file.close() +plt.xlim(xmin, xmax) +plt.ylim(ymin, ymax) + +plt.ylabel('Data Memory (RAM)') +plt.xlabel('Time (Cycles)') + +plt.show() +#pylab.savefig('baseline.pdf', bbox_inches='tight')