summaryrefslogtreecommitdiffstats
path: root/smt_analysis
diff options
context:
space:
mode:
authorJoshua Bakita <jbakita@cs.unc.edu>2020-10-22 00:27:52 -0400
committerJoshua Bakita <jbakita@cs.unc.edu>2020-10-22 00:28:01 -0400
commite7562d1b6e782a415a44be280dc51b0e104242b7 (patch)
tree959c2e4511dc774f2099473d418d61bf8bd0102d /smt_analysis
parent4f634d4cd3254dfc68b65e63be32708105032101 (diff)
Add a phenomenal script to distill SMT pair data to Mij and Mi scores
Diffstat (limited to 'smt_analysis')
-rwxr-xr-xsmt_analysis/computeSMTslowdown.py291
1 files changed, 291 insertions, 0 deletions
diff --git a/smt_analysis/computeSMTslowdown.py b/smt_analysis/computeSMTslowdown.py
new file mode 100755
index 0000000..2cf58ac
--- /dev/null
+++ b/smt_analysis/computeSMTslowdown.py
@@ -0,0 +1,291 @@
1#!/usr/bin/python3
2from typing import List, Any
3import numpy as np
4from scipy import stats
5import sys
6import os
7import plotille.plotille as plt
8TIMING_ERROR = 1000 #ns
9LEVEL_C_ANALYSIS = False
10
11def print_usage(argv):
12 print("This program takes in the all-pairs and baseline SMT data and computes how much each program is slowed when SMT in enabled.", file=sys.stderr)
13 print("Level-A/B usage: {} <file -A> <file -B> <baseline file> --cij".format(argv[0]), file=sys.stderr)
14 print("Level-C usage: {} <continuous pairs> <baseline file>".format(argv[0]), file=sys.stderr)
15
16# Check that we got the right number of parameters
17if len(sys.argv) < 3:
18 print_usage(sys.argv)
19 exit()
20
21if len(sys.argv) > 3:
22 print("Analyzing results using Level-A/B methodology...")
23else:
24 print("Analyzing results using Level-C methodology...")
25 LEVEL_C_ANALYSIS = True
26
27# Check that all input files are valid
28for f in sys.argv[1:-1]:
29 if not os.path.exists(f) or os.path.getsize(f) == 0:
30 print("ERROR: File '{}' does not exist or is empty".format(f), file=sys.stderr);
31 print_usage(sys.argv)
32 exit()
33
34# Print Cij values rather than Mij
35TIMES_ONLY = len(sys.argv) > 4 and "--cij" in sys.argv[4]
36OK_PAIRS_ONLY = len(sys.argv) > 4 and "--cij-ok" in sys.argv[4]
37
38# This parses the result data from unthreaded timing experiments
39# @param f File name to load
40# @returns res Map of benchmark name to sample count
41# @returns samples Map of benchmark name to list of execution time samples
42# @returns max_res May of benchmark to maximum execution time among all samples for that benchmark
43def load_baseline(f):
44 # constants for columns of baseline data files
45 TOTAL_NS = 5
46 BENCH_NAME = 0
47 SAMPLES = 4
48
49 # Load baseline data. This logic is based off the summarize programs
50 res = {} # Map of benchmark to list of all execution time samples
51 samples = {} # Map of benchmark name to sample count
52 max_res = {} # Map of benchmark name to maximum execution time
53
54 with open(f) as fp:
55 for line in fp:
56 s = line.split()
57 if s[BENCH_NAME] not in res:
58 res[s[BENCH_NAME]] = list([int(s[TOTAL_NS])])
59 samples[s[BENCH_NAME]] = int(s[SAMPLES])
60 max_res[s[BENCH_NAME]] = int(s[TOTAL_NS])
61 else:
62 res[s[BENCH_NAME]].append(int(s[TOTAL_NS]))
63 max_res[s[BENCH_NAME]] = max(int(s[TOTAL_NS]), max_res[s[BENCH_NAME]])
64 return res, samples, max_res
65
66# This parses the result data from paired, threaded timing experiements
67# @param file1 The -A file name
68# @param file2 The -B file name
69# @returns time 2D array of benchmark IDs to list of total container execution times
70# @returns offset 2D array of benchmark IDs to list of differences between the start
71# of the first and the start of the second benchmark
72# @returns name_to_idx Map of benchmark names to benchmark IDs
73# @returns idx_to_name List which when indexed with benchmark ID will yield the benchmark name
74def load_paired(file1, file2, benchmarkCount):
75 # constants for columns of paired data files
76 FIRST_PROG = 0
77 SECOND_PROG = 1
78 FIRST_CORE = 2
79 SECOND_CORE = 3
80 TRIALS = 4
81 START_S = 5 # Start seconds
82 START_N = 6 # Start nanoseconds
83 END_S = 7 # End seconds
84 END_N = 8 # End nanoseconds
85 RUN_ID = 9
86 JOB_NUM = 10
87
88 with open(file1) as f1:
89 numJobs = int(f1.readline().split()[TRIALS])
90 assert numJobs > 0
91 assert benchmarkCount > 0
92
93 # Total times of each container
94 time=[[[0 for x in range(numJobs)]for y in range(benchmarkCount)]for z in range(benchmarkCount)]
95 # Difference in time between when the first and the second task start in the container
96 offset=[[[0 for x in range(numJobs)]for y in range(benchmarkCount)]for z in range(benchmarkCount)]
97
98 # Some aggregate counters that we update as we go along
99 avg_off = 0
100 avg_off_samp = 0
101
102 # Load paired data
103 bench1 = 0 # Index to what's the current first benchmark being examined
104 bench2 = 0 # Index to what's the current second benchmark being examined
105
106 name_to_idx = {}
107 idx_to_name = [0 for x in range(benchmarkCount)]
108
109 job_idx = 0
110 with open(file1) as f1, open(file2) as f2:
111 for line1, line2 in zip(f1, f2):
112 lineArr1 = line1.split()
113 lineArr2 = line2.split()
114 start1 = int(lineArr1[START_S]) * 10**9 + int(lineArr1[START_N])
115 start2 = int(lineArr2[START_S]) * 10**9 + int(lineArr2[START_N])
116 minStart = min(start1, start2)
117 end1 = int(lineArr1[END_S]) * 10**9 + int(lineArr1[END_N])
118 end2 = int(lineArr2[END_S]) * 10**9 + int(lineArr2[END_N])
119 maxEnd = max(end1, end2)
120 # Time actually co-scheduled is minEnd - maxStart, but Sims uses a different model
121# time[bench1][bench2][int(lineArr1[JOB_NUM])] = maxEnd - minStart
122 time[bench1][bench2][job_idx] = maxEnd - minStart
123 if lineArr1[SECOND_PROG] == "h264_dec" and lineArr2[JOB_NUM] == 0:
124 print(maxEnd - minStart)
125 # Compute offset: if first job starts at t=0, when does second start?
126# offset[bench1][bench2][int(lineArr1[JOB_NUM])] = abs(start2-start1)
127 offset[bench1][bench2][job_idx] = abs(start2-start1)
128 # Compute some running statistics
129 avg_off += abs(start2-start1)
130 avg_off_samp += 1
131 # Increment to the next benchmark, this is weird because of the zip()
132 # This is doubly weird because our results are an upper trianguler matrix
133 if job_idx == numJobs - 1: #int(lineArr1[JOB_NUM]) == numJobs - 1:
134 if bench2 < benchmarkCount-1:
135 bench2 = bench2 + 1
136 job_idx = 0
137 else:
138 name_to_idx[lineArr1[FIRST_PROG]] = bench1
139 idx_to_name[bench1] = lineArr1[FIRST_PROG]
140 bench1 = bench1 + 1
141 bench2 = bench1 # bench1 will never again appear as bench2
142 job_idx = 0
143 else:
144 job_idx += 1
145 print("Average offset is: " + str(avg_off/avg_off_samp) + "ns")
146 return time, offset, name_to_idx, idx_to_name
147
148# Pull in the data
149if not LEVEL_C_ANALYSIS:
150 baseline_times, baseline_sample_cnt, baseline_max_times = load_baseline(sys.argv[3])
151 paired_times, paired_offsets, name_to_idx, idx_to_name = load_paired(sys.argv[1], sys.argv[2], len(list(baseline_times.keys())))
152 for key in baseline_times:
153 print(key,max(baseline_times[key]))
154else:
155 baseline_times, baseline_sample_cnt, baseline_max_times = load_baseline(sys.argv[2])
156 # Paired times use an abuse of the baseline file format
157 paired_times_raw, _, _ = load_baseline(sys.argv[1])
158 benchmarkCount = int(np.sqrt(len(list(paired_times_raw.keys()))))
159 numJobs = len(next(iter(paired_times_raw.values())))
160 paired_times=[[[0 for x in range(numJobs)]for y in range(benchmarkCount)]for z in range(benchmarkCount)]
161 idx_to_name=[]
162 name_to_idx={}
163 bench1 = -1
164 #Generate the indexing approach
165 for pair in sorted(paired_times_raw.keys()):
166 [bench1name, bench2name] = pair.split('+') # Benchmark name is pair concatenated together with a '+' delimiter
167 if bench1 == -1 or bench1name != idx_to_name[-1]:
168 idx_to_name.append(bench1name)
169 name_to_idx[bench1name] = len(idx_to_name) - 1
170 bench1 += 1
171 # Populate the array
172 for bench1 in range(len(idx_to_name)):
173 for bench2 in range(len(idx_to_name)):
174 paired_times[bench1][bench2] = paired_times_raw[idx_to_name[bench1]+"+"+idx_to_name[bench2]]
175
176# We work iff the baseline was run for the same set of benchmarks as the pairs were
177if sorted(baseline_times.keys()) != sorted(name_to_idx.keys()):
178 print("ERROR: The baseline and paired experiments were over a different set of benchmarks!", file=sys.stderr)
179 print("Baseline keys:", baseline_times.keys(), file=sys.stderr)
180 print("Paired keys:", name_to_idx.keys(), file=sys.stderr)
181 exit();
182
183# Only consider benchmarks that are at least an order of magnitude longer than the timing error
184reliableNames = []
185for i in range(0, len(name_to_idx)):
186 benchmark = idx_to_name[i]
187 if min(baseline_times[benchmark]) > TIMING_ERROR * 10:
188 reliableNames.append(benchmark)
189
190# Compute SMT slowdown for each benchmark
191# Output format: table, each row is one benchmark and each column is one benchmark