28
28
# - See #TODOs for known limitations.
29
29
30
30
# 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.
32
31
class GenericSTDMetrics ():
33
- def __init__ (self , results_dir ):
32
+ def __init__ (self , results_dir , crate ):
34
33
self .results_directory = results_dir
34
+ self .crate = crate
35
35
self .unsafe_fns_count = 0
36
36
self .safe_abstractions_count = 0
37
37
self .safe_fns_count = 0
@@ -44,7 +44,7 @@ def __init__(self, results_dir):
44
44
# Read {crate}_overall_counts.csv
45
45
# and return the number of unsafe functions and safe abstractions
46
46
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"
48
48
with open (file_path , 'r' ) as f :
49
49
csv_reader = csv .reader (f , delimiter = ';' )
50
50
counts = {row [0 ]: int (row [1 ]) for row in csv_reader if len (row ) >= 2 }
@@ -56,7 +56,7 @@ def read_overall_counts(self):
56
56
# and return an array of the unsafe functions and the safe abstractions
57
57
def read_scan_functions (self ):
58
58
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"
60
60
61
61
with open (file_path , 'r' ) as f :
62
62
csv_reader = csv .reader (f , delimiter = ';' , quotechar = '"' )
@@ -90,19 +90,19 @@ def read_std_analysis(self):
90
90
91
91
# Sanity checks
92
92
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" )
94
94
print (f"UNSAFE_FNS_COUNT: { self .unsafe_fns_count } " )
95
95
print (f"UNSAFE_FNS length: { len (self .unsafe_fns )} " )
96
96
sys .exit (1 )
97
97
98
98
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" )
100
100
print (f"SAFE_ABSTRACTIONS_COUNT: { self .safe_abstractions_count } " )
101
101
print (f"SAFE_ABSTRACTIONS length: { len (self .safe_abstractions )} " )
102
102
sys .exit (1 )
103
103
104
104
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" )
106
106
print (f"SAFE_FNS_COUNT: { self .safe_fns_count } " )
107
107
print (f"SAFE_FNS length: { len (self .safe_fns )} " )
108
108
sys .exit (1 )
@@ -140,7 +140,8 @@ def read_kani_list_data(self, kani_list_filepath):
140
140
# Generate metrics about Kani's application to the standard library over time
141
141
# by reading past metrics from metrics_file, then computing today's metrics.
142
142
class KaniSTDMetricsOverTime ():
143
- def __init__ (self , metrics_file ):
143
+ def __init__ (self , metrics_file , crate ):
144
+ self .crate = crate
144
145
self .dates = []
145
146
self .unsafe_metrics = ['total_unsafe_fns' , 'unsafe_fns_under_contract' , 'verified_unsafe_fns_under_contract' ]
146
147
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):
190
191
191
192
# Process the `kani list` and `std-analysis.sh` data
192
193
kani_data = KaniListSTDMetrics (kani_list_filepath )
193
- generic_metrics = GenericSTDMetrics (analysis_results_dir )
194
+ generic_metrics = GenericSTDMetrics (analysis_results_dir , self . crate )
194
195
195
196
print ("Comparing kani-list output to std-analysis.sh output and computing metrics..." )
196
197
@@ -280,12 +281,28 @@ def plot_single(self, data, title, filename, plot_dir):
280
281
print (f"PNG graph generated: { outfile } " )
281
282
282
283
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 )
286
299
287
300
def main ():
288
301
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" )
289
306
parser .add_argument ('--metrics-file' ,
290
307
type = str ,
291
308
default = "metrics-data.json" ,
@@ -308,7 +325,7 @@ def main():
308
325
309
326
args = parser .parse_args ()
310
327
311
- metrics = KaniSTDMetricsOverTime (args .metrics_file )
328
+ metrics = KaniSTDMetricsOverTime (args .metrics_file , args . crate )
312
329
313
330
if args .plot_only :
314
331
metrics .plot (args .plot_dir )
0 commit comments