@@ -26,8 +26,10 @@ def __init__(self):
26
26
self .results_directory = "/tmp/std_lib_analysis/results"
27
27
self .unsafe_fns_count = 0
28
28
self .safe_abstractions_count = 0
29
+ self .safe_fns_count = 0
29
30
self .unsafe_fns = []
30
31
self .safe_abstractions = []
32
+ self .safe_fns = []
31
33
32
34
self .read_std_analysis ()
33
35
@@ -40,6 +42,7 @@ def read_overall_counts(self):
40
42
counts = {row [0 ]: int (row [1 ]) for row in csv_reader if len (row ) >= 2 }
41
43
self .unsafe_fns_count = counts .get ('unsafe_fns' , 0 )
42
44
self .safe_abstractions_count = counts .get ('safe_abstractions' , 0 )
45
+ self .safe_fns_count = counts .get ('safe_fns' , 0 )
43
46
44
47
# Read {crate}_scan_functions.csv
45
48
# and return an array of the unsafe functions and the safe abstractions
@@ -66,15 +69,18 @@ def read_scan_functions(self):
66
69
# An unsafe function is a function for which is_unsafe=true
67
70
if is_unsafe .strip () == "true" :
68
71
self .unsafe_fns .append (name )
69
- # A safe abstraction is a function that is not unsafe (is_unsafe=false) but has unsafe ops
70
- elif is_unsafe .strip () == "false" and has_unsafe_ops .strip () == "true" :
71
- self .safe_abstractions .append (name )
72
+ else :
73
+ assert is_unsafe .strip () == "false" # sanity check against malformed data
74
+ self .safe_fns .append (name )
75
+ # A safe abstraction is a safe function with unsafe ops
76
+ if has_unsafe_ops .strip () == "true" :
77
+ self .safe_abstractions .append (name )
72
78
73
79
def read_std_analysis (self ):
74
80
self .read_overall_counts ()
75
81
self .read_scan_functions ()
76
82
77
- # Sanity checks for the CSV parsing
83
+ # Sanity checks
78
84
if len (self .unsafe_fns ) != self .unsafe_fns_count :
79
85
print (f"Number of unsafe functions does not match core_scan_functions.csv" )
80
86
print (f"UNSAFE_FNS_COUNT: { self .unsafe_fns_count } " )
@@ -86,6 +92,12 @@ def read_std_analysis(self):
86
92
print (f"SAFE_ABSTRACTIONS_COUNT: { self .safe_abstractions_count } " )
87
93
print (f"SAFE_ABSTRACTIONS length: { len (self .safe_abstractions )} " )
88
94
sys .exit (1 )
95
+
96
+ if len (self .safe_fns ) != self .safe_fns_count :
97
+ print (f"Number of safe functions does not match core_scan_functions.csv" )
98
+ print (f"SAFE_FNS_COUNT: { self .safe_fns_count } " )
99
+ print (f"SAFE_FNS length: { len (self .safe_fns )} " )
100
+ sys .exit (1 )
89
101
90
102
# Process the results of running `kani list` against the standard library,
91
103
# i.e., the Kani STD metrics for a single date (whichever day this script is running).
@@ -124,10 +136,11 @@ def __init__(self, metrics_file):
124
136
self .dates = []
125
137
self .unsafe_metrics = ['total_unsafe_fns' , 'unsafe_fns_under_contract' , 'verified_unsafe_fns_under_contract' ]
126
138
self .safe_abstr_metrics = ['total_safe_abstractions' , 'safe_abstractions_under_contract' , 'verified_safe_abstractions_under_contract' ]
127
- # Generate two plots per crate: one with metrics about unsafe functions, and one with metrics about safe abstractions.
139
+ self . safe_metrics = [ 'total_safe_fns' , 'safe_fns_under_contract' , 'verified_safe_fns_under_contract' ]
128
140
# The keys in these dictionaries are unsafe_metrics and safe_abstr_metrics, respectively; see update_plot_metrics()
129
141
self .unsafe_plot_data = defaultdict (list )
130
142
self .safe_abstr_plot_data = defaultdict (list )
143
+ self .safe_plot_data = defaultdict (list )
131
144
132
145
self .date = datetime .today ().date ()
133
146
self .metrics_file = metrics_file
@@ -160,6 +173,10 @@ def update_plot_metrics(self, all_data):
160
173
for metric in self .safe_abstr_metrics :
161
174
if not metric .startswith ("verified" ):
162
175
self .safe_abstr_plot_data [metric ].append (data [metric ])
176
+
177
+ for metric in self .safe_metrics :
178
+ if not metric .startswith ("verified" ):
179
+ self .safe_plot_data [metric ].append (data [metric ])
163
180
164
181
# Read output from kani list and std-analysis.sh, then compare their outputs to compute Kani-specific metrics
165
182
# and write the results to {self.metrics_file}
@@ -179,19 +196,21 @@ def compute_metrics(self, kani_list_filepath):
179
196
unsafe_fns_under_contract += 1
180
197
if has_harnesses :
181
198
verified_unsafe_fns_under_contract += 1
182
- elif func_under_contract in generic_metrics .safe_abstractions :
199
+ if func_under_contract in generic_metrics .safe_abstractions :
183
200
safe_abstractions_under_contract += 1
184
201
if has_harnesses :
185
202
verified_safe_abstractions_under_contract += 1
186
- else :
203
+ if func_under_contract in generic_metrics . safe_fns :
187
204
safe_fns_under_contract += 1
188
205
if has_harnesses :
189
206
verified_safe_fns_under_contract += 1
190
207
208
+ # Keep the keys here in sync with unsafe_metrics, safe_metrics, and safe_abstr_metrics
191
209
data = {
192
210
"date" : self .date ,
193
211
"total_unsafe_fns" : generic_metrics .unsafe_fns_count ,
194
212
"total_safe_abstractions" : generic_metrics .safe_abstractions_count ,
213
+ "total_safe_fns" : generic_metrics .safe_fns_count ,
195
214
"unsafe_fns_under_contract" : unsafe_fns_under_contract ,
196
215
"verified_unsafe_fns_under_contract" : verified_unsafe_fns_under_contract ,
197
216
"safe_abstractions_under_contract" : safe_abstractions_under_contract ,
@@ -252,8 +271,9 @@ def plot_single(self, data, title, outfile):
252
271
print (f"PNG graph generated: { outfile } " )
253
272
254
273
def plot (self ):
255
- self .plot_single (self .unsafe_plot_data , title = "Contracts on Unsafe Functions in core" , outfile = "core_unsafe_std_lib_metrics.png" )
256
- self .plot_single (self .safe_abstr_plot_data , title = "Contracts on Safe Abstractions in core" , outfile = "core_safe_abstractions_std_lib_metrics.png" )
274
+ self .plot_single (self .unsafe_plot_data , title = "Contracts on Unsafe Functions in core" , outfile = "core_unsafe_metrics.png" )
275
+ self .plot_single (self .safe_abstr_plot_data , title = "Contracts on Safe Abstractions in core" , outfile = "core_safe_abstractions_metrics.png" )
276
+ self .plot_single (self .safe_plot_data , title = "Contracts on Safe Functions in core" , outfile = "core_safe_metrics.png" )
257
277
258
278
def main ():
259
279
parser = argparse .ArgumentParser (description = "Generate metrics about Kani's application to the standard library." )
0 commit comments