Source file data_labels.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
let = "# luncov-updated coverage data\n\
# id, status, tag, origin_loc, current_loc, emitter, drivers, exec_time\n";
type status = Unknown | Covered | Uncoverable
type id = int
type label = {
mutable status: status;
mutable tag: string;
mutable origin_loc: string;
mutable current_loc : string;
mutable emitter: string;
drivers: string;
mutable exec_time : float;
mutable extra : string list;
}
type t = (id, label) Hashtbl.t
let status_of_string str =
if str = "unknown" then Unknown
else if str = "covered" then Covered
else if str = "uncoverable" then Uncoverable
else if str = "unreachable" then Uncoverable
else invalid_arg "status_of_string"
let string_of_status s =
match s with
| Unknown -> "unknown"
| Covered -> "covered"
| Uncoverable -> "uncoverable"
let string_of_statusAT s =
match s with
| Unknown -> "unknown"
| Covered -> "covered"
| Uncoverable -> "always true"
let pp_status formatter status =
Format.pp_print_string formatter (if !Instrument_label.at=Cil_types.Req then string_of_status status else string_of_statusAT status)
let create ?(size=100) () = Hashtbl.create size
let size = Hashtbl.length
let input_line_opt input =
try
Some (input_line input)
with End_of_file ->
None
let load_add data idstr statusstr tag origin_loc current_loc emitter drivers exec_time replace line =
try
let id = int_of_string idstr in
let status = status_of_string statusstr in
if replace then
Hashtbl.replace data id {status; tag; origin_loc; current_loc; emitter; drivers; exec_time; extra}
else if not (Hashtbl.mem data id) then
Hashtbl.add data id {status; tag; origin_loc; current_loc; emitter; drivers; exec_time; extra}
else
Options.warning "duplicate id (row ignored) at line %d in .labels file" line
with Invalid_argument _ ->
Options.warning "incorrect id (%s) or status (%s) at line %d in .labels" idstr statusstr line
let rec load_stream replace linenum input data =
match input_line_opt input with
| None -> ()
| Some line ->
if line.[0] <> '#' && String.length line > 0 then begin
let fields = Str.split_delim (Str.regexp "[ \t]*,[ \t]*") line in
match fields with
| [] | _::[] ->
Options.warning "not enough fields at line %d in .labels file" linenum
| idstr :: statusstr :: tag :: origin_loc :: current_loc :: emitter :: drivers ::exec_time :: ->
load_add data idstr statusstr tag origin_loc current_loc emitter drivers (float_of_string exec_time) extra replace linenum
| idstr :: statusstr :: tag :: origin_loc :: current_loc :: emitter :: drivers :: ->
load_add data idstr statusstr tag origin_loc current_loc emitter drivers 0.0 extra replace linenum
| idstr :: statusstr :: tag :: origin_loc :: current_loc :: emitter :: ->
load_add data idstr statusstr tag origin_loc current_loc emitter "" 0.0 extra replace linenum
| idstr :: statusstr :: tag :: origin_loc :: current_loc :: ->
load_add data idstr statusstr tag origin_loc current_loc "" "" 0.0 extra replace linenum
| idstr :: statusstr :: tag :: origin_loc :: [] ->
load_add data idstr statusstr tag origin_loc "" "" "" 0.0 [] replace linenum
| idstr :: statusstr :: tag :: [] ->
load_add data idstr statusstr tag "" "" "" "" 0.0 [] replace linenum
| idstr :: statusstr :: [] ->
load_add data idstr statusstr "" "" "" "" "" 0.0 [] replace linenum
end;
load_stream replace (linenum+1) input data
let load data ?(replace=false) filepath =
let input = open_in filepath in
load_stream replace 1 input data;
close_in input
let store data filepath =
if Options.Backup.get () then Commons.backup filepath;
let output = open_out filepath in
let f id l acc =
let drivers = if l.status = Covered then l.drivers else "" in
(id, (String.concat ", " (string_of_int id :: string_of_status l.status :: l.tag
:: l.origin_loc :: l.current_loc :: l.emitter :: drivers
:: (string_of_float l.exec_time) :: l.extra ))) :: acc
in
let l = Hashtbl.fold f data [] in
let l = List.sort compare l in
output_string output data_header;
List.iter (fun (_,line)-> output_string output line; output_char output '\n') l;
close_out output
let storeAT data filepath =
if Options.Backup.get () then Commons.backup filepath;
let output = open_out filepath in
let f id l acc =
let drivers = if l.status = Covered then l.drivers else "" in
(id, (String.concat ", " (string_of_int id :: string_of_statusAT l.status :: l.tag
:: l.origin_loc :: l.current_loc :: l.emitter :: drivers
:: (string_of_float l.exec_time) :: l.extra ))) :: acc
in
let l = Hashtbl.fold f data [] in
let l = List.sort compare l in
output_string output data_header;
List.iter (fun (_,line)-> output_string output line; output_char output '\n') l;
close_out output
let merge_status ?(force=false) old_status new_status =
match old_status,new_status with
| Covered, Uncoverable ->
Options.warning "discrepency detected (covered detected as uncoverable)";
if force then new_status else old_status
| Covered, Unknown ->
old_status
| Uncoverable, Unknown ->
Options.warning "loss of precision detected";
if force then new_status else old_status
| _, _ ->
new_status
let merge_tag ?(force=false) old_tag new_tag =
if old_tag = "" || force then new_tag
else old_tag
let merge_loc = merge_tag
let ?(force=false) =
if old_extra = [] || force then new_extra
else old_extra
let merge_status_info ?(force=false) label status emitter time =
let new_status = merge_status ~force label.status status in
if force || new_status <> label.status then
begin
label.emitter <- emitter;
label.status <- new_status;
Option.iter (fun time ->
if Options.Time.get () then
label.exec_time <- time
else
label.exec_time <- 0.
) time
end
else if label.emitter = "" || label.exec_time = 0.0 then
begin
label.emitter <- emitter;
Option.iter (fun time ->
if Options.Time.get () then
label.exec_time <- time
else
label.exec_time <- 0.
) time
end
let update_status ?(force=false) label status emitter time =
match status, emitter with
| Some status, None ->
Options.warning "status updated without emitter";
merge_status_info ~force label status "anonymous" time
| Some status, Some emitter ->
Options.debug ~level:3 "update label: %a from %s with force=%b"
pp_status status emitter force;
merge_status_info ~force label status emitter time
| _, _ ->
()
let default () =
{ status = Unknown; tag = ""; origin_loc = ""; current_loc = ""; emitter = ""; drivers = ""; exec_time = 0.0; extra = [] }
let update data ?(force=false) ?status ?tag ?origin_loc ?current_loc ?emitter ?exec_time ? id =
let label =
if Hashtbl.mem data id then
Hashtbl.find data id
else
let l = default () in
Hashtbl.add data id l;
l
in
update_status ~force label status emitter exec_time;
Option.iter (fun tag -> label.tag <- merge_tag ~force label.tag tag) tag;
Option.iter (fun loc -> label.origin_loc <- merge_loc ~force label.origin_loc loc) origin_loc;
Option.iter (fun loc -> label.current_loc <- merge_loc ~force label.current_loc loc) current_loc;
Option.iter (fun -> label.extra <- merge_extra ~force label.extra extra) extra
let is_unknown data id =
not (Hashtbl.mem data id) || (Hashtbl.find data id).status = Unknown
let is_uncoverable data id =
(Hashtbl.mem data id) && (Hashtbl.find data id).status = Uncoverable
let get_status data id =
(Hashtbl.find data id).status
let get_emitter data id =
(Hashtbl.find data id).emitter
let get_exec_time data id =
(Hashtbl.find data id).exec_time
module S = Datatype.Int.Set
let get_label_ids data =
S.elements (Hashtbl.fold (fun k _ acc -> S.add k acc) data S.empty)
type stats = {
total: int;
unknown : int;
covered : int;
uncoverable: int;
}
let get_stats data =
let total = ref 0 in
let unknown = ref 0 in
let covered = ref 0 in
let uncoverable = ref 0 in
let incr_counter = function
| Unknown -> incr unknown
| Covered -> incr covered
| Uncoverable -> incr uncoverable
in
Hashtbl.iter (fun _ li -> incr_counter li.status; incr total) data;
let total = !total in
let unknown = !unknown in
let covered = !covered in
let uncoverable = !uncoverable in
{ total; unknown; covered; uncoverable }
let coverage_ratio stats =
let maybe_coverable = stats.total - stats.uncoverable in
if maybe_coverable > 0 then
Some (float_of_int stats.covered /. float_of_int maybe_coverable)
else
None
let pp_stats f stats =
Format.fprintf f "total number of labels %8d@." stats.total;
Format.fprintf f "number of covered %8d@." stats.covered;
Format.fprintf f "number of uncoverable %8d@." stats.uncoverable;
Format.fprintf f "number of unknown %8d@." stats.unknown;
let pcov rat =
Format.fprintf f "coverage ratio %8.2f%% \
(covered over maybe coverable)@."
(100.0 *. rat)
in
Option.iter pcov (coverage_ratio stats)
let pp_diff_stats f (before,after) =
let pp_diff f n = if n <> 0 then Format.fprintf f " (%+d)" n in
Format.fprintf f "total number of labels %8d%a@." after.total
pp_diff (after.total-before.total);
Format.fprintf f "number of covered %8d%a@." after.covered
pp_diff (after.covered-before.covered);
Format.fprintf f "number of uncoverable %8d%a@." after.uncoverable
pp_diff (after.uncoverable-before.uncoverable);
Format.fprintf f "number of unknown %8d%a@." after.unknown
pp_diff (after.unknown-before.unknown);
match coverage_ratio before, coverage_ratio after with
| Some before_rat, Some after_rat ->
Format.fprintf f "coverage ratio %8.2f%% \
(was %.2f%%)@."
(100.0 *. after_rat) (100.0 *. before_rat)
| None, Some after_rat ->
Format.fprintf f "coverage ratio %8.2f%% \
(covered over maybe coverable)@."
(100.0 *. after_rat)
| _ -> ()
let clear data =
Hashtbl.clear data