diff options
Diffstat (limited to 'measurements/tolatex.py')
-rw-r--r-- | measurements/tolatex.py | 233 |
1 files changed, 0 insertions, 233 deletions
diff --git a/measurements/tolatex.py b/measurements/tolatex.py deleted file mode 100644 index f85ee41af..000000000 --- a/measurements/tolatex.py +++ /dev/null @@ -1,233 +0,0 @@ -# Generates benchmark graphs in LaTex (following format from the pgfplots -# package) -import sys, math, re - -USAGE = "USAGE: python tolatex.py [input file] {plot32, plot64, table32, table64}" - -SETUPS = { - "gmpxx": "color=red,mark=x", - "gmpsec" : "color=red,mark=*", - "gmpvar": "color=red,mark=o", - "fiat_montgomery": "color=blue,mark=triangle*", - "fiat_solinas": "color=blue,mark=triangle", - } - -# setups to combine and functions to combine them -COMBINE = [ - ("fiat_montgomery", "fiat_solinas", min), - ] - -# setups to exclude -EXCLUDE = [ - "gmpxx" - ] - -LEGEND = { - "fiat_montgomery": "this paper", - "fiat_solinas": "this paper", - "gmpvar": "GMP mpn API", - "gmpxx": "GMP C++ API", - "gmpsec" : "GMP mpn_sec API" - } - -class ParseException(Exception): pass -class MissingDataException(Exception): pass - -# given a string representing one term or "tap" in a prime, returns a pair of -# integers representing the weight and coefficient of that tap -# "2 ^ y" -> [1, y] -# "x * 2 ^ y" -> [x, y] -# "x * y" -> [x*y,0] -# "x" -> [x,0] -def parse_term(t) : - if "*" not in t and "^" not in t: - return [int(t),0] - - if "*" in t: - if len(t.split("*")) > 2: # this occurs when e.g. [w - x * y] has been turned into [w + -1 * x * y] - a1,a2,b = t.split("*") - a = int(a1) * int(a2) - else: - a,b = t.split("*") - if "^" not in b: - return [int(a) * int(b),0] - else: - a,b = (1,t) - - b,e = b.split("^") - if int(b) != 2: - raise ParseException("Could not parse term, power with base other than 2: %s" %t) - return [int(a),int(e)] - -# expects prime to be a string and expressed as sum/difference of products of -# two with small coefficients (e.g. '2^448 - 2^224 - 1', '2^255 - 19') -# returns tuple (string representation, numeric value) -def parse_prime(prime): - rep = prime.replace("e", "^").replace("m", "-").replace("p","+").replace("x","*") - terms = rep.replace("-", "+ -").replace(' ', '').replace('+-2^', '+-1*2^').split("+") - value = sum([(x * (2**e)) for x,e in map(parse_term, terms)]) - return (rep, value) - -def parse_line(line): - data = line.strip().split("\t") - if len(data) != 3 or (data[1] not in SETUPS) or ("2e" not in data[0]) : - raise ParseException("Could not parse line %s" %line.strip()) - return { - "prime" : data[0], - "setup" : data[1], - "time" : data[2] } - -def final_lines(bits): - out = [] - for s in SETUPS: - if (s in EXCLUDE) or any([x[1]==s for x in COMBINE]): - continue # in this case, the setup has been combined into some other one - out.append(s) - return out - -# check for missing data points -def check_missing(data, bits): - all_primes = set() - for s in final_lines(bits): - all_primes = all_primes | set(data[s].keys()) - missing = [] - for s in final_lines(bits): - x = all_primes ^ set(data[s].keys()) - if len(x) != 0: - missing.append((s, x)) - if len(missing) > 0: - message = "\n".join(["missing datapoints in %s: primes are %s" %(LEGEND[s],list(map(lambda t:t[0], x))) for s,x in missing]) - print("WARNING: %s" %message) - #raise MissingDataException(message) - -# reorganize, and parse primes -def clean_plot_data(parsed_lines, bits): - out = {s:{} for s in SETUPS} - for ln in parsed_lines: - p = parse_prime(ln["prime"]) - if p in out[ln["setup"]]: - out[ln["setup"]][p] = min(float(ln["time"]), out[ln["setup"]][p]) - else: - out[ln["setup"]][p] = float(ln["time"]) - # combine setups according to COMBINE list - for s1, s2, f in COMBINE: - all_primes = list(out[s1].keys()) - all_primes.extend(out[s2].keys()) - for p in set(all_primes): - if p in out[s1] and p in out[s2]: - out[s1][p] = f(out[s1][p], out[s2][p]) - elif p in out[s2]: - out[s1][p] = out[s2][p] - check_missing(out, bits) - return out - -# remove duplicates, reorganize, and parse primes -def clean_table_data(parsed_lines): - all_primes = set([ln["prime"] for ln in parsed_lines]) - out = {p:{} for p in all_primes} - for ln in parsed_lines: - prime = ln["prime"] - s = ln["setup"] - if s in out[prime]: - out[prime][s] = min(float(ln["time"]), out[prime][s]) - else: - out[prime][s] = float(ln["time"]) - return out - -def maketable(data, bits): - if bits == 64: - out="""\\tablehead{% - \\hline - & \\multicolumn{2}{c|}{\\textbf{Our Code}} & \\multicolumn{3}{c|}{\\textbf{GMP Code}} & \\\\ - \\cline{2-6} - \\textbf{Prime} & \\textbf{Sol.} & \\textbf{Mont.} & \\textbf{const time} & \\textbf{var time} & \\textbf{C++} & \\textbf{Speedup} \\\\ \\hline} -\\footnotesize -\\begin{xtabular}{|l|p{0.6cm}|p{0.6cm}|p{0.6cm}|p{0.6cm}|p{0.6cm}|p{0.6cm}|}\n""" - else: - out="""\\tablehead{% - \\hline - & \\multicolumn{2}{c|}{\\textbf{Our Code}} & \\multicolumn{2}{c|}{\\textbf{GMP Code}} & \\\\ - \\cline{2-5} - \\textbf{Prime} & \\textbf{Solinas} & \\textbf{Mont.} & \\textbf{const time} & \\textbf{var time} & \\textbf{Speedup} \\\\ \\hline} -\\footnotesize -\\begin{xtabular}{|l|p{0.7cm}|p{0.7cm}|p{0.7cm}|p{0.7cm}|p{0.9cm}|}\n""" - - cols_64 = ["fiat_solinas", "fiat_montgomery", "gmpsec", "gmpvar", "gmpxx"] - cols_32 = ["fiat_solinas", "fiat_montgomery", "gmpsec", "gmpvar"] - cols = cols_64 if bits == 64 else cols_32 - - for p in sorted(data.keys()): - prime_latex= re.sub("2\^[0-9]+", lambda matchobj : "2^{%s}" %matchobj.group(0)[2:], parse_prime(p)[0]) - prime_latex= re.sub("[0-9]\*[0-9]", lambda matchobj : "%s\cdot %s" %(matchobj.group(0)[0], matchobj.group(0)[2]), prime_latex) - row = ["$" + prime_latex + "$"] - our_best = None - gmp_best = None - for s in cols: - if s in data[p]: - row.append(str(data[p][s])) - if "fiat" in s and (our_best == None or float(data[p][s]) < our_best): - our_best = float(data[p][s]) - if "gmp" in s and (gmp_best == None or float(data[p][s]) < gmp_best): - gmp_best = float(data[p][s]) - else: - row.append("-") - if our_best != None and gmp_best != None: - row.append(str(round(gmp_best/our_best, 2))) - else: - row.append("-") - out += ("\t" + " & ".join(row) + " \\\\ \n") - - out +="""\\hline\n\\end{xtabular}""" - return out - -def makeplot(data, bits): - out = """ - \\begin{figure*} - \\begin{tikzpicture} - \t\\begin{axis}[ - \t\theight=3.4cm, - \t\ttitle style={font=\small}, - \t\ttitle=%s-Bit Field Arithmetic Benchmarks, - \t\twidth=\\textwidth, - \t\tlegend pos= north west, - \t\txtick distance=64, - \t\tlegend style={font=\\tiny}, - \t\tlabel style={font=\\footnotesize}, - \t\txlabel style={at={(0.5,0.1)}, anchor=north}, - \t\tlegend columns=2, - \t\ttick label style={font=\\footnotesize}, - \t\tgrid=major, - \t\tymin=0, - \t\txlabel=log2(prime), - \t\tylabel=Time (seconds)]\n""" %bits - for s in final_lines(bits): - out +="\t\t\\addplot[%s,mark size=2pt] coordinates {\n" %SETUPS[s] - for p,t in sorted(data[s].items()): - out += "\t\t\t(%s, %s) \n" %(math.log2(p[1]), t) - out += "\t\t};\n" - out += "\t\t\\addlegendentry{%s}\n\n" %LEGEND[s].replace("_", "\_") - out += "\t\end{axis}\n\\end{tikzpicture}\n\\end{figure*}" - return out - -if __name__ == "__main__": - if len(sys.argv) != 3 or sys.argv[2] not in ["plot32", "plot64", "table32", "table64"]: - print(USAGE) - sys.exit() - f = open(sys.argv[1]) - parsed_lines = [] - for line in f: - try: - parsed_lines.append(parse_line(line)) - except ParseException: - print("WARNING: Could not parse line %s, skipping" %line.strip().split("\t")) - f.close() - - if sys.argv[2] == "table32": - print(maketable(clean_table_data(parsed_lines), 32)) - if sys.argv[2] == "table64": - print(maketable(clean_table_data(parsed_lines), 64)) - elif sys.argv[2] == "plot32": - print(makeplot(clean_plot_data(parsed_lines, 32), 32)) - elif sys.argv[2] == "plot64": - print(makeplot(clean_plot_data(parsed_lines, 64), 64)) - |