1+ #!/usr/bin/env python3
2+
3+ import sys
4+ import re
5+ import argparse
6+
7+ # Function to format a number to two significant digits
8+ def format_to_two_sig_digits (value ):
9+ if not isinstance (value , (int , float )) or value == 0 :
10+ return "N/A"
11+
12+ # Handle negative numbers
13+ is_negative = value < 0
14+ abs_value = abs (value )
15+
16+ exponent = 0
17+
18+ while abs_value >= 100 :
19+ abs_value /= 10
20+ exponent += 1
21+ while abs_value < 10 :
22+ abs_value *= 10
23+ exponent -= 1
24+
25+ # Round to two significant digits
26+ abs_value = round (abs_value , 0 )
27+
28+ # Format the number
29+ if exponent >= 0 and exponent <= 4 :
30+ format = f"{ '-' if is_negative else '' } { abs_value * 10 ** exponent } "
31+ format = format .replace (".0" , "" )
32+ return format
33+ elif exponent < 0 and exponent >= - 4 :
34+ return f"{ '-' if is_negative else '' } { abs_value * 10 ** exponent :.1f} "
35+ else :
36+ return f"{ '-' if is_negative else '' } { abs_value :.1f} e{ exponent } "
37+
38+ # Function to parse the raw input data
39+ def parse_input (data ):
40+ lines = data .splitlines ()
41+ parsed_data = []
42+ current_entry = None
43+
44+ for line in lines :
45+ line = line .strip ()
46+ # Skip empty lines or comments
47+ if not line or line .startswith ("#" ):
48+ continue
49+
50+ # Match lines that start a new entry (e.g., "just_string : 1365.92 MB/s ...")
51+ match_entry = re .match (r"(\S+)\s*:\s*[\d.]+\s*MB/s" , line )
52+ if match_entry :
53+ current_entry = {"name" : match_entry .group (1 )}
54+ parsed_data .append (current_entry )
55+ if not current_entry :
56+ continue
57+ # Match lines with ns/f
58+ match_ns = re .search (r"([\d.]+)\s*ns/f" , line )
59+ if match_ns and current_entry :
60+ current_entry ["ns_per_float" ] = float (match_ns .group (1 ))
61+
62+ # Match lines with instructions/float (i/f)
63+ match_inst_float = re .search (r"([\d.]+)\s*i/f" , line )
64+ if match_inst_float and current_entry :
65+ current_entry ["inst_per_float" ] = float (match_inst_float .group (1 ))
66+
67+ # Match lines with instructions/cycle (i/c)
68+ match_inst_cycle = re .search (r"([\d.]+)\s*i/c" , line )
69+ if match_inst_cycle and current_entry :
70+ current_entry ["inst_per_cycle" ] = float (match_inst_cycle .group (1 ))
71+
72+ # Filter out incomplete entries
73+ return parsed_data
74+
75+ # Function to generate LaTeX table
76+ def generate_latex_table (data ):
77+ latex_table = r"""
78+ \begin{tabular}{lccc}
79+ \toprule
80+ \textbf{Name} & \textbf{ns/f} & \textbf{instructions/float} & \textbf{instructions/cycle} \\
81+ \midrule
82+ """
83+
84+ for entry in data :
85+ name = entry ["name" ].replace ("_" , "\\ _" ) # Escape underscores for LaTeX
86+ ns_per_float = format_to_two_sig_digits (entry ['ns_per_float' ]) if 'ns_per_float' in entry else 'N/A'
87+ inst_per_float = format_to_two_sig_digits (entry ['inst_per_float' ]) if 'inst_per_float' in entry else 'N/A'
88+ inst_per_cycle = format_to_two_sig_digits (entry ['inst_per_cycle' ]) if 'inst_per_cycle' in entry else 'N/A'
89+ latex_table += f"{ name } & { ns_per_float } & { inst_per_float } & { inst_per_cycle } \\ \\ \n "
90+
91+ latex_table += r"""\bottomrule
92+ \end{tabular}
93+ """
94+ return latex_table
95+
96+ if __name__ == "__main__" :
97+ parser = argparse .ArgumentParser (description = "Generate LaTeX table from performance data" )
98+ parser .add_argument ("file" , nargs = "?" , help = "Optional input file name (if not provided, reads from stdin)" )
99+ args = parser .parse_args ()
100+
101+ # Read input data
102+ if args .file :
103+ try :
104+ with open (args .file , "r" ) as f :
105+ raw_input = f .read ()
106+ except FileNotFoundError :
107+ print (f"Error: File '{ args .file } ' not found." , file = sys .stderr )
108+ sys .exit (1 )
109+ except IOError as e :
110+ print (f"Error reading file '{ args .file } ': { e } " , file = sys .stderr )
111+ sys .exit (1 )
112+ else :
113+ raw_input = sys .stdin .read ()
114+ parsed_data = parse_input (raw_input )
115+ latex_output = generate_latex_table (parsed_data )
116+ print (latex_output )
0 commit comments