2828# - See #TODOs for known limitations.
2929
3030# Process the results from Kani's std-analysis.sh script for each crate.
31- # TODO For now, we just handle "core", but we should process all crates in the library.
3231class GenericSTDMetrics ():
33- def __init__ (self , results_dir ):
32+ def __init__ (self , results_dir , crate ):
3433 self .results_directory = results_dir
34+ self .crate = crate
3535 self .unsafe_fns_count = 0
3636 self .safe_abstractions_count = 0
3737 self .safe_fns_count = 0
@@ -44,7 +44,7 @@ def __init__(self, results_dir):
4444 # Read {crate}_overall_counts.csv
4545 # and return the number of unsafe functions and safe abstractions
4646 def read_overall_counts (self ):
47- file_path = f"{ self .results_directory } /core_scan_overall .csv"
47+ file_path = f"{ self .results_directory } /{ self . crate } _scan_overall .csv"
4848 with open (file_path , 'r' ) as f :
4949 csv_reader = csv .reader (f , delimiter = ';' )
5050 counts = {row [0 ]: int (row [1 ]) for row in csv_reader if len (row ) >= 2 }
@@ -56,7 +56,7 @@ def read_overall_counts(self):
5656 # and return an array of the unsafe functions and the safe abstractions
5757 def read_scan_functions (self ):
5858 expected_header_start = "name;is_unsafe;has_unsafe_ops"
59- file_path = f"{ self .results_directory } /core_scan_functions .csv"
59+ file_path = f"{ self .results_directory } /{ self . crate } _scan_functions .csv"
6060
6161 with open (file_path , 'r' ) as f :
6262 csv_reader = csv .reader (f , delimiter = ';' , quotechar = '"' )
@@ -90,19 +90,19 @@ def read_std_analysis(self):
9090
9191 # Sanity checks
9292 if len (self .unsafe_fns ) != self .unsafe_fns_count :
93- print (f"Number of unsafe functions does not match core_scan_functions .csv" )
93+ print (f"Number of unsafe functions does not match { self . crate } _scan_functions .csv" )
9494 print (f"UNSAFE_FNS_COUNT: { self .unsafe_fns_count } " )
9595 print (f"UNSAFE_FNS length: { len (self .unsafe_fns )} " )
9696 sys .exit (1 )
9797
9898 if len (self .safe_abstractions ) != self .safe_abstractions_count :
99- print (f"Number of safe abstractions does not match core_scan_functions .csv" )
99+ print (f"Number of safe abstractions does not match { self . crate } _scan_functions .csv" )
100100 print (f"SAFE_ABSTRACTIONS_COUNT: { self .safe_abstractions_count } " )
101101 print (f"SAFE_ABSTRACTIONS length: { len (self .safe_abstractions )} " )
102102 sys .exit (1 )
103103
104104 if len (self .safe_fns ) != self .safe_fns_count :
105- print (f"Number of safe functions does not match core_scan_functions .csv" )
105+ print (f"Number of safe functions does not match { self . crate } _scan_functions .csv" )
106106 print (f"SAFE_FNS_COUNT: { self .safe_fns_count } " )
107107 print (f"SAFE_FNS length: { len (self .safe_fns )} " )
108108 sys .exit (1 )
@@ -140,7 +140,8 @@ def read_kani_list_data(self, kani_list_filepath):
140140# Generate metrics about Kani's application to the standard library over time
141141# by reading past metrics from metrics_file, then computing today's metrics.
142142class KaniSTDMetricsOverTime ():
143- def __init__ (self , metrics_file ):
143+ def __init__ (self , metrics_file , crate ):
144+ self .crate = crate
144145 self .dates = []
145146 self .unsafe_metrics = ['total_unsafe_fns' , 'unsafe_fns_under_contract' , 'verified_unsafe_fns_under_contract' ]
146147 self .safe_abstr_metrics = ['total_safe_abstractions' , 'safe_abstractions_under_contract' , 'verified_safe_abstractions_under_contract' ]
@@ -190,7 +191,7 @@ def compute_metrics(self, kani_list_filepath, analysis_results_dir):
190191
191192 # Process the `kani list` and `std-analysis.sh` data
192193 kani_data = KaniListSTDMetrics (kani_list_filepath )
193- generic_metrics = GenericSTDMetrics (analysis_results_dir )
194+ generic_metrics = GenericSTDMetrics (analysis_results_dir , self . crate )
194195
195196 print ("Comparing kani-list output to std-analysis.sh output and computing metrics..." )
196197
@@ -280,12 +281,28 @@ def plot_single(self, data, title, filename, plot_dir):
280281 print (f"PNG graph generated: { outfile } " )
281282
282283 def plot (self , plot_dir ):
283- self .plot_single (self .unsafe_plot_data , title = "Contracts on Unsafe Functions in core" , filename = "core_unsafe_metrics.png" , plot_dir = plot_dir )
284- self .plot_single (self .safe_abstr_plot_data , title = "Contracts on Safe Abstractions in core" , filename = "core_safe_abstractions_metrics.png" , plot_dir = plot_dir )
285- self .plot_single (self .safe_plot_data , title = "Contracts on Safe Functions in core" , filename = "core_safe_metrics.png" , plot_dir = plot_dir )
284+ self .plot_single (
285+ self .unsafe_plot_data ,
286+ title = f"Contracts on Unsafe Functions in { self .crate } " ,
287+ filename = f"{ self .crate } _unsafe_metrics.png" ,
288+ plot_dir = plot_dir )
289+ self .plot_single (
290+ self .safe_abstr_plot_data ,
291+ title = f"Contracts on Safe Abstractions in { self .crate } " ,
292+ filename = f"{ self .crate } _safe_abstractions_metrics.png" ,
293+ plot_dir = plot_dir )
294+ self .plot_single (
295+ self .safe_plot_data ,
296+ title = f"Contracts on Safe Functions in { self .crate } " ,
297+ filename = f"{ self .crate } _safe_metrics.png" ,
298+ plot_dir = plot_dir )
286299
287300def main ():
288301 parser = argparse .ArgumentParser (description = "Generate metrics about Kani's application to the standard library." )
302+ parser .add_argument ('--crate' ,
303+ type = str ,
304+ required = True ,
305+ help = "Name of standard library crate to produce metrics for" )
289306 parser .add_argument ('--metrics-file' ,
290307 type = str ,
291308 default = "metrics-data.json" ,
@@ -308,7 +325,7 @@ def main():
308325
309326 args = parser .parse_args ()
310327
311- metrics = KaniSTDMetricsOverTime (args .metrics_file )
328+ metrics = KaniSTDMetricsOverTime (args .metrics_file , args . crate )
312329
313330 if args .plot_only :
314331 metrics .plot (args .plot_dir )
0 commit comments