From 4235722244de5b47f78898a7e49bc8324ea323bf Mon Sep 17 00:00:00 2001 From: Joshua Bakita Date: Sat, 13 Mar 2021 18:13:18 -0500 Subject: Benchmarks and Analysis Scripts: Fix everything for 2D cache sensitivity exp. - Adds plot_cache_sensitivity_at_4mb.py to plot the results - Fixes run_bench.sh to work in mode `dis` - Fixes postproc.sh to use updated paths --- dis/inputs/4mb_WSS | 1 + dis/plot_cache_sensitivity_at_4mb.py | 61 ++++++++++++++++++++++++++++++++++++ dis/postproc.sh | 2 +- run_bench.sh | 10 +++--- 4 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 dis/inputs/4mb_WSS create mode 100755 dis/plot_cache_sensitivity_at_4mb.py diff --git a/dis/inputs/4mb_WSS b/dis/inputs/4mb_WSS new file mode 100644 index 0000000..3f7803d --- /dev/null +++ b/dis/inputs/4mb_WSS @@ -0,0 +1 @@ +4194304 diff --git a/dis/plot_cache_sensitivity_at_4mb.py b/dis/plot_cache_sensitivity_at_4mb.py new file mode 100755 index 0000000..56484c8 --- /dev/null +++ b/dis/plot_cache_sensitivity_at_4mb.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +import matplotlib.pyplot as plt +import numpy as np +import sys + +if len(sys.argv) < 2: + print("Usage:", sys.argv[0], "") + exit() + +# Index to name lookup table +id_name_map = ("field", "matrix", "neighborhood", "pointer", "update", "transitive") +# Name to index lookup hash table +name_id_map = {id_name_map[idx]: idx for idx in range(len(id_name_map))} + +# Extracts one benchmark's result from a file with multiple +def multibench_file(filename): + data = np.loadtxt(filename, usecols=(1,2,4,0), converters={0: lambda n: name_id_map[n.decode("utf_8")]}) + names = np.unique(data[:,3]) + for name in names: + yield (data[data[:,3] == name][:,:-1], id_name_map[int(name)]) + +# Subsamples one benchmark at a specific WSS +def plot_exec_vs_cache_data(data, ax, wss, **kwargs): + wsss = np.unique(data[:,0]) + # Get exec time for this working set size with all ways allocated + divisor = data[np.logical_and(data[:,0] == wss, data[:,1] == 16.0)][0,2] + # Normalize relative to that exec time + one_wss_data = data[data[:,0] == wss] / [1,1,divisor] + # Plot max exec time vs cache allocation + return ax.plot(np.flip(one_wss_data[:,1],0), np.flip(one_wss_data[:,2],0), **kwargs) + +# Wrapper function for backwards compatibility +def plot_exec_vs_cache(filename, ax, wss, line='-'): + data = np.loadtxt(filename, usecols=(1,2,4)) + plot_exec_vs_cache_data(data, ax, wss, linestyle=line, label=filename.split("-")[-4]) + +# Styles and colors which match those used in the paper +name_to_label = {"matrix":"-", "transitive":"-.", "neighborhood":"--", "pointer":":", "update":"-", "field":"-."} +name_to_color = {"matrix":"C0", "transitive":"C1", "neighborhood":"C2", "pointer":"C3", "update":"C4", "field":"C5"} +plt.rcParams["font.family"] = "serif" +plt.rcParams['figure.figsize'] = [6, 4] +legend_labels = [] +wss = 4 * 2**20 + +fig, ax = plt.subplots() +ax.set_xlabel("Cache Half Ways Allocated") +ax.set_ylabel("Worst-Case Execution Time Multiplier") +for (data, name) in multibench_file(sys.argv[1]): + line, = plot_exec_vs_cache_data(data, ax, wss, linestyle=name_to_label[name], label=name, color=name_to_color[name]) + # Save the max plotted value and legend info + legend_labels.append((max(line.get_ydata()), line, name)) + +# Sort the legend by the max plotted value +legend_labels.sort(key=lambda k: k[0], reverse=True) +ax.legend([x[1] for x in legend_labels], [x[2] for x in legend_labels]) + +# Plot from most to least ways allocated +ax.set_xlim(ax.get_xlim()[::-1]) + +fig.savefig("exec_vs_cache_4mb_ae.pdf") +print("Plot saved as exec_vs_cache_4mb_ae.pdf") diff --git a/dis/postproc.sh b/dis/postproc.sh index efe6774..0147595 100755 --- a/dis/postproc.sh +++ b/dis/postproc.sh @@ -14,5 +14,5 @@ if [[ ! -f $1.txt ]]; then echo "Input does not exist. Exiting..." exit fi -./summarize.py $1.txt --inf-precision > $1-pp.txt +../summarize.py $1.txt --inf-precision > $1-pp.txt ./clean.sh $1-pp.txt diff --git a/run_bench.sh b/run_bench.sh index 6e4abb5..39e9dcb 100755 --- a/run_bench.sh +++ b/run_bench.sh @@ -27,8 +27,8 @@ if [ $# -lt 5 ]; then echo " L3-only (i3), or color-based L2+L3 (i)" echo "Mode base requires no additional options." echo "Mode dis does not support the 2nd col. of -b and needs:" - echo " -W FILE List of working set sizes to pass gen_input.py" - echo " -T FILE Input template to pass to gen_input.py" + echo " -W FILE List of kB working set sizes to pass gen_input.py" + echo " -T IN_ID Input template to pass to gen_input.py (eg. in0)" echo " -C FILE List of cache configurations to test" echo "Mode pair options:" echo " -P CPU CPU to run the 2nd benchmark on" @@ -87,7 +87,7 @@ if [[ "$mode" == "dis" ]] && [[ ! -f "$wss_settings" ]]; then echo "Invalid argument: $wss_settings does not exist" exit fi -if [[ "$mode" == "dis" ]] && [[ ! -f "$template_input" ]]; then +if [[ "$mode" == "dis" ]] && [[ ! -f "inputs/Field/$template_input" ]]; then echo "Invalid argument: $template_input does not exist" exit fi @@ -350,9 +350,9 @@ for (( i = 0; i < ${#bench[@]} ; i++ )); do echo $j > /sys/fs/resctrl/benchmarks/schemata while read ii; do # For WSS setting if [[ -v $LITMUS ]]; then - ./gen_input.py ${bench[$i]} inputs/${bench[$i]^}/$template_input $ii | numactl $numa_arg0 $prefix/${bench[$i]} $bench[$i]}-$ii-$j $maxJobs $core $runID 1 + ./gen_input.py ${bench[$i]} inputs/${bench[$i]^}/$template_input $ii | numactl $numa_arg0 $prefix/${bench[$i]} $bench{[$i]}-$ii-$j $maxJobs $core $runID-$userRunID 1 else - ./gen_input.py ${bench[$i]} inputs/${bench[$i]^}/$template_input $ii | chrt -r 97 numactl $numa_arg0 taskset -c $core $prefix/${bench[$i]} ${bench[$i]}-$ii-$j $maxJobs $core $runID 1 + ./gen_input.py ${bench[$i]} inputs/${bench[$i]^}/$template_input $ii | chrt -r 97 numactl $numa_arg0 taskset -c $core $prefix/${bench[$i]} ${bench[$i]}-$ii-$j $maxJobs $core $runID-$userRunID 1 fi done < $wss_settings done < $cache_settings -- cgit v1.2.2