OLD | NEW |
1 #!/usr/bin/perl -w | 1 #!/usr/bin/perl -w |
2 # | 2 # |
3 # Copyright (c) International Business Machines Corp., 2002,2007 | 3 # Copyright (c) International Business Machines Corp., 2002,2012 |
4 # | 4 # |
5 # This program is free software; you can redistribute it and/or modify | 5 # This program is free software; you can redistribute it and/or modify |
6 # it under the terms of the GNU General Public License as published by | 6 # it under the terms of the GNU General Public License as published by |
7 # the Free Software Foundation; either version 2 of the License, or (at | 7 # the Free Software Foundation; either version 2 of the License, or (at |
8 # your option) any later version. | 8 # your option) any later version. |
9 # | 9 # |
10 # This program is distributed in the hope that it will be useful, but | 10 # This program is distributed in the hope that it will be useful, but |
11 # WITHOUT ANY WARRANTY; without even the implied warranty of | 11 # WITHOUT ANY WARRANTY; without even the implied warranty of |
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 # General Public License for more details. | 13 # General Public License for more details. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 # 2003-12-11 / Laurent Deniel: added --follow option | 53 # 2003-12-11 / Laurent Deniel: added --follow option |
54 # 2004-03-29 / Peter Oberparleiter: modified --diff option to better cope with | 54 # 2004-03-29 / Peter Oberparleiter: modified --diff option to better cope with |
55 # ambiguous patch file entries, modified --capture option to use | 55 # ambiguous patch file entries, modified --capture option to use |
56 # modprobe before insmod (needed for 2.6) | 56 # modprobe before insmod (needed for 2.6) |
57 # 2004-03-30 / Peter Oberparleiter: added --path option | 57 # 2004-03-30 / Peter Oberparleiter: added --path option |
58 # 2004-08-09 / Peter Oberparleiter: added configuration file support | 58 # 2004-08-09 / Peter Oberparleiter: added configuration file support |
59 # 2008-08-13 / Peter Oberparleiter: added function coverage support | 59 # 2008-08-13 / Peter Oberparleiter: added function coverage support |
60 # | 60 # |
61 | 61 |
62 use strict; | 62 use strict; |
63 use File::Basename; | 63 use File::Basename; |
| 64 use File::Path; |
| 65 use File::Find; |
| 66 use File::Temp qw /tempdir/; |
| 67 use File::Spec::Functions qw /abs2rel canonpath catdir catfile catpath |
| 68 » » » file_name_is_absolute rootdir splitdir splitpath/; |
64 use Getopt::Long; | 69 use Getopt::Long; |
| 70 use Cwd qw /abs_path getcwd/; |
65 | 71 |
66 | 72 |
67 # Global constants | 73 # Global constants |
68 our $lcov_version» = "LCOV version 1.7"; | 74 our $lcov_version» = 'LCOV version 1.10'; |
69 our $lcov_url = "http://ltp.sourceforge.net/coverage/lcov.php"; | 75 our $lcov_url = "http://ltp.sourceforge.net/coverage/lcov.php"; |
70 our $tool_name = basename($0); | 76 our $tool_name = basename($0); |
71 | 77 |
72 # Names of the GCOV kernel module | |
73 our @gcovmod = ("gcov-prof", "gcov-proc"); | |
74 | |
75 # Directory containing gcov kernel files | 78 # Directory containing gcov kernel files |
76 our $gcov_dir = "/proc/gcov"; | 79 our $gcov_dir; |
77 | |
78 # The location of the insmod tool | |
79 our $insmod_tool» = "/sbin/insmod"; | |
80 | |
81 # The location of the modprobe tool | |
82 our $modprobe_tool» = "/sbin/modprobe"; | |
83 | |
84 # The location of the rmmod tool | |
85 our $rmmod_tool»» = "/sbin/rmmod"; | |
86 | 80 |
87 # Where to create temporary directories | 81 # Where to create temporary directories |
88 our $tmp_dir» » = "/tmp"; | 82 our $tmp_dir; |
89 | 83 |
90 # How to prefix a temporary directory name | 84 # Internal constants |
91 our $tmp_prefix»» = "tmpdir"; | 85 our $GKV_PROC = 0;» # gcov-kernel data in /proc via external patch |
| 86 our $GKV_SYS = 1;» # gcov-kernel data in /sys via vanilla 2.6.31+ |
| 87 our @GKV_NAME = ( "external", "upstream" ); |
| 88 our $pkg_gkv_file = ".gcov_kernel_version"; |
| 89 our $pkg_build_file = ".build_directory"; |
92 | 90 |
| 91 our $BR_BLOCK = 0; |
| 92 our $BR_BRANCH = 1; |
| 93 our $BR_TAKEN = 2; |
| 94 our $BR_VEC_ENTRIES = 3; |
| 95 our $BR_VEC_WIDTH = 32; |
| 96 |
| 97 # Branch data combination types |
| 98 our $BR_SUB = 0; |
| 99 our $BR_ADD = 1; |
93 | 100 |
94 # Prototypes | 101 # Prototypes |
95 sub print_usage(*); | 102 sub print_usage(*); |
96 sub check_options(); | 103 sub check_options(); |
97 sub userspace_reset(); | 104 sub userspace_reset(); |
98 sub userspace_capture(); | 105 sub userspace_capture(); |
99 sub kernel_reset(); | 106 sub kernel_reset(); |
100 sub kernel_capture(); | 107 sub kernel_capture(); |
| 108 sub kernel_capture_initial(); |
| 109 sub package_capture(); |
101 sub add_traces(); | 110 sub add_traces(); |
102 sub read_info_file($); | 111 sub read_info_file($); |
103 sub get_info_entry($); | 112 sub get_info_entry($); |
104 sub set_info_entry($$$$$$$;$$$$); | 113 sub set_info_entry($$$$$$$$$;$$$$$$); |
105 sub add_counts($$); | 114 sub add_counts($$); |
106 sub merge_checksums($$$); | 115 sub merge_checksums($$$); |
107 sub combine_info_entries($$$); | 116 sub combine_info_entries($$$); |
108 sub combine_info_files($$); | 117 sub combine_info_files($$); |
109 sub write_info_file(*$); | 118 sub write_info_file(*$); |
110 sub extract(); | 119 sub extract(); |
111 sub remove(); | 120 sub remove(); |
112 sub list(); | 121 sub list(); |
113 sub get_common_filename($$); | 122 sub get_common_filename($$); |
114 sub read_diff($); | 123 sub read_diff($); |
115 sub diff(); | 124 sub diff(); |
116 sub system_no_output($@); | 125 sub system_no_output($@); |
117 sub read_config($); | 126 sub read_config($); |
118 sub apply_config($); | 127 sub apply_config($); |
119 sub info(@); | 128 sub info(@); |
120 sub unload_module($); | |
121 sub check_and_load_kernel_module(); | |
122 sub create_temp_dir(); | 129 sub create_temp_dir(); |
123 sub transform_pattern($); | 130 sub transform_pattern($); |
124 sub warn_handler($); | 131 sub warn_handler($); |
125 sub die_handler($); | 132 sub die_handler($); |
126 | 133 sub abort_handler($); |
| 134 sub temp_cleanup(); |
| 135 sub setup_gkv(); |
| 136 sub get_overall_line($$$$); |
| 137 sub print_overall_rate($$$$$$$$$); |
| 138 sub lcov_geninfo(@); |
| 139 sub create_package($$$;$); |
| 140 sub get_func_found_and_hit($); |
| 141 sub br_ivec_get($$); |
| 142 sub summary(); |
| 143 sub rate($$;$$$); |
127 | 144 |
128 # Global variables & initialization | 145 # Global variables & initialization |
129 our @directory; # Specifies where to get coverage data from | 146 our @directory; # Specifies where to get coverage data from |
130 our @kernel_directory; # If set, captures only from specified kernel subdirs | 147 our @kernel_directory; # If set, captures only from specified kernel subdirs |
131 our @add_tracefile; # If set, reads in and combines all files in list | 148 our @add_tracefile; # If set, reads in and combines all files in list |
132 our $list; # If set, list contents of tracefile | 149 our $list; # If set, list contents of tracefile |
133 our $extract; # If set, extracts parts of tracefile | 150 our $extract; # If set, extracts parts of tracefile |
134 our $remove; # If set, removes parts of tracefile | 151 our $remove; # If set, removes parts of tracefile |
135 our $diff; # If set, modifies tracefile according to diff | 152 our $diff; # If set, modifies tracefile according to diff |
136 our $reset; # If set, reset all coverage data to zero | 153 our $reset; # If set, reset all coverage data to zero |
137 our $capture; # If set, capture data | 154 our $capture; # If set, capture data |
138 our $output_filename; # Name for file to write coverage data to | 155 our $output_filename; # Name for file to write coverage data to |
139 our $test_name = ""; # Test case name | 156 our $test_name = ""; # Test case name |
140 our $quiet = ""; # If set, suppress information messages | 157 our $quiet = ""; # If set, suppress information messages |
141 our $help; # Help option flag | 158 our $help; # Help option flag |
142 our $version; # Version option flag | 159 our $version; # Version option flag |
143 our $convert_filenames; # If set, convert filenames when applying diff | 160 our $convert_filenames; # If set, convert filenames when applying diff |
144 our $strip; # If set, strip leading directories when applying diff | 161 our $strip; # If set, strip leading directories when applying diff |
145 our $need_unload; # If set, unload gcov kernel module | |
146 our $temp_dir_name; # Name of temporary directory | 162 our $temp_dir_name; # Name of temporary directory |
147 our $cwd = `pwd`; # Current working directory | 163 our $cwd = `pwd`; # Current working directory |
148 our $to_file; # If set, indicates that output is written to a file | 164 our $to_file; # If set, indicates that output is written to a file |
149 our $follow; # If set, indicates that find shall follow links | 165 our $follow; # If set, indicates that find shall follow links |
150 our $diff_path = ""; # Path removed from tracefile when applying diff | 166 our $diff_path = ""; # Path removed from tracefile when applying diff |
151 our $base_directory; # Base directory (cwd of gcc during compilation) | 167 our $base_directory; # Base directory (cwd of gcc during compilation) |
152 our $checksum; # If set, calculate a checksum for each line | 168 our $checksum; # If set, calculate a checksum for each line |
153 our $no_checksum; # If set, don't calculate a checksum for each line | 169 our $no_checksum; # If set, don't calculate a checksum for each line |
154 our $compat_libtool; # If set, indicates that libtool mode is to be enabled | 170 our $compat_libtool; # If set, indicates that libtool mode is to be enabled |
155 our $no_compat_libtool; # If set, indicates that libtool mode is to be disabled | 171 our $no_compat_libtool; # If set, indicates that libtool mode is to be disabled |
156 our $gcov_tool; | 172 our $gcov_tool; |
157 our $ignore_errors; | 173 our @opt_ignore_errors; |
158 our $initial; | 174 our $initial; |
159 our $no_recursion = 0; | 175 our $no_recursion = 0; |
| 176 our $to_package; |
| 177 our $from_package; |
160 our $maxdepth; | 178 our $maxdepth; |
| 179 our $no_markers; |
161 our $config; # Configuration file contents | 180 our $config; # Configuration file contents |
162 chomp($cwd); | 181 chomp($cwd); |
163 our $tool_dir = dirname($0); # Directory where genhtml tool is installed | 182 our $tool_dir = dirname($0); # Directory where genhtml tool is installed |
| 183 our @temp_dirs; |
| 184 our $gcov_gkv; # gcov kernel support version found on machine |
| 185 our $opt_derive_func_data; |
| 186 our $opt_debug; |
| 187 our $opt_list_full_path; |
| 188 our $opt_no_list_full_path; |
| 189 our $opt_list_width = 80; |
| 190 our $opt_list_truncate_max = 20; |
| 191 our $opt_external; |
| 192 our $opt_no_external; |
| 193 our $opt_config_file; |
| 194 our %opt_rc; |
| 195 our @opt_summary; |
| 196 our $opt_compat; |
| 197 our $ln_overall_found; |
| 198 our $ln_overall_hit; |
| 199 our $fn_overall_found; |
| 200 our $fn_overall_hit; |
| 201 our $br_overall_found; |
| 202 our $br_overall_hit; |
| 203 our $func_coverage = 1; |
| 204 our $br_coverage = 0; |
164 | 205 |
165 | 206 |
166 # | 207 # |
167 # Code entry point | 208 # Code entry point |
168 # | 209 # |
169 | 210 |
170 $SIG{__WARN__} = \&warn_handler; | 211 $SIG{__WARN__} = \&warn_handler; |
171 $SIG{__DIE__} = \&die_handler; | 212 $SIG{__DIE__} = \&die_handler; |
| 213 $SIG{'INT'} = \&abort_handler; |
| 214 $SIG{'QUIT'} = \&abort_handler; |
| 215 |
| 216 # Prettify version string |
| 217 $lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/; |
172 | 218 |
173 # Add current working directory if $tool_dir is not already an absolute path | 219 # Add current working directory if $tool_dir is not already an absolute path |
174 if (! ($tool_dir =~ /^\/(.*)$/)) | 220 if (! ($tool_dir =~ /^\/(.*)$/)) |
175 { | 221 { |
176 $tool_dir = "$cwd/$tool_dir"; | 222 $tool_dir = "$cwd/$tool_dir"; |
177 } | 223 } |
178 | 224 |
| 225 # Check command line for a configuration file name |
| 226 Getopt::Long::Configure("pass_through", "no_auto_abbrev"); |
| 227 GetOptions("config-file=s" => \$opt_config_file, |
| 228 "rc=s%" => \%opt_rc); |
| 229 Getopt::Long::Configure("default"); |
| 230 |
179 # Read configuration file if available | 231 # Read configuration file if available |
180 if (-r $ENV{"HOME"}."/.lcovrc") | 232 if (defined($opt_config_file)) { |
| 233 » $config = read_config($opt_config_file); |
| 234 } elsif (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc")) |
181 { | 235 { |
182 $config = read_config($ENV{"HOME"}."/.lcovrc"); | 236 $config = read_config($ENV{"HOME"}."/.lcovrc"); |
183 } | 237 } |
184 elsif (-r "/etc/lcovrc") | 238 elsif (-r "/etc/lcovrc") |
185 { | 239 { |
186 $config = read_config("/etc/lcovrc"); | 240 $config = read_config("/etc/lcovrc"); |
187 } | 241 } |
188 | 242 |
189 if ($config) | 243 if ($config || %opt_rc) |
190 { | 244 { |
191 » # Copy configuration file values to variables | 245 » # Copy configuration file and --rc values to variables |
192 apply_config({ | 246 apply_config({ |
193 "lcov_gcov_dir" => \$gcov_dir, | 247 "lcov_gcov_dir" => \$gcov_dir, |
194 » » "lcov_insmod_tool"» => \$insmod_tool, | 248 » » "lcov_tmp_dir"» » => \$tmp_dir, |
195 » » "lcov_modprobe_tool"» => \$modprobe_tool, | 249 » » "lcov_list_full_path"» => \$opt_list_full_path, |
196 » » "lcov_rmmod_tool"» => \$rmmod_tool, | 250 » » "lcov_list_width"» => \$opt_list_width, |
197 » » "lcov_tmp_dir"» » => \$tmp_dir}); | 251 » » "lcov_list_truncate_max"=> \$opt_list_truncate_max, |
| 252 » » "lcov_branch_coverage"» => \$br_coverage, |
| 253 » » "lcov_function_coverage"=> \$func_coverage, |
| 254 » }); |
198 } | 255 } |
199 | 256 |
200 # Parse command line options | 257 # Parse command line options |
201 if (!GetOptions("directory|d|di=s" => \@directory, | 258 if (!GetOptions("directory|d|di=s" => \@directory, |
202 » » "add-tracefile=s" => \@add_tracefile, | 259 » » "add-tracefile|a=s" => \@add_tracefile, |
203 » » "list=s" => \$list, | 260 » » "list|l=s" => \$list, |
204 » » "kernel-directory=s" => \@kernel_directory, | 261 » » "kernel-directory|k=s" => \@kernel_directory, |
205 » » "extract=s" => \$extract, | 262 » » "extract|e=s" => \$extract, |
206 » » "remove=s" => \$remove, | 263 » » "remove|r=s" => \$remove, |
207 "diff=s" => \$diff, | 264 "diff=s" => \$diff, |
208 "convert-filenames" => \$convert_filenames, | 265 "convert-filenames" => \$convert_filenames, |
209 "strip=i" => \$strip, | 266 "strip=i" => \$strip, |
210 "capture|c" => \$capture, | 267 "capture|c" => \$capture, |
211 » » "output-file=s" => \$output_filename, | 268 » » "output-file|o=s" => \$output_filename, |
212 » » "test-name=s" => \$test_name, | 269 » » "test-name|t=s" => \$test_name, |
213 » » "zerocounters" => \$reset, | 270 » » "zerocounters|z" => \$reset, |
214 » » "quiet" => \$quiet, | 271 » » "quiet|q" => \$quiet, |
215 » » "help|?" => \$help, | 272 » » "help|h|?" => \$help, |
216 » » "version" => \$version, | 273 » » "version|v" => \$version, |
217 » » "follow" => \$follow, | 274 » » "follow|f" => \$follow, |
218 "path=s" => \$diff_path, | 275 "path=s" => \$diff_path, |
219 » » "base-directory=s" => \$base_directory, | 276 » » "base-directory|b=s" => \$base_directory, |
220 "checksum" => \$checksum, | 277 "checksum" => \$checksum, |
221 "no-checksum" => \$no_checksum, | 278 "no-checksum" => \$no_checksum, |
222 "compat-libtool" => \$compat_libtool, | 279 "compat-libtool" => \$compat_libtool, |
223 "no-compat-libtool" => \$no_compat_libtool, | 280 "no-compat-libtool" => \$no_compat_libtool, |
224 "gcov-tool=s" => \$gcov_tool, | 281 "gcov-tool=s" => \$gcov_tool, |
225 » » "ignore-errors=s" => \$ignore_errors, | 282 » » "ignore-errors=s" => \@opt_ignore_errors, |
226 "initial|i" => \$initial, | 283 "initial|i" => \$initial, |
227 » » "no-recursion" => \$no_recursion | 284 » » "no-recursion" => \$no_recursion, |
| 285 » » "to-package=s" => \$to_package, |
| 286 » » "from-package=s" => \$from_package, |
| 287 » » "no-markers" => \$no_markers, |
| 288 » » "derive-func-data" => \$opt_derive_func_data, |
| 289 » » "debug" => \$opt_debug, |
| 290 » » "list-full-path" => \$opt_list_full_path, |
| 291 » » "no-list-full-path" => \$opt_no_list_full_path, |
| 292 » » "external" => \$opt_external, |
| 293 » » "no-external" => \$opt_no_external, |
| 294 » » "summary=s" => \@opt_summary, |
| 295 » » "compat=s" => \$opt_compat, |
| 296 » » "config-file=s" => \$opt_config_file, |
| 297 » » "rc=s%" => \%opt_rc, |
228 )) | 298 )) |
229 { | 299 { |
230 print(STDERR "Use $tool_name --help to get usage information\n"); | 300 print(STDERR "Use $tool_name --help to get usage information\n"); |
231 exit(1); | 301 exit(1); |
232 } | 302 } |
233 else | 303 else |
234 { | 304 { |
235 # Merge options | 305 # Merge options |
236 if (defined($no_checksum)) | 306 if (defined($no_checksum)) |
237 { | 307 { |
238 $checksum = ($no_checksum ? 0 : 1); | 308 $checksum = ($no_checksum ? 0 : 1); |
239 $no_checksum = undef; | 309 $no_checksum = undef; |
240 } | 310 } |
241 | 311 |
242 if (defined($no_compat_libtool)) | 312 if (defined($no_compat_libtool)) |
243 { | 313 { |
244 $compat_libtool = ($no_compat_libtool ? 0 : 1); | 314 $compat_libtool = ($no_compat_libtool ? 0 : 1); |
245 $no_compat_libtool = undef; | 315 $no_compat_libtool = undef; |
246 } | 316 } |
| 317 |
| 318 if (defined($opt_no_list_full_path)) |
| 319 { |
| 320 $opt_list_full_path = ($opt_no_list_full_path ? 0 : 1); |
| 321 $opt_no_list_full_path = undef; |
| 322 } |
| 323 |
| 324 if (defined($opt_no_external)) { |
| 325 $opt_external = 0; |
| 326 $opt_no_external = undef; |
| 327 } |
247 } | 328 } |
248 | 329 |
249 # Check for help option | 330 # Check for help option |
250 if ($help) | 331 if ($help) |
251 { | 332 { |
252 print_usage(*STDOUT); | 333 print_usage(*STDOUT); |
253 exit(0); | 334 exit(0); |
254 } | 335 } |
255 | 336 |
256 # Check for version option | 337 # Check for version option |
257 if ($version) | 338 if ($version) |
258 { | 339 { |
259 print("$tool_name: $lcov_version\n"); | 340 print("$tool_name: $lcov_version\n"); |
260 exit(0); | 341 exit(0); |
261 } | 342 } |
262 | 343 |
| 344 # Check list width option |
| 345 if ($opt_list_width <= 40) { |
| 346 die("ERROR: lcov_list_width parameter out of range (needs to be ". |
| 347 "larger than 40)\n"); |
| 348 } |
| 349 |
263 # Normalize --path text | 350 # Normalize --path text |
264 $diff_path =~ s/\/$//; | 351 $diff_path =~ s/\/$//; |
265 | 352 |
266 if ($follow) | 353 if ($follow) |
267 { | 354 { |
268 $follow = "-follow"; | 355 $follow = "-follow"; |
269 } | 356 } |
270 else | 357 else |
271 { | 358 { |
272 $follow = ""; | 359 $follow = ""; |
273 } | 360 } |
274 | 361 |
275 if ($no_recursion) | 362 if ($no_recursion) |
276 { | 363 { |
277 $maxdepth = "-maxdepth 1"; | 364 $maxdepth = "-maxdepth 1"; |
278 } | 365 } |
279 else | 366 else |
280 { | 367 { |
281 $maxdepth = ""; | 368 $maxdepth = ""; |
282 } | 369 } |
283 | 370 |
284 # Check for valid options | 371 # Check for valid options |
285 check_options(); | 372 check_options(); |
286 | 373 |
287 # Only --extract, --remove and --diff allow unnamed parameters | 374 # Only --extract, --remove and --diff allow unnamed parameters |
288 if (@ARGV && !($extract || $remove || $diff)) | 375 if (@ARGV && !($extract || $remove || $diff || @opt_summary)) |
289 { | 376 { |
290 » die("Extra parameter found\n". | 377 » die("Extra parameter found: '".join(" ", @ARGV)."'\n". |
291 "Use $tool_name --help to get usage information\n"); | 378 "Use $tool_name --help to get usage information\n"); |
292 } | 379 } |
293 | 380 |
294 # Check for output filename | 381 # Check for output filename |
295 $to_file = ($output_filename && ($output_filename ne "-")); | 382 $to_file = ($output_filename && ($output_filename ne "-")); |
296 | 383 |
297 if ($capture) | 384 if ($capture) |
298 { | 385 { |
299 if (!$to_file) | 386 if (!$to_file) |
300 { | 387 { |
301 # Option that tells geninfo to write to stdout | 388 # Option that tells geninfo to write to stdout |
302 $output_filename = "-"; | 389 $output_filename = "-"; |
303 } | 390 } |
304 } | 391 } |
305 else | 392 |
306 { | 393 # Determine kernel directory for gcov data |
307 » if ($initial) | 394 if (!$from_package && !@directory && ($capture || $reset)) { |
308 » { | 395 » ($gcov_gkv, $gcov_dir) = setup_gkv(); |
309 » » die("Option --initial is only valid when capturing data (-c)\n". | |
310 » » "Use $tool_name --help to get usage information\n"); | |
311 » } | |
312 } | 396 } |
313 | 397 |
314 # Check for requested functionality | 398 # Check for requested functionality |
315 if ($reset) | 399 if ($reset) |
316 { | 400 { |
317 # Differentiate between user space and kernel reset | 401 # Differentiate between user space and kernel reset |
318 if (@directory) | 402 if (@directory) |
319 { | 403 { |
320 userspace_reset(); | 404 userspace_reset(); |
321 } | 405 } |
322 else | 406 else |
323 { | 407 { |
324 kernel_reset(); | 408 kernel_reset(); |
325 } | 409 } |
326 } | 410 } |
327 elsif ($capture) | 411 elsif ($capture) |
328 { | 412 { |
329 » # Differentiate between user space and kernel | 413 » # Capture source can be user space, kernel or package |
330 » if (@directory) | 414 » if ($from_package) { |
331 » { | 415 » » package_capture(); |
| 416 » } elsif (@directory) { |
332 userspace_capture(); | 417 userspace_capture(); |
333 » } | 418 » } else { |
334 » else | 419 » » if ($initial) { |
335 » { | 420 » » » if (defined($to_package)) { |
336 » » kernel_capture(); | 421 » » » » die("ERROR: --initial cannot be used together ". |
| 422 » » » » "with --to-package\n"); |
| 423 » » » } |
| 424 » » » kernel_capture_initial(); |
| 425 » » } else { |
| 426 » » » kernel_capture(); |
| 427 » » } |
337 } | 428 } |
338 } | 429 } |
339 elsif (@add_tracefile) | 430 elsif (@add_tracefile) |
340 { | 431 { |
341 » add_traces(); | 432 » ($ln_overall_found, $ln_overall_hit, |
| 433 » $fn_overall_found, $fn_overall_hit, |
| 434 » $br_overall_found, $br_overall_hit) = add_traces(); |
342 } | 435 } |
343 elsif ($remove) | 436 elsif ($remove) |
344 { | 437 { |
345 » remove(); | 438 » ($ln_overall_found, $ln_overall_hit, |
| 439 » $fn_overall_found, $fn_overall_hit, |
| 440 » $br_overall_found, $br_overall_hit) = remove(); |
346 } | 441 } |
347 elsif ($extract) | 442 elsif ($extract) |
348 { | 443 { |
349 » extract(); | 444 » ($ln_overall_found, $ln_overall_hit, |
| 445 » $fn_overall_found, $fn_overall_hit, |
| 446 » $br_overall_found, $br_overall_hit) = extract(); |
350 } | 447 } |
351 elsif ($list) | 448 elsif ($list) |
352 { | 449 { |
353 list(); | 450 list(); |
354 } | 451 } |
355 elsif ($diff) | 452 elsif ($diff) |
356 { | 453 { |
357 if (scalar(@ARGV) != 1) | 454 if (scalar(@ARGV) != 1) |
358 { | 455 { |
359 die("ERROR: option --diff requires one additional argument!\n". | 456 die("ERROR: option --diff requires one additional argument!\n". |
360 "Use $tool_name --help to get usage information\n"); | 457 "Use $tool_name --help to get usage information\n"); |
361 } | 458 } |
362 » diff(); | 459 » ($ln_overall_found, $ln_overall_hit, |
| 460 » $fn_overall_found, $fn_overall_hit, |
| 461 » $br_overall_found, $br_overall_hit) = diff(); |
| 462 } |
| 463 elsif (@opt_summary) |
| 464 { |
| 465 » ($ln_overall_found, $ln_overall_hit, |
| 466 » $fn_overall_found, $fn_overall_hit, |
| 467 » $br_overall_found, $br_overall_hit) = summary(); |
363 } | 468 } |
364 | 469 |
365 info("Done.\n"); | 470 temp_cleanup(); |
| 471 |
| 472 if (defined($ln_overall_found)) { |
| 473 » print_overall_rate(1, $ln_overall_found, $ln_overall_hit, |
| 474 » » » 1, $fn_overall_found, $fn_overall_hit, |
| 475 » » » 1, $br_overall_found, $br_overall_hit); |
| 476 } else { |
| 477 » info("Done.\n") if (!$list && !$capture); |
| 478 } |
366 exit(0); | 479 exit(0); |
367 | 480 |
368 # | 481 # |
369 # print_usage(handle) | 482 # print_usage(handle) |
370 # | 483 # |
371 # Print usage information. | 484 # Print usage information. |
372 # | 485 # |
373 | 486 |
374 sub print_usage(*) | 487 sub print_usage(*) |
375 { | 488 { |
(...skipping 12 matching lines...) Expand all Loading... |
388 -q, --quiet Do not print progress messages | 501 -q, --quiet Do not print progress messages |
389 | 502 |
390 Operation: | 503 Operation: |
391 -z, --zerocounters Reset all execution counts to zero | 504 -z, --zerocounters Reset all execution counts to zero |
392 -c, --capture Capture coverage data | 505 -c, --capture Capture coverage data |
393 -a, --add-tracefile FILE Add contents of tracefiles | 506 -a, --add-tracefile FILE Add contents of tracefiles |
394 -e, --extract FILE PATTERN Extract files matching PATTERN from FILE | 507 -e, --extract FILE PATTERN Extract files matching PATTERN from FILE |
395 -r, --remove FILE PATTERN Remove files matching PATTERN from FILE | 508 -r, --remove FILE PATTERN Remove files matching PATTERN from FILE |
396 -l, --list FILE List contents of tracefile FILE | 509 -l, --list FILE List contents of tracefile FILE |
397 --diff FILE DIFF Transform tracefile FILE according to DIFF | 510 --diff FILE DIFF Transform tracefile FILE according to DIFF |
| 511 --summary FILE Show summary coverage data for tracefiles |
398 | 512 |
399 Options: | 513 Options: |
400 -i, --initial Capture initial zero coverage data | 514 -i, --initial Capture initial zero coverage data |
401 -t, --test-name NAME Specify test name to be stored with data | 515 -t, --test-name NAME Specify test name to be stored with data |
402 -o, --output-file FILENAME Write data to FILENAME instead of stdout | 516 -o, --output-file FILENAME Write data to FILENAME instead of stdout |
403 -d, --directory DIR Use .da files in DIR instead of kernel | 517 -d, --directory DIR Use .da files in DIR instead of kernel |
404 -f, --follow Follow links when searching .da files | 518 -f, --follow Follow links when searching .da files |
405 -k, --kernel-directory KDIR Capture kernel coverage data only from KDIR | 519 -k, --kernel-directory KDIR Capture kernel coverage data only from KDIR |
406 -b, --base-directory DIR Use DIR as base directory for relative paths | 520 -b, --base-directory DIR Use DIR as base directory for relative paths |
407 --convert-filenames Convert filenames when applying diff | 521 --convert-filenames Convert filenames when applying diff |
408 --strip DEPTH Strip initial DEPTH directory levels in diff | 522 --strip DEPTH Strip initial DEPTH directory levels in diff |
409 --path PATH Strip PATH from tracefile when applying diff | 523 --path PATH Strip PATH from tracefile when applying diff |
410 --(no-)checksum Enable (disable) line checksumming | 524 --(no-)checksum Enable (disable) line checksumming |
411 --(no-)compat-libtool Enable (disable) libtool compatibility mode | 525 --(no-)compat-libtool Enable (disable) libtool compatibility mode |
412 --gcov-tool TOOL Specify gcov tool location | 526 --gcov-tool TOOL Specify gcov tool location |
413 --ignore-errors ERRORS Continue after ERRORS (gcov, source) | 527 --ignore-errors ERRORS Continue after ERRORS (gcov, source, graph) |
414 --no-recursion Exlude subdirectories from processing | 528 --no-recursion Exclude subdirectories from processing |
| 529 --to-package FILENAME Store unprocessed coverage data in FILENAME |
| 530 --from-package FILENAME Capture from unprocessed data in FILENAME |
| 531 --no-markers Ignore exclusion markers in source code |
| 532 --derive-func-data Generate function data from line data |
| 533 --list-full-path Print full path during a list operation |
| 534 --(no-)external Include (ignore) data for external files |
| 535 --config-file FILENAME Specify configuration file location |
| 536 --rc SETTING=VALUE Override configuration file setting |
| 537 --compat MODE=on|off|auto Set compat MODE (libtool, hammer, split_crc) |
415 | 538 |
416 For more information see: $lcov_url | 539 For more information see: $lcov_url |
417 END_OF_USAGE | 540 END_OF_USAGE |
418 ; | 541 ; |
419 } | 542 } |
420 | 543 |
421 | 544 |
422 # | 545 # |
423 # check_options() | 546 # check_options() |
424 # | 547 # |
425 # Check for valid combination of command line options. Die on error. | 548 # Check for valid combination of command line options. Die on error. |
426 # | 549 # |
427 | 550 |
428 sub check_options() | 551 sub check_options() |
429 { | 552 { |
430 my $i = 0; | 553 my $i = 0; |
431 | 554 |
432 # Count occurrence of mutually exclusive options | 555 # Count occurrence of mutually exclusive options |
433 $reset && $i++; | 556 $reset && $i++; |
434 $capture && $i++; | 557 $capture && $i++; |
435 @add_tracefile && $i++; | 558 @add_tracefile && $i++; |
436 $extract && $i++; | 559 $extract && $i++; |
437 $remove && $i++; | 560 $remove && $i++; |
438 $list && $i++; | 561 $list && $i++; |
439 $diff && $i++; | 562 $diff && $i++; |
| 563 @opt_summary && $i++; |
440 | 564 |
441 if ($i == 0) | 565 if ($i == 0) |
442 { | 566 { |
443 » » die("Need one of the options -z, -c, -a, -e, -r, -l or ". | 567 » » die("Need one of options -z, -c, -a, -e, -r, -l, ". |
444 » » "--diff\n". | 568 » » "--diff or --summary\n". |
445 "Use $tool_name --help to get usage information\n"); | 569 "Use $tool_name --help to get usage information\n"); |
446 } | 570 } |
447 elsif ($i > 1) | 571 elsif ($i > 1) |
448 { | 572 { |
449 » » die("ERROR: only one of -z, -c, -a, -e, -r, -l or ". | 573 » » die("ERROR: only one of -z, -c, -a, -e, -r, -l, ". |
450 » » "--diff allowed!\n". | 574 » » "--diff or --summary allowed!\n". |
451 "Use $tool_name --help to get usage information\n"); | 575 "Use $tool_name --help to get usage information\n"); |
452 } | 576 } |
453 } | 577 } |
454 | 578 |
455 | 579 |
456 # | 580 # |
457 # userspace_reset() | 581 # userspace_reset() |
458 # | 582 # |
459 # Reset coverage data found in DIRECTORY by deleting all contained .da files. | 583 # Reset coverage data found in DIRECTORY by deleting all contained .da files. |
460 # | 584 # |
(...skipping 15 matching lines...) Expand all Loading... |
476 { | 600 { |
477 unlink($_) or die("ERROR: cannot remove file $_!\n"); | 601 unlink($_) or die("ERROR: cannot remove file $_!\n"); |
478 } | 602 } |
479 } | 603 } |
480 } | 604 } |
481 | 605 |
482 | 606 |
483 # | 607 # |
484 # userspace_capture() | 608 # userspace_capture() |
485 # | 609 # |
486 # Capture coverage data found in DIRECTORY and write it to OUTPUT_FILENAME | 610 # Capture coverage data found in DIRECTORY and write it to a package (if |
487 # if specified, otherwise to STDOUT. | 611 # TO_PACKAGE specified) or to OUTPUT_FILENAME or STDOUT. |
488 # | 612 # |
489 # Die on error. | 613 # Die on error. |
490 # | 614 # |
491 | 615 |
492 sub userspace_capture() | 616 sub userspace_capture() |
493 { | 617 { |
| 618 my $dir; |
| 619 my $build; |
| 620 |
| 621 if (!defined($to_package)) { |
| 622 lcov_geninfo(@directory); |
| 623 return; |
| 624 } |
| 625 if (scalar(@directory) != 1) { |
| 626 die("ERROR: -d may be specified only once with --to-package\n"); |
| 627 } |
| 628 $dir = $directory[0]; |
| 629 if (defined($base_directory)) { |
| 630 $build = $base_directory; |
| 631 } else { |
| 632 $build = $dir; |
| 633 } |
| 634 create_package($to_package, $dir, $build); |
| 635 } |
| 636 |
| 637 |
| 638 # |
| 639 # kernel_reset() |
| 640 # |
| 641 # Reset kernel coverage. |
| 642 # |
| 643 # Die on error. |
| 644 # |
| 645 |
| 646 sub kernel_reset() |
| 647 { |
| 648 local *HANDLE; |
| 649 my $reset_file; |
| 650 |
| 651 info("Resetting kernel execution counters\n"); |
| 652 if (-e "$gcov_dir/vmlinux") { |
| 653 $reset_file = "$gcov_dir/vmlinux"; |
| 654 } elsif (-e "$gcov_dir/reset") { |
| 655 $reset_file = "$gcov_dir/reset"; |
| 656 } else { |
| 657 die("ERROR: no reset control found in $gcov_dir\n"); |
| 658 } |
| 659 open(HANDLE, ">", $reset_file) or |
| 660 die("ERROR: cannot write to $reset_file!\n"); |
| 661 print(HANDLE "0"); |
| 662 close(HANDLE); |
| 663 } |
| 664 |
| 665 |
| 666 # |
| 667 # lcov_copy_single(from, to) |
| 668 # |
| 669 # Copy single regular file FROM to TO without checking its size. This is |
| 670 # required to work with special files generated by the kernel |
| 671 # seq_file-interface. |
| 672 # |
| 673 # |
| 674 sub lcov_copy_single($$) |
| 675 { |
| 676 my ($from, $to) = @_; |
| 677 my $content; |
| 678 local $/; |
| 679 local *HANDLE; |
| 680 |
| 681 open(HANDLE, "<", $from) or die("ERROR: cannot read $from: $!\n"); |
| 682 $content = <HANDLE>; |
| 683 close(HANDLE); |
| 684 open(HANDLE, ">", $to) or die("ERROR: cannot write $from: $!\n"); |
| 685 if (defined($content)) { |
| 686 print(HANDLE $content); |
| 687 } |
| 688 close(HANDLE); |
| 689 } |
| 690 |
| 691 # |
| 692 # lcov_find(dir, function, data[, extension, ...)]) |
| 693 # |
| 694 # Search DIR for files and directories whose name matches PATTERN and run |
| 695 # FUNCTION for each match. If not pattern is specified, match all names. |
| 696 # |
| 697 # FUNCTION has the following prototype: |
| 698 # function(dir, relative_name, data) |
| 699 # |
| 700 # Where: |
| 701 # dir: the base directory for this search |
| 702 # relative_name: the name relative to the base directory of this entry |
| 703 # data: the DATA variable passed to lcov_find |
| 704 # |
| 705 sub lcov_find($$$;@) |
| 706 { |
| 707 my ($dir, $fn, $data, @pattern) = @_; |
| 708 my $result; |
| 709 my $_fn = sub { |
| 710 my $filename = $File::Find::name; |
| 711 |
| 712 if (defined($result)) { |
| 713 return; |
| 714 } |
| 715 $filename = abs2rel($filename, $dir); |
| 716 foreach (@pattern) { |
| 717 if ($filename =~ /$_/) { |
| 718 goto ok; |
| 719 } |
| 720 } |
| 721 return; |
| 722 ok: |
| 723 $result = &$fn($dir, $filename, $data); |
| 724 }; |
| 725 if (scalar(@pattern) == 0) { |
| 726 @pattern = ".*"; |
| 727 } |
| 728 find( { wanted => $_fn, no_chdir => 1 }, $dir); |
| 729 |
| 730 return $result; |
| 731 } |
| 732 |
| 733 # |
| 734 # lcov_copy_fn(from, rel, to) |
| 735 # |
| 736 # Copy directories, files and links from/rel to to/rel. |
| 737 # |
| 738 |
| 739 sub lcov_copy_fn($$$) |
| 740 { |
| 741 my ($from, $rel, $to) = @_; |
| 742 my $absfrom = canonpath(catfile($from, $rel)); |
| 743 my $absto = canonpath(catfile($to, $rel)); |
| 744 |
| 745 if (-d) { |
| 746 if (! -d $absto) { |
| 747 mkpath($absto) or |
| 748 die("ERROR: cannot create directory $absto\n"); |
| 749 chmod(0700, $absto); |
| 750 } |
| 751 } elsif (-l) { |
| 752 # Copy symbolic link |
| 753 my $link = readlink($absfrom); |
| 754 |
| 755 if (!defined($link)) { |
| 756 die("ERROR: cannot read link $absfrom: $!\n"); |
| 757 } |
| 758 symlink($link, $absto) or |
| 759 die("ERROR: cannot create link $absto: $!\n"); |
| 760 } else { |
| 761 lcov_copy_single($absfrom, $absto); |
| 762 chmod(0600, $absto); |
| 763 } |
| 764 return undef; |
| 765 } |
| 766 |
| 767 # |
| 768 # lcov_copy(from, to, subdirs) |
| 769 # |
| 770 # Copy all specified SUBDIRS and files from directory FROM to directory TO. For |
| 771 # regular files, copy file contents without checking its size. This is required |
| 772 # to work with seq_file-generated files. |
| 773 # |
| 774 |
| 775 sub lcov_copy($$;@) |
| 776 { |
| 777 my ($from, $to, @subdirs) = @_; |
| 778 my @pattern; |
| 779 |
| 780 foreach (@subdirs) { |
| 781 push(@pattern, "^$_"); |
| 782 } |
| 783 lcov_find($from, \&lcov_copy_fn, $to, @pattern); |
| 784 } |
| 785 |
| 786 # |
| 787 # lcov_geninfo(directory) |
| 788 # |
| 789 # Call geninfo for the specified directory and with the parameters specified |
| 790 # at the command line. |
| 791 # |
| 792 |
| 793 sub lcov_geninfo(@) |
| 794 { |
| 795 my (@dir) = @_; |
494 my @param; | 796 my @param; |
495 my $file_list = join(" ", @directory); | |
496 | 797 |
497 » info("Capturing coverage data from $file_list\n"); | 798 » # Capture data |
498 » @param = ("$tool_dir/geninfo", @directory); | 799 » info("Capturing coverage data from ".join(" ", @dir)."\n"); |
| 800 » @param = ("$tool_dir/geninfo", @dir); |
499 if ($output_filename) | 801 if ($output_filename) |
500 { | 802 { |
501 @param = (@param, "--output-filename", $output_filename); | 803 @param = (@param, "--output-filename", $output_filename); |
502 } | 804 } |
503 if ($test_name) | 805 if ($test_name) |
504 { | 806 { |
505 @param = (@param, "--test-name", $test_name); | 807 @param = (@param, "--test-name", $test_name); |
506 } | 808 } |
507 if ($follow) | 809 if ($follow) |
508 { | 810 { |
(...skipping 23 matching lines...) Expand all Loading... |
532 @param = (@param, "--no-compat-libtool"); | 834 @param = (@param, "--no-compat-libtool"); |
533 } | 835 } |
534 elsif ($compat_libtool) | 836 elsif ($compat_libtool) |
535 { | 837 { |
536 @param = (@param, "--compat-libtool"); | 838 @param = (@param, "--compat-libtool"); |
537 } | 839 } |
538 if ($gcov_tool) | 840 if ($gcov_tool) |
539 { | 841 { |
540 @param = (@param, "--gcov-tool", $gcov_tool); | 842 @param = (@param, "--gcov-tool", $gcov_tool); |
541 } | 843 } |
542 » if ($ignore_errors) | 844 » foreach (@opt_ignore_errors) { |
543 » { | 845 » » @param = (@param, "--ignore-errors", $_); |
544 » » @param = (@param, "--ignore-errors", $ignore_errors); | 846 » } |
| 847 » if ($no_recursion) { |
| 848 » » @param = (@param, "--no-recursion"); |
545 } | 849 } |
546 if ($initial) | 850 if ($initial) |
547 { | 851 { |
548 @param = (@param, "--initial"); | 852 @param = (@param, "--initial"); |
549 } | 853 } |
550 » if ($no_recursion) | 854 » if ($no_markers) |
551 » { | 855 » { |
552 » » @param = (@param, "--no-recursion"); | 856 » » @param = (@param, "--no-markers"); |
553 » } | 857 » } |
554 | 858 » if ($opt_derive_func_data) |
555 » system(@param); | 859 » { |
556 » exit($? >> 8); | 860 » » @param = (@param, "--derive-func-data"); |
557 } | 861 » } |
558 | 862 » if ($opt_debug) |
559 | 863 » { |
560 # | 864 » » @param = (@param, "--debug"); |
561 # kernel_reset() | 865 » } |
562 # | 866 » if (defined($opt_external) && $opt_external) |
563 # Reset kernel coverage. | 867 » { |
564 # | 868 » » @param = (@param, "--external"); |
565 # Die on error. | 869 » } |
566 # | 870 » if (defined($opt_external) && !$opt_external) |
567 | 871 » { |
568 sub kernel_reset() | 872 » » @param = (@param, "--no-external"); |
569 { | 873 » } |
| 874 » if (defined($opt_compat)) { |
| 875 » » @param = (@param, "--compat", $opt_compat); |
| 876 » } |
| 877 » if (%opt_rc) { |
| 878 » » foreach my $key (keys(%opt_rc)) { |
| 879 » » » @param = (@param, "--rc", "$key=".$opt_rc{$key}); |
| 880 » » } |
| 881 » } |
| 882 |
| 883 » system(@param) and exit($? >> 8); |
| 884 } |
| 885 |
| 886 # |
| 887 # read_file(filename) |
| 888 # |
| 889 # Return the contents of the file defined by filename. |
| 890 # |
| 891 |
| 892 sub read_file($) |
| 893 { |
| 894 » my ($filename) = @_; |
| 895 » my $content; |
| 896 » local $\; |
570 local *HANDLE; | 897 local *HANDLE; |
571 » check_and_load_kernel_module(); | 898 |
572 | 899 » open(HANDLE, "<", $filename) || return undef; |
573 » info("Resetting kernel execution counters\n"); | 900 » $content = <HANDLE>; |
574 » open(HANDLE, ">$gcov_dir/vmlinux") or | |
575 » » die("ERROR: cannot write to $gcov_dir/vmlinux!\n"); | |
576 » print(HANDLE "0"); | |
577 close(HANDLE); | 901 close(HANDLE); |
578 | 902 |
579 » # Unload module if we loaded it in the first place | 903 » return $content; |
580 » if ($need_unload) | 904 } |
581 » { | 905 |
582 » » unload_module($need_unload); | 906 # |
583 » } | 907 # get_package(package_file) |
584 } | 908 # |
585 | 909 # Unpack unprocessed coverage data files from package_file to a temporary |
586 | 910 # directory and return directory name, build directory and gcov kernel version |
587 # | 911 # as found in package. |
588 # kernel_capture() | 912 # |
589 # | 913 |
590 # Capture kernel coverage data and write it to OUTPUT_FILENAME if specified, | 914 sub get_package($) |
591 # otherwise stdout. | 915 { |
592 # | 916 » my ($file) = @_; |
| 917 » my $dir = create_temp_dir(); |
| 918 » my $gkv; |
| 919 » my $build; |
| 920 » my $cwd = getcwd(); |
| 921 » my $count; |
| 922 » local *HANDLE; |
| 923 |
| 924 » info("Reading package $file:\n"); |
| 925 » info(" data directory .......: $dir\n"); |
| 926 » $file = abs_path($file); |
| 927 » chdir($dir); |
| 928 » open(HANDLE, "-|", "tar xvfz '$file' 2>/dev/null") |
| 929 » » or die("ERROR: could not process package $file\n"); |
| 930 » while (<HANDLE>) { |
| 931 » » if (/\.da$/ || /\.gcda$/) { |
| 932 » » » $count++; |
| 933 » » } |
| 934 » } |
| 935 » close(HANDLE); |
| 936 » $build = read_file("$dir/$pkg_build_file"); |
| 937 » if (defined($build)) { |
| 938 » » info(" build directory ......: $build\n"); |
| 939 » } |
| 940 » $gkv = read_file("$dir/$pkg_gkv_file"); |
| 941 » if (defined($gkv)) { |
| 942 » » $gkv = int($gkv); |
| 943 » » if ($gkv != $GKV_PROC && $gkv != $GKV_SYS) { |
| 944 » » » die("ERROR: unsupported gcov kernel version found ". |
| 945 » » » "($gkv)\n"); |
| 946 » » } |
| 947 » » info(" content type .........: kernel data\n"); |
| 948 » » info(" gcov kernel version ..: %s\n", $GKV_NAME[$gkv]); |
| 949 » } else { |
| 950 » » info(" content type .........: application data\n"); |
| 951 » } |
| 952 » info(" data files ...........: $count\n"); |
| 953 » chdir($cwd); |
| 954 |
| 955 » return ($dir, $build, $gkv); |
| 956 } |
| 957 |
| 958 # |
| 959 # write_file(filename, $content) |
| 960 # |
| 961 # Create a file named filename and write the specified content to it. |
| 962 # |
| 963 |
| 964 sub write_file($$) |
| 965 { |
| 966 » my ($filename, $content) = @_; |
| 967 » local *HANDLE; |
| 968 |
| 969 » open(HANDLE, ">", $filename) || return 0; |
| 970 » print(HANDLE $content); |
| 971 » close(HANDLE) || return 0; |
| 972 |
| 973 » return 1; |
| 974 } |
| 975 |
| 976 # count_package_data(filename) |
| 977 # |
| 978 # Count the number of coverage data files in the specified package file. |
| 979 # |
| 980 |
| 981 sub count_package_data($) |
| 982 { |
| 983 » my ($filename) = @_; |
| 984 » local *HANDLE; |
| 985 » my $count = 0; |
| 986 |
| 987 » open(HANDLE, "-|", "tar tfz '$filename'") or return undef; |
| 988 » while (<HANDLE>) { |
| 989 » » if (/\.da$/ || /\.gcda$/) { |
| 990 » » » $count++; |
| 991 » » } |
| 992 » } |
| 993 » close(HANDLE); |
| 994 » return $count; |
| 995 } |
| 996 |
| 997 # |
| 998 # create_package(package_file, source_directory, build_directory[, |
| 999 # » » kernel_gcov_version]) |
| 1000 # |
| 1001 # Store unprocessed coverage data files from source_directory to package_file. |
| 1002 # |
| 1003 |
| 1004 sub create_package($$$;$) |
| 1005 { |
| 1006 » my ($file, $dir, $build, $gkv) = @_; |
| 1007 » my $cwd = getcwd(); |
| 1008 |
| 1009 » # Print information about the package |
| 1010 » info("Creating package $file:\n"); |
| 1011 » info(" data directory .......: $dir\n"); |
| 1012 |
| 1013 » # Handle build directory |
| 1014 » if (defined($build)) { |
| 1015 » » info(" build directory ......: $build\n"); |
| 1016 » » write_file("$dir/$pkg_build_file", $build) |
| 1017 » » » or die("ERROR: could not write to ". |
| 1018 » » » "$dir/$pkg_build_file\n"); |
| 1019 » } |
| 1020 |
| 1021 » # Handle gcov kernel version data |
| 1022 » if (defined($gkv)) { |
| 1023 » » info(" content type .........: kernel data\n"); |
| 1024 » » info(" gcov kernel version ..: %s\n", $GKV_NAME[$gkv]); |
| 1025 » » write_file("$dir/$pkg_gkv_file", $gkv) |
| 1026 » » » or die("ERROR: could not write to ". |
| 1027 » » » "$dir/$pkg_gkv_file\n"); |
| 1028 » } else { |
| 1029 » » info(" content type .........: application data\n"); |
| 1030 » } |
| 1031 |
| 1032 » # Create package |
| 1033 » $file = abs_path($file); |
| 1034 » chdir($dir); |
| 1035 » system("tar cfz $file .") |
| 1036 » » and die("ERROR: could not create package $file\n"); |
| 1037 |
| 1038 » # Remove temporary files |
| 1039 » unlink("$dir/$pkg_build_file"); |
| 1040 » unlink("$dir/$pkg_gkv_file"); |
| 1041 |
| 1042 » # Show number of data files |
| 1043 » if (!$quiet) { |
| 1044 » » my $count = count_package_data($file); |
| 1045 |
| 1046 » » if (defined($count)) { |
| 1047 » » » info(" data files ...........: $count\n"); |
| 1048 » » } |
| 1049 » } |
| 1050 » chdir($cwd); |
| 1051 } |
| 1052 |
| 1053 sub find_link_fn($$$) |
| 1054 { |
| 1055 » my ($from, $rel, $filename) = @_; |
| 1056 » my $absfile = catfile($from, $rel, $filename); |
| 1057 |
| 1058 » if (-l $absfile) { |
| 1059 » » return $absfile; |
| 1060 » } |
| 1061 » return undef; |
| 1062 } |
| 1063 |
| 1064 # |
| 1065 # get_base(dir) |
| 1066 # |
| 1067 # Return (BASE, OBJ), where |
| 1068 # - BASE: is the path to the kernel base directory relative to dir |
| 1069 # - OBJ: is the absolute path to the kernel build directory |
| 1070 # |
| 1071 |
| 1072 sub get_base($) |
| 1073 { |
| 1074 » my ($dir) = @_; |
| 1075 » my $marker = "kernel/gcov/base.gcno"; |
| 1076 » my $markerfile; |
| 1077 » my $sys; |
| 1078 » my $obj; |
| 1079 » my $link; |
| 1080 |
| 1081 » $markerfile = lcov_find($dir, \&find_link_fn, $marker); |
| 1082 » if (!defined($markerfile)) { |
| 1083 » » return (undef, undef); |
| 1084 » } |
| 1085 |
| 1086 » # sys base is parent of parent of markerfile. |
| 1087 » $sys = abs2rel(dirname(dirname(dirname($markerfile))), $dir); |
| 1088 |
| 1089 » # obj base is parent of parent of markerfile link target. |
| 1090 » $link = readlink($markerfile); |
| 1091 » if (!defined($link)) { |
| 1092 » » die("ERROR: could not read $markerfile\n"); |
| 1093 » } |
| 1094 » $obj = dirname(dirname(dirname($link))); |
| 1095 |
| 1096 » return ($sys, $obj); |
| 1097 } |
| 1098 |
| 1099 # |
| 1100 # apply_base_dir(data_dir, base_dir, build_dir, @directories) |
| 1101 # |
| 1102 # Make entries in @directories relative to data_dir. |
| 1103 # |
| 1104 |
| 1105 sub apply_base_dir($$$@) |
| 1106 { |
| 1107 » my ($data, $base, $build, @dirs) = @_; |
| 1108 » my $dir; |
| 1109 » my @result; |
| 1110 |
| 1111 » foreach $dir (@dirs) { |
| 1112 » » # Is directory path relative to data directory? |
| 1113 » » if (-d catdir($data, $dir)) { |
| 1114 » » » push(@result, $dir); |
| 1115 » » » next; |
| 1116 » » } |
| 1117 » » # Relative to the auto-detected base-directory? |
| 1118 » » if (defined($base)) { |
| 1119 » » » if (-d catdir($data, $base, $dir)) { |
| 1120 » » » » push(@result, catdir($base, $dir)); |
| 1121 » » » » next; |
| 1122 » » » } |
| 1123 » » } |
| 1124 » » # Relative to the specified base-directory? |
| 1125 » » if (defined($base_directory)) { |
| 1126 » » » if (file_name_is_absolute($base_directory)) { |
| 1127 » » » » $base = abs2rel($base_directory, rootdir()); |
| 1128 » » » } else { |
| 1129 » » » » $base = $base_directory; |
| 1130 » » » } |
| 1131 » » » if (-d catdir($data, $base, $dir)) { |
| 1132 » » » » push(@result, catdir($base, $dir)); |
| 1133 » » » » next; |
| 1134 » » » } |
| 1135 » » } |
| 1136 » » # Relative to the build directory? |
| 1137 » » if (defined($build)) { |
| 1138 » » » if (file_name_is_absolute($build)) { |
| 1139 » » » » $base = abs2rel($build, rootdir()); |
| 1140 » » » } else { |
| 1141 » » » » $base = $build; |
| 1142 » » » } |
| 1143 » » » if (-d catdir($data, $base, $dir)) { |
| 1144 » » » » push(@result, catdir($base, $dir)); |
| 1145 » » » » next; |
| 1146 » » » } |
| 1147 » » } |
| 1148 » » die("ERROR: subdirectory $dir not found\n". |
| 1149 » » "Please use -b to specify the correct directory\n"); |
| 1150 » } |
| 1151 » return @result; |
| 1152 } |
| 1153 |
| 1154 # |
| 1155 # copy_gcov_dir(dir, [@subdirectories]) |
| 1156 # |
| 1157 # Create a temporary directory and copy all or, if specified, only some |
| 1158 # subdirectories from dir to that directory. Return the name of the temporary |
| 1159 # directory. |
| 1160 # |
| 1161 |
| 1162 sub copy_gcov_dir($;@) |
| 1163 { |
| 1164 » my ($data, @dirs) = @_; |
| 1165 » my $tempdir = create_temp_dir(); |
| 1166 |
| 1167 » info("Copying data to temporary directory $tempdir\n"); |
| 1168 » lcov_copy($data, $tempdir, @dirs); |
| 1169 |
| 1170 » return $tempdir; |
| 1171 } |
| 1172 |
| 1173 # |
| 1174 # kernel_capture_initial |
| 1175 # |
| 1176 # Capture initial kernel coverage data, i.e. create a coverage data file from |
| 1177 # static graph files which contains zero coverage data for all instrumented |
| 1178 # lines. |
| 1179 # |
| 1180 |
| 1181 sub kernel_capture_initial() |
| 1182 { |
| 1183 » my $build; |
| 1184 » my $source; |
| 1185 » my @params; |
| 1186 |
| 1187 » if (defined($base_directory)) { |
| 1188 » » $build = $base_directory; |
| 1189 » » $source = "specified"; |
| 1190 » } else { |
| 1191 » » (undef, $build) = get_base($gcov_dir); |
| 1192 » » if (!defined($build)) { |
| 1193 » » » die("ERROR: could not auto-detect build directory.\n". |
| 1194 » » » "Please use -b to specify the build directory\n"); |
| 1195 » » } |
| 1196 » » $source = "auto-detected"; |
| 1197 » } |
| 1198 » info("Using $build as kernel build directory ($source)\n"); |
| 1199 » # Build directory needs to be passed to geninfo |
| 1200 » $base_directory = $build; |
| 1201 » if (@kernel_directory) { |
| 1202 » » foreach my $dir (@kernel_directory) { |
| 1203 » » » push(@params, "$build/$dir"); |
| 1204 » » } |
| 1205 » } else { |
| 1206 » » push(@params, $build); |
| 1207 » } |
| 1208 » lcov_geninfo(@params); |
| 1209 } |
| 1210 |
| 1211 # |
| 1212 # kernel_capture_from_dir(directory, gcov_kernel_version, build) |
| 1213 # |
| 1214 # Perform the actual kernel coverage capturing from the specified directory |
| 1215 # assuming that the data was copied from the specified gcov kernel version. |
| 1216 # |
| 1217 |
| 1218 sub kernel_capture_from_dir($$$) |
| 1219 { |
| 1220 » my ($dir, $gkv, $build) = @_; |
| 1221 |
| 1222 » # Create package or coverage file |
| 1223 » if (defined($to_package)) { |
| 1224 » » create_package($to_package, $dir, $build, $gkv); |
| 1225 » } else { |
| 1226 » » # Build directory needs to be passed to geninfo |
| 1227 » » $base_directory = $build; |
| 1228 » » lcov_geninfo($dir); |
| 1229 » } |
| 1230 } |
| 1231 |
| 1232 # |
| 1233 # adjust_kernel_dir(dir, build) |
| 1234 # |
| 1235 # Adjust directories specified with -k so that they point to the directory |
| 1236 # relative to DIR. Return the build directory if specified or the auto- |
| 1237 # detected build-directory. |
| 1238 # |
| 1239 |
| 1240 sub adjust_kernel_dir($$) |
| 1241 { |
| 1242 » my ($dir, $build) = @_; |
| 1243 » my ($sys_base, $build_auto) = get_base($dir); |
| 1244 |
| 1245 » if (!defined($build)) { |
| 1246 » » $build = $build_auto; |
| 1247 » } |
| 1248 » if (!defined($build)) { |
| 1249 » » die("ERROR: could not auto-detect build directory.\n". |
| 1250 » » "Please use -b to specify the build directory\n"); |
| 1251 » } |
| 1252 » # Make @kernel_directory relative to sysfs base |
| 1253 » if (@kernel_directory) { |
| 1254 » » @kernel_directory = apply_base_dir($dir, $sys_base, $build, |
| 1255 » » » » » » @kernel_directory); |
| 1256 » } |
| 1257 » return $build; |
| 1258 } |
593 | 1259 |
594 sub kernel_capture() | 1260 sub kernel_capture() |
595 { | 1261 { |
596 » my @param; | 1262 » my $data_dir; |
597 | 1263 » my $build = $base_directory; |
598 » check_and_load_kernel_module(); | 1264 |
599 | 1265 » if ($gcov_gkv == $GKV_SYS) { |
600 » # Make sure the temporary directory is removed upon script termination | 1266 » » $build = adjust_kernel_dir($gcov_dir, $build); |
601 » END | 1267 » } |
602 » { | 1268 » $data_dir = copy_gcov_dir($gcov_dir, @kernel_directory); |
603 » » if ($temp_dir_name) | 1269 » kernel_capture_from_dir($data_dir, $gcov_gkv, $build); |
604 » » { | 1270 } |
605 » » » stat($temp_dir_name); | 1271 |
606 » » » if (-r _) | 1272 # |
607 » » » { | 1273 # package_capture() |
608 » » » » info("Removing temporary directory ". | 1274 # |
609 » » » » "$temp_dir_name\n"); | 1275 # Capture coverage data from a package of unprocessed coverage data files |
610 | 1276 # as generated by lcov --to-package. |
611 » » » » # Remove temporary directory | 1277 # |
612 » » » » system("rm", "-rf", $temp_dir_name) | 1278 |
613 » » » » » and warn("WARNING: cannot remove ". | 1279 sub package_capture() |
614 » » » » » » "temporary directory ". | 1280 { |
615 » » » » » » "$temp_dir_name!\n"); | 1281 » my $dir; |
616 » » » } | 1282 » my $build; |
617 » » } | 1283 » my $gkv; |
618 » } | 1284 |
619 | 1285 » ($dir, $build, $gkv) = get_package($from_package); |
620 » # Get temporary directory | 1286 |
621 » $temp_dir_name = create_temp_dir(); | 1287 » # Check for build directory |
622 | 1288 » if (defined($base_directory)) { |
623 » info("Copying kernel data to temporary directory $temp_dir_name\n"); | 1289 » » if (defined($build)) { |
624 | 1290 » » » info("Using build directory specified by -b.\n"); |
625 » if (!@kernel_directory) | 1291 » » } |
626 » { | 1292 » » $build = $base_directory; |
627 » » # Copy files from gcov kernel directory | 1293 » } |
628 » » system("cp", "-dr", $gcov_dir, $temp_dir_name) | 1294 |
629 » » » and die("ERROR: cannot copy files from $gcov_dir!\n"); | 1295 » # Do the actual capture |
630 » } | 1296 » if (defined($gkv)) { |
631 » else | 1297 » » if ($gkv == $GKV_SYS) { |
632 » { | 1298 » » » $build = adjust_kernel_dir($dir, $build); |
633 » » # Prefix list of kernel sub-directories with the gcov kernel | 1299 » » } |
634 » » # directory | 1300 » » if (@kernel_directory) { |
635 » » @kernel_directory = map("$gcov_dir/$_", @kernel_directory); | 1301 » » » $dir = copy_gcov_dir($dir, @kernel_directory);» |
636 | 1302 » » } |
637 » » # Copy files from gcov kernel directory | 1303 » » kernel_capture_from_dir($dir, $gkv, $build); |
638 » » system("cp", "-dr", @kernel_directory, $temp_dir_name) | 1304 » } else { |
639 » » » and die("ERROR: cannot copy files from ". | 1305 » » # Build directory needs to be passed to geninfo |
640 » » » » join(" ", @kernel_directory)."!\n"); | 1306 » » $base_directory = $build; |
641 » } | 1307 » » lcov_geninfo($dir); |
642 | 1308 » } |
643 » # Make directories writable | 1309 } |
644 » system("find", $temp_dir_name, "-type", "d", "-exec", "chmod", "u+w", | 1310 |
645 » "{}", ";") | |
646 » » and die("ERROR: cannot modify access rights for ". | |
647 » » » "$temp_dir_name!\n"); | |
648 | |
649 » # Make files writable | |
650 » system("find", $temp_dir_name, "-type", "f", "-exec", "chmod", "u+w", | |
651 » "{}", ";") | |
652 » » and die("ERROR: cannot modify access rights for ". | |
653 » » » "$temp_dir_name!\n"); | |
654 | |
655 » # Capture data | |
656 » info("Capturing coverage data from $temp_dir_name\n"); | |
657 » @param = ("$tool_dir/geninfo", $temp_dir_name); | |
658 » if ($output_filename) | |
659 » { | |
660 » » @param = (@param, "--output-filename", $output_filename); | |
661 » } | |
662 » if ($test_name) | |
663 » { | |
664 » » @param = (@param, "--test-name", $test_name); | |
665 » } | |
666 » if ($follow) | |
667 » { | |
668 » » @param = (@param, "--follow"); | |
669 » } | |
670 » if ($quiet) | |
671 » { | |
672 » » @param = (@param, "--quiet"); | |
673 » } | |
674 » if (defined($checksum)) | |
675 » { | |
676 » » if ($checksum) | |
677 » » { | |
678 » » » @param = (@param, "--checksum"); | |
679 » » } | |
680 » » else | |
681 » » { | |
682 » » » @param = (@param, "--no-checksum"); | |
683 » » } | |
684 » } | |
685 » if ($base_directory) | |
686 » { | |
687 » » @param = (@param, "--base-directory", $base_directory); | |
688 » } | |
689 » if ($no_compat_libtool) | |
690 » { | |
691 » » @param = (@param, "--no-compat-libtool"); | |
692 » } | |
693 » elsif ($compat_libtool) | |
694 » { | |
695 » » @param = (@param, "--compat-libtool"); | |
696 » } | |
697 » if ($gcov_tool) | |
698 » { | |
699 » » @param = (@param, "--gcov-tool", $gcov_tool); | |
700 » } | |
701 » if ($ignore_errors) | |
702 » { | |
703 » » @param = (@param, "--ignore-errors", $ignore_errors); | |
704 » } | |
705 » if ($initial) | |
706 » { | |
707 » » @param = (@param, "--initial"); | |
708 » } | |
709 » system(@param) and exit($? >> 8); | |
710 | |
711 | |
712 » # Unload module if we loaded it in the first place | |
713 » if ($need_unload) | |
714 » { | |
715 » » unload_module($need_unload); | |
716 » } | |
717 } | |
718 | |
719 | 1311 |
720 # | 1312 # |
721 # info(printf_parameter) | 1313 # info(printf_parameter) |
722 # | 1314 # |
723 # Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag | 1315 # Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag |
724 # is not set. | 1316 # is not set. |
725 # | 1317 # |
726 | 1318 |
727 sub info(@) | 1319 sub info(@) |
728 { | 1320 { |
729 if (!$quiet) | 1321 if (!$quiet) |
730 { | 1322 { |
731 # Print info string | 1323 # Print info string |
732 if ($to_file) | 1324 if ($to_file) |
733 { | 1325 { |
734 » » » print(@_) | 1326 » » » printf(@_) |
735 } | 1327 } |
736 else | 1328 else |
737 { | 1329 { |
738 » » » # Don't interfer with the .info output to STDOUT | 1330 » » » # Don't interfere with the .info output to STDOUT |
739 printf(STDERR @_); | 1331 printf(STDERR @_); |
740 } | 1332 } |
741 } | 1333 } |
742 } | 1334 } |
743 | 1335 |
744 | 1336 |
745 # | 1337 # |
746 # Check if the gcov kernel module is loaded. If it is, exit, if not, try | 1338 # create_temp_dir() |
747 # to load it. | 1339 # |
| 1340 # Create a temporary directory and return its path. |
748 # | 1341 # |
749 # Die on error. | 1342 # Die on error. |
750 # | 1343 # |
751 | 1344 |
752 sub check_and_load_kernel_module() | 1345 sub create_temp_dir() |
753 { | 1346 { |
754 » my $module_name; | 1347 » my $dir; |
755 | 1348 |
756 » # Is it loaded already? | 1349 » if (defined($tmp_dir)) { |
757 » stat("$gcov_dir"); | 1350 » » $dir = tempdir(DIR => $tmp_dir, CLEANUP => 1); |
758 » if (-r _) { return(); } | 1351 » } else { |
759 | 1352 » » $dir = tempdir(CLEANUP => 1); |
760 » info("Loading required gcov kernel module.\n"); | 1353 » } |
761 | 1354 » if (!defined($dir)) { |
762 » # Do we have access to the insmod tool? | 1355 » » die("ERROR: cannot create temporary directory\n"); |
763 » stat($insmod_tool); | 1356 » } |
764 » if (!-x _) | 1357 » push(@temp_dirs, $dir); |
765 » { | 1358 |
766 » » die("ERROR: need insmod tool ($insmod_tool) to access kernel ". | 1359 » return $dir; |
767 » » "coverage data!\n"); | 1360 } |
768 » } | 1361 |
769 » # Do we have access to the modprobe tool? | 1362 |
770 » stat($modprobe_tool); | 1363 # |
771 » if (!-x _) | 1364 # br_taken_to_num(taken) |
772 » { | 1365 # |
773 » » die("ERROR: need modprobe tool ($modprobe_tool) to access ". | 1366 # Convert a branch taken value .info format to number format. |
774 » » "kernel coverage data!\n"); | 1367 # |
775 » } | 1368 |
776 | 1369 sub br_taken_to_num($) |
777 » # Try some possibilities of where the gcov kernel module may be found | 1370 { |
778 » foreach $module_name (@gcovmod) | 1371 » my ($taken) = @_; |
779 » { | 1372 |
780 » » # Try to load module from system wide module directory | 1373 » return 0 if ($taken eq '-'); |
781 » » # /lib/modules | 1374 » return $taken + 1; |
782 » » if (system_no_output(3, $modprobe_tool, $module_name) == 0) | 1375 } |
783 » » { | 1376 |
784 » » » # Succeeded | 1377 |
785 » » » $need_unload = $module_name; | 1378 # |
786 » » » return(); | 1379 # br_num_to_taken(taken) |
| 1380 # |
| 1381 # Convert a branch taken value in number format to .info format. |
| 1382 # |
| 1383 |
| 1384 sub br_num_to_taken($) |
| 1385 { |
| 1386 » my ($taken) = @_; |
| 1387 |
| 1388 » return '-' if ($taken == 0); |
| 1389 » return $taken - 1; |
| 1390 } |
| 1391 |
| 1392 |
| 1393 # |
| 1394 # br_taken_add(taken1, taken2) |
| 1395 # |
| 1396 # Return the result of taken1 + taken2 for 'branch taken' values. |
| 1397 # |
| 1398 |
| 1399 sub br_taken_add($$) |
| 1400 { |
| 1401 » my ($t1, $t2) = @_; |
| 1402 |
| 1403 » return $t1 if (!defined($t2)); |
| 1404 » return $t2 if (!defined($t1)); |
| 1405 » return $t1 if ($t2 eq '-'); |
| 1406 » return $t2 if ($t1 eq '-'); |
| 1407 » return $t1 + $t2; |
| 1408 } |
| 1409 |
| 1410 |
| 1411 # |
| 1412 # br_taken_sub(taken1, taken2) |
| 1413 # |
| 1414 # Return the result of taken1 - taken2 for 'branch taken' values. Return 0 |
| 1415 # if the result would become negative. |
| 1416 # |
| 1417 |
| 1418 sub br_taken_sub($$) |
| 1419 { |
| 1420 » my ($t1, $t2) = @_; |
| 1421 |
| 1422 » return $t1 if (!defined($t2)); |
| 1423 » return undef if (!defined($t1)); |
| 1424 » return $t1 if ($t1 eq '-'); |
| 1425 » return $t1 if ($t2 eq '-'); |
| 1426 » return 0 if $t2 > $t1; |
| 1427 » return $t1 - $t2; |
| 1428 } |
| 1429 |
| 1430 |
| 1431 # |
| 1432 # |
| 1433 # br_ivec_len(vector) |
| 1434 # |
| 1435 # Return the number of entries in the branch coverage vector. |
| 1436 # |
| 1437 |
| 1438 sub br_ivec_len($) |
| 1439 { |
| 1440 » my ($vec) = @_; |
| 1441 |
| 1442 » return 0 if (!defined($vec)); |
| 1443 » return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES; |
| 1444 } |
| 1445 |
| 1446 |
| 1447 # |
| 1448 # br_ivec_push(vector, block, branch, taken) |
| 1449 # |
| 1450 # Add an entry to the branch coverage vector. If an entry with the same |
| 1451 # branch ID already exists, add the corresponding taken values. |
| 1452 # |
| 1453 |
| 1454 sub br_ivec_push($$$$) |
| 1455 { |
| 1456 » my ($vec, $block, $branch, $taken) = @_; |
| 1457 » my $offset; |
| 1458 » my $num = br_ivec_len($vec); |
| 1459 » my $i; |
| 1460 |
| 1461 » $vec = "" if (!defined($vec)); |
| 1462 |
| 1463 » # Check if branch already exists in vector |
| 1464 » for ($i = 0; $i < $num; $i++) { |
| 1465 » » my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i); |
| 1466 |
| 1467 » » next if ($v_block != $block || $v_branch != $branch); |
| 1468 |
| 1469 » » # Add taken counts |
| 1470 » » $taken = br_taken_add($taken, $v_taken); |
| 1471 » » last; |
| 1472 » } |
| 1473 |
| 1474 » $offset = $i * $BR_VEC_ENTRIES; |
| 1475 » $taken = br_taken_to_num($taken); |
| 1476 |
| 1477 » # Add to vector |
| 1478 » vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block; |
| 1479 » vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch; |
| 1480 » vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken; |
| 1481 |
| 1482 » return $vec; |
| 1483 } |
| 1484 |
| 1485 |
| 1486 # |
| 1487 # br_ivec_get(vector, number) |
| 1488 # |
| 1489 # Return an entry from the branch coverage vector. |
| 1490 # |
| 1491 |
| 1492 sub br_ivec_get($$) |
| 1493 { |
| 1494 » my ($vec, $num) = @_; |
| 1495 » my $block; |
| 1496 » my $branch; |
| 1497 » my $taken; |
| 1498 » my $offset = $num * $BR_VEC_ENTRIES; |
| 1499 |
| 1500 » # Retrieve data from vector |
| 1501 » $block» = vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH); |
| 1502 » $branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH); |
| 1503 » $taken» = vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH); |
| 1504 |
| 1505 » # Decode taken value from an integer |
| 1506 » $taken = br_num_to_taken($taken); |
| 1507 |
| 1508 » return ($block, $branch, $taken); |
| 1509 } |
| 1510 |
| 1511 |
| 1512 # |
| 1513 # get_br_found_and_hit(brcount) |
| 1514 # |
| 1515 # Return (br_found, br_hit) for brcount |
| 1516 # |
| 1517 |
| 1518 sub get_br_found_and_hit($) |
| 1519 { |
| 1520 » my ($brcount) = @_; |
| 1521 » my $line; |
| 1522 » my $br_found = 0; |
| 1523 » my $br_hit = 0; |
| 1524 |
| 1525 » foreach $line (keys(%{$brcount})) { |
| 1526 » » my $brdata = $brcount->{$line}; |
| 1527 » » my $i; |
| 1528 » » my $num = br_ivec_len($brdata); |
| 1529 |
| 1530 » » for ($i = 0; $i < $num; $i++) { |
| 1531 » » » my $taken; |
| 1532 |
| 1533 » » » (undef, undef, $taken) = br_ivec_get($brdata, $i); |
| 1534 |
| 1535 » » » $br_found++; |
| 1536 » » » $br_hit++ if ($taken ne "-" && $taken > 0); |
787 } | 1537 } |
788 | 1538 » } |
789 » » # Try to load linux 2.5/2.6 module from tool directory | 1539 |
790 » » if (system_no_output(3, $insmod_tool, | 1540 » return ($br_found, $br_hit); |
791 » » » » "$tool_dir/$module_name.ko") == 0) | 1541 } |
792 » » { | 1542 |
793 » » » # Succeeded | 1543 |
794 » » » $need_unload = $module_name; | |
795 » » » return(); | |
796 » » } | |
797 | |
798 » » # Try to load linux 2.4 module from tool directory | |
799 » » if (system_no_output(3, $insmod_tool, | |
800 » » » » "$tool_dir/$module_name.o") == 0) | |
801 » » { | |
802 » » » # Succeeded | |
803 » » » $need_unload = $module_name; | |
804 » » » return(); | |
805 » » } | |
806 » } | |
807 | |
808 » # Hm, loading failed - maybe we aren't root? | |
809 » if ($> != 0) | |
810 » { | |
811 » » die("ERROR: need root access to load kernel module!\n"); | |
812 » } | |
813 | |
814 » die("ERROR: cannot load required gcov kernel module!\n"); | |
815 } | |
816 | |
817 | |
818 # | |
819 # unload_module() | |
820 # | |
821 # Unload the gcov kernel module. | |
822 # | |
823 | |
824 sub unload_module($) | |
825 { | |
826 » my $module = $_[0]; | |
827 | |
828 » info("Unloading kernel module $module\n"); | |
829 | |
830 » # Do we have access to the rmmod tool? | |
831 » stat($rmmod_tool); | |
832 » if (!-x _) | |
833 » { | |
834 » » warn("WARNING: cannot execute rmmod tool at $rmmod_tool - ". | |
835 » » "gcov module still loaded!\n"); | |
836 » } | |
837 | |
838 » # Unload gcov kernel module | |
839 » system_no_output(1, $rmmod_tool, $module) | |
840 » » and warn("WARNING: cannot unload gcov kernel module ". | |
841 » » "$module!\n"); | |
842 } | |
843 | |
844 | |
845 # | |
846 # create_temp_dir() | |
847 # | |
848 # Create a temporary directory and return its path. | |
849 # | |
850 # Die on error. | |
851 # | |
852 | |
853 sub create_temp_dir() | |
854 { | |
855 » my $dirname; | |
856 » my $number = sprintf("%d", rand(1000)); | |
857 | |
858 » # Endless loops are evil | |
859 » while ($number++ < 1000) | |
860 » { | |
861 » » $dirname = "$tmp_dir/$tmp_prefix$number"; | |
862 » » stat($dirname); | |
863 » » if (-e _) { next; } | |
864 | |
865 » » mkdir($dirname) | |
866 » » » or die("ERROR: cannot create temporary directory ". | |
867 » » » "$dirname!\n"); | |
868 | |
869 » » return($dirname); | |
870 » } | |
871 | |
872 » die("ERROR: cannot create temporary directory in $tmp_dir!\n"); | |
873 } | |
874 | |
875 | |
876 # | 1544 # |
877 # read_info_file(info_filename) | 1545 # read_info_file(info_filename) |
878 # | 1546 # |
879 # Read in the contents of the .info file specified by INFO_FILENAME. Data will | 1547 # Read in the contents of the .info file specified by INFO_FILENAME. Data will |
880 # be returned as a reference to a hash containing the following mappings: | 1548 # be returned as a reference to a hash containing the following mappings: |
881 # | 1549 # |
882 # %result: for each filename found in file -> \%data | 1550 # %result: for each filename found in file -> \%data |
883 # | 1551 # |
884 # %data: "test" -> \%testdata | 1552 # %data: "test" -> \%testdata |
885 # "sum" -> \%sumcount | 1553 # "sum" -> \%sumcount |
886 # "func" -> \%funcdata | 1554 # "func" -> \%funcdata |
887 # "found" -> $lines_found (number of instrumented lines found in file) | 1555 # "found" -> $lines_found (number of instrumented lines found in file) |
888 # "hit" -> $lines_hit (number of executed lines in file) | 1556 # "hit" -> $lines_hit (number of executed lines in file) |
889 # "check" -> \%checkdata | 1557 # "check" -> \%checkdata |
890 # "testfnc" -> \%testfncdata | 1558 # "testfnc" -> \%testfncdata |
891 # "sumfnc" -> \%sumfnccount | 1559 # "sumfnc" -> \%sumfnccount |
| 1560 # "testbr" -> \%testbrdata |
| 1561 # "sumbr" -> \%sumbrcount |
892 # | 1562 # |
893 # %testdata : name of test affecting this file -> \%testcount | 1563 # %testdata : name of test affecting this file -> \%testcount |
894 # %testfncdata: name of test affecting this file -> \%testfnccount | 1564 # %testfncdata: name of test affecting this file -> \%testfnccount |
| 1565 # %testbrdata: name of test affecting this file -> \%testbrcount |
895 # | 1566 # |
896 # %testcount : line number -> execution count for a single test | 1567 # %testcount : line number -> execution count for a single test |
897 # %testfnccount: function name -> execution count for a single test | 1568 # %testfnccount: function name -> execution count for a single test |
| 1569 # %testbrcount : line number -> branch coverage data for a single test |
898 # %sumcount : line number -> execution count for all tests | 1570 # %sumcount : line number -> execution count for all tests |
899 # %sumfnccount : function name -> execution count for all tests | 1571 # %sumfnccount : function name -> execution count for all tests |
| 1572 # %sumbrcount : line number -> branch coverage data for all tests |
900 # %funcdata : function name -> line number | 1573 # %funcdata : function name -> line number |
901 # %checkdata : line number -> checksum of source code line | 1574 # %checkdata : line number -> checksum of source code line |
| 1575 # $brdata : vector of items: block, branch, taken |
902 # | 1576 # |
903 # Note that .info file sections referring to the same file and test name | 1577 # Note that .info file sections referring to the same file and test name |
904 # will automatically be combined by adding all execution counts. | 1578 # will automatically be combined by adding all execution counts. |
905 # | 1579 # |
906 # Note that if INFO_FILENAME ends with ".gz", it is assumed that the file | 1580 # Note that if INFO_FILENAME ends with ".gz", it is assumed that the file |
907 # is compressed using GZIP. If available, GUNZIP will be used to decompress | 1581 # is compressed using GZIP. If available, GUNZIP will be used to decompress |
908 # this file. | 1582 # this file. |
909 # | 1583 # |
910 # Die on error. | 1584 # Die on error. |
911 # | 1585 # |
912 | 1586 |
913 sub read_info_file($) | 1587 sub read_info_file($) |
914 { | 1588 { |
915 my $tracefile = $_[0]; # Name of tracefile | 1589 my $tracefile = $_[0]; # Name of tracefile |
916 my %result; # Resulting hash: file -> data | 1590 my %result; # Resulting hash: file -> data |
917 my $data; # Data handle for current entry | 1591 my $data; # Data handle for current entry |
918 my $testdata; # " " | 1592 my $testdata; # " " |
919 my $testcount; # " " | 1593 my $testcount; # " " |
920 my $sumcount; # " " | 1594 my $sumcount; # " " |
921 my $funcdata; # " " | 1595 my $funcdata; # " " |
922 my $checkdata; # " " | 1596 my $checkdata; # " " |
923 my $testfncdata; | 1597 my $testfncdata; |
924 my $testfnccount; | 1598 my $testfnccount; |
925 my $sumfnccount; | 1599 my $sumfnccount; |
| 1600 my $testbrdata; |
| 1601 my $testbrcount; |
| 1602 my $sumbrcount; |
926 my $line; # Current line read from .info file | 1603 my $line; # Current line read from .info file |
927 my $testname; # Current test name | 1604 my $testname; # Current test name |
928 my $filename; # Current filename | 1605 my $filename; # Current filename |
929 my $hitcount; # Count for lines hit | 1606 my $hitcount; # Count for lines hit |
930 my $count; # Execution count of current line | 1607 my $count; # Execution count of current line |
931 my $negative; # If set, warn about negative counts | 1608 my $negative; # If set, warn about negative counts |
932 my $changed_testname; # If set, warn about changed testname | 1609 my $changed_testname; # If set, warn about changed testname |
933 my $line_checksum; # Checksum of current line | 1610 my $line_checksum; # Checksum of current line |
934 local *INFO_HANDLE; # Filehandle for .info file | 1611 local *INFO_HANDLE; # Filehandle for .info file |
935 | 1612 |
(...skipping 18 matching lines...) Expand all Loading... |
954 # Check for availability of GZIP tool | 1631 # Check for availability of GZIP tool |
955 system_no_output(1, "gunzip" ,"-h") | 1632 system_no_output(1, "gunzip" ,"-h") |
956 and die("ERROR: gunzip command not available!\n"); | 1633 and die("ERROR: gunzip command not available!\n"); |
957 | 1634 |
958 # Check integrity of compressed file | 1635 # Check integrity of compressed file |
959 system_no_output(1, "gunzip", "-t", $_[0]) | 1636 system_no_output(1, "gunzip", "-t", $_[0]) |
960 and die("ERROR: integrity check failed for ". | 1637 and die("ERROR: integrity check failed for ". |
961 "compressed file $_[0]!\n"); | 1638 "compressed file $_[0]!\n"); |
962 | 1639 |
963 # Open compressed file | 1640 # Open compressed file |
964 » » open(INFO_HANDLE, "gunzip -c $_[0]|") | 1641 » » open(INFO_HANDLE, "-|", "gunzip -c '$_[0]'") |
965 or die("ERROR: cannot start gunzip to decompress ". | 1642 or die("ERROR: cannot start gunzip to decompress ". |
966 "file $_[0]!\n"); | 1643 "file $_[0]!\n"); |
967 } | 1644 } |
968 else | 1645 else |
969 { | 1646 { |
970 # Open decompressed file | 1647 # Open decompressed file |
971 » » open(INFO_HANDLE, $_[0]) | 1648 » » open(INFO_HANDLE, "<", $_[0]) |
972 or die("ERROR: cannot read file $_[0]!\n"); | 1649 or die("ERROR: cannot read file $_[0]!\n"); |
973 } | 1650 } |
974 | 1651 |
975 $testname = ""; | 1652 $testname = ""; |
976 while (<INFO_HANDLE>) | 1653 while (<INFO_HANDLE>) |
977 { | 1654 { |
978 chomp($_); | 1655 chomp($_); |
979 $line = $_; | 1656 $line = $_; |
980 | 1657 |
981 # Switch statement | 1658 # Switch statement |
982 foreach ($line) | 1659 foreach ($line) |
983 { | 1660 { |
984 » » » /^TN:([^,]*)/ && do | 1661 » » » /^TN:([^,]*)(,diff)?/ && do |
985 { | 1662 { |
986 # Test name information found | 1663 # Test name information found |
987 $testname = defined($1) ? $1 : ""; | 1664 $testname = defined($1) ? $1 : ""; |
988 if ($testname =~ s/\W/_/g) | 1665 if ($testname =~ s/\W/_/g) |
989 { | 1666 { |
990 $changed_testname = 1; | 1667 $changed_testname = 1; |
991 } | 1668 } |
| 1669 $testname .= $2 if (defined($2)); |
992 last; | 1670 last; |
993 }; | 1671 }; |
994 | 1672 |
995 /^[SK]F:(.*)/ && do | 1673 /^[SK]F:(.*)/ && do |
996 { | 1674 { |
997 # Filename information found | 1675 # Filename information found |
998 # Retrieve data for new entry | 1676 # Retrieve data for new entry |
999 $filename = $1; | 1677 $filename = $1; |
1000 | 1678 |
1001 $data = $result{$filename}; | 1679 $data = $result{$filename}; |
1002 ($testdata, $sumcount, $funcdata, $checkdata, | 1680 ($testdata, $sumcount, $funcdata, $checkdata, |
1003 » » » » $testfncdata, $sumfnccount) = | 1681 » » » » $testfncdata, $sumfnccount, $testbrdata, |
| 1682 » » » » $sumbrcount) = |
1004 get_info_entry($data); | 1683 get_info_entry($data); |
1005 | 1684 |
1006 if (defined($testname)) | 1685 if (defined($testname)) |
1007 { | 1686 { |
1008 $testcount = $testdata->{$testname}; | 1687 $testcount = $testdata->{$testname}; |
1009 $testfnccount = $testfncdata->{$testname
}; | 1688 $testfnccount = $testfncdata->{$testname
}; |
| 1689 $testbrcount = $testbrdata->{$testname}; |
1010 } | 1690 } |
1011 else | 1691 else |
1012 { | 1692 { |
1013 $testcount = {}; | 1693 $testcount = {}; |
1014 $testfnccount = {}; | 1694 $testfnccount = {}; |
| 1695 $testbrcount = {}; |
1015 } | 1696 } |
1016 last; | 1697 last; |
1017 }; | 1698 }; |
1018 | 1699 |
1019 /^DA:(\d+),(-?\d+)(,[^,\s]+)?/ && do | 1700 /^DA:(\d+),(-?\d+)(,[^,\s]+)?/ && do |
1020 { | 1701 { |
1021 # Fix negative counts | 1702 # Fix negative counts |
1022 $count = $2 < 0 ? 0 : $2; | 1703 $count = $2 < 0 ? 0 : $2; |
1023 if ($2 < 0) | 1704 if ($2 < 0) |
1024 { | 1705 { |
(...skipping 23 matching lines...) Expand all Loading... |
1048 "at $filename:$1\n"); | 1729 "at $filename:$1\n"); |
1049 } | 1730 } |
1050 | 1731 |
1051 $checkdata->{$1} = $line_checksum; | 1732 $checkdata->{$1} = $line_checksum; |
1052 } | 1733 } |
1053 last; | 1734 last; |
1054 }; | 1735 }; |
1055 | 1736 |
1056 /^FN:(\d+),([^,]+)/ && do | 1737 /^FN:(\d+),([^,]+)/ && do |
1057 { | 1738 { |
| 1739 last if (!$func_coverage); |
| 1740 |
1058 # Function data found, add to structure | 1741 # Function data found, add to structure |
1059 $funcdata->{$2} = $1; | 1742 $funcdata->{$2} = $1; |
1060 | 1743 |
1061 # Also initialize function call data | 1744 # Also initialize function call data |
1062 if (!defined($sumfnccount->{$2})) { | 1745 if (!defined($sumfnccount->{$2})) { |
1063 $sumfnccount->{$2} = 0; | 1746 $sumfnccount->{$2} = 0; |
1064 } | 1747 } |
1065 if (defined($testname)) | 1748 if (defined($testname)) |
1066 { | 1749 { |
1067 if (!defined($testfnccount->{$2})) { | 1750 if (!defined($testfnccount->{$2})) { |
1068 $testfnccount->{$2} = 0; | 1751 $testfnccount->{$2} = 0; |
1069 } | 1752 } |
1070 } | 1753 } |
1071 last; | 1754 last; |
1072 }; | 1755 }; |
1073 | 1756 |
1074 /^FNDA:(\d+),([^,]+)/ && do | 1757 /^FNDA:(\d+),([^,]+)/ && do |
1075 { | 1758 { |
| 1759 last if (!$func_coverage); |
| 1760 |
1076 # Function call count found, add to structure | 1761 # Function call count found, add to structure |
1077 # Add summary counts | 1762 # Add summary counts |
1078 $sumfnccount->{$2} += $1; | 1763 $sumfnccount->{$2} += $1; |
1079 | 1764 |
1080 # Add test-specific counts | 1765 # Add test-specific counts |
1081 if (defined($testname)) | 1766 if (defined($testname)) |
1082 { | 1767 { |
1083 $testfnccount->{$2} += $1; | 1768 $testfnccount->{$2} += $1; |
1084 } | 1769 } |
1085 last; | 1770 last; |
1086 }; | 1771 }; |
| 1772 |
| 1773 /^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do { |
| 1774 # Branch coverage data found |
| 1775 my ($line, $block, $branch, $taken) = |
| 1776 ($1, $2, $3, $4); |
| 1777 |
| 1778 last if (!$br_coverage); |
| 1779 $sumbrcount->{$line} = |
| 1780 br_ivec_push($sumbrcount->{$line}, |
| 1781 $block, $branch, $taken); |
| 1782 |
| 1783 # Add test-specific counts |
| 1784 if (defined($testname)) { |
| 1785 $testbrcount->{$line} = |
| 1786 br_ivec_push( |
| 1787 $testbrcount->{$line}, |
| 1788 $block, $branch, |
| 1789 $taken); |
| 1790 } |
| 1791 last; |
| 1792 }; |
| 1793 |
1087 /^end_of_record/ && do | 1794 /^end_of_record/ && do |
1088 { | 1795 { |
1089 # Found end of section marker | 1796 # Found end of section marker |
1090 if ($filename) | 1797 if ($filename) |
1091 { | 1798 { |
1092 # Store current section data | 1799 # Store current section data |
1093 if (defined($testname)) | 1800 if (defined($testname)) |
1094 { | 1801 { |
1095 $testdata->{$testname} = | 1802 $testdata->{$testname} = |
1096 $testcount; | 1803 $testcount; |
1097 $testfncdata->{$testname} = | 1804 $testfncdata->{$testname} = |
1098 $testfnccount; | 1805 $testfnccount; |
| 1806 $testbrdata->{$testname} = |
| 1807 $testbrcount; |
1099 } | 1808 } |
1100 | 1809 |
1101 set_info_entry($data, $testdata, | 1810 set_info_entry($data, $testdata, |
1102 $sumcount, $funcdata, | 1811 $sumcount, $funcdata, |
1103 $checkdata, $testfncdata, | 1812 $checkdata, $testfncdata, |
1104 » » » » » » $sumfnccount); | 1813 » » » » » » $sumfnccount, |
| 1814 » » » » » » $testbrdata, |
| 1815 » » » » » » $sumbrcount); |
1105 $result{$filename} = $data; | 1816 $result{$filename} = $data; |
1106 last; | 1817 last; |
1107 } | 1818 } |
1108 }; | 1819 }; |
1109 | 1820 |
1110 # default | 1821 # default |
1111 last; | 1822 last; |
1112 } | 1823 } |
1113 } | 1824 } |
1114 close(INFO_HANDLE); | 1825 close(INFO_HANDLE); |
1115 | 1826 |
1116 # Calculate hit and found values for lines and functions of each file | 1827 # Calculate hit and found values for lines and functions of each file |
1117 foreach $filename (keys(%result)) | 1828 foreach $filename (keys(%result)) |
1118 { | 1829 { |
1119 $data = $result{$filename}; | 1830 $data = $result{$filename}; |
1120 | 1831 |
1121 ($testdata, $sumcount, undef, undef, $testfncdata, | 1832 ($testdata, $sumcount, undef, undef, $testfncdata, |
1122 » » $sumfnccount) = get_info_entry($data); | 1833 » » $sumfnccount, $testbrdata, $sumbrcount) = |
| 1834 » » » get_info_entry($data); |
1123 | 1835 |
1124 # Filter out empty files | 1836 # Filter out empty files |
1125 if (scalar(keys(%{$sumcount})) == 0) | 1837 if (scalar(keys(%{$sumcount})) == 0) |
1126 { | 1838 { |
1127 delete($result{$filename}); | 1839 delete($result{$filename}); |
1128 next; | 1840 next; |
1129 } | 1841 } |
1130 # Filter out empty test cases | 1842 # Filter out empty test cases |
1131 foreach $testname (keys(%{$testdata})) | 1843 foreach $testname (keys(%{$testdata})) |
1132 { | 1844 { |
(...skipping 18 matching lines...) Expand all Loading... |
1151 # Get found/hit values for function call data | 1863 # Get found/hit values for function call data |
1152 $data->{"f_found"} = scalar(keys(%{$sumfnccount})); | 1864 $data->{"f_found"} = scalar(keys(%{$sumfnccount})); |
1153 $hitcount = 0; | 1865 $hitcount = 0; |
1154 | 1866 |
1155 foreach (keys(%{$sumfnccount})) { | 1867 foreach (keys(%{$sumfnccount})) { |
1156 if ($sumfnccount->{$_} > 0) { | 1868 if ($sumfnccount->{$_} > 0) { |
1157 $hitcount++; | 1869 $hitcount++; |
1158 } | 1870 } |
1159 } | 1871 } |
1160 $data->{"f_hit"} = $hitcount; | 1872 $data->{"f_hit"} = $hitcount; |
| 1873 |
| 1874 # Get found/hit values for branch data |
| 1875 { |
| 1876 my ($br_found, $br_hit) = get_br_found_and_hit($sumbrcou
nt); |
| 1877 |
| 1878 $data->{"b_found"} = $br_found; |
| 1879 $data->{"b_hit"} = $br_hit; |
| 1880 } |
1161 } | 1881 } |
1162 | 1882 |
1163 if (scalar(keys(%result)) == 0) | 1883 if (scalar(keys(%result)) == 0) |
1164 { | 1884 { |
1165 die("ERROR: no valid records found in tracefile $tracefile\n"); | 1885 die("ERROR: no valid records found in tracefile $tracefile\n"); |
1166 } | 1886 } |
1167 if ($negative) | 1887 if ($negative) |
1168 { | 1888 { |
1169 warn("WARNING: negative counts found in tracefile ". | 1889 warn("WARNING: negative counts found in tracefile ". |
1170 "$tracefile\n"); | 1890 "$tracefile\n"); |
1171 } | 1891 } |
1172 if ($changed_testname) | 1892 if ($changed_testname) |
1173 { | 1893 { |
1174 warn("WARNING: invalid characters removed from testname in ". | 1894 warn("WARNING: invalid characters removed from testname in ". |
1175 "tracefile $tracefile\n"); | 1895 "tracefile $tracefile\n"); |
1176 } | 1896 } |
1177 | 1897 |
1178 return(\%result); | 1898 return(\%result); |
1179 } | 1899 } |
1180 | 1900 |
1181 | 1901 |
1182 # | 1902 # |
1183 # get_info_entry(hash_ref) | 1903 # get_info_entry(hash_ref) |
1184 # | 1904 # |
1185 # Retrieve data from an entry of the structure generated by read_info_file(). | 1905 # Retrieve data from an entry of the structure generated by read_info_file(). |
1186 # Return a list of references to hashes: | 1906 # Return a list of references to hashes: |
1187 # (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash | 1907 # (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash |
1188 # ref, testfncdata hash ref, sumfnccount hash ref, lines found, lines hit, | 1908 # ref, testfncdata hash ref, sumfnccount hash ref, testbrdata hash ref, |
1189 # functions found, functions hit) | 1909 # sumbrcount hash ref, lines found, lines hit, functions found, |
| 1910 # functions hit, branches found, branches hit) |
1190 # | 1911 # |
1191 | 1912 |
1192 sub get_info_entry($) | 1913 sub get_info_entry($) |
1193 { | 1914 { |
1194 my $testdata_ref = $_[0]->{"test"}; | 1915 my $testdata_ref = $_[0]->{"test"}; |
1195 my $sumcount_ref = $_[0]->{"sum"}; | 1916 my $sumcount_ref = $_[0]->{"sum"}; |
1196 my $funcdata_ref = $_[0]->{"func"}; | 1917 my $funcdata_ref = $_[0]->{"func"}; |
1197 my $checkdata_ref = $_[0]->{"check"}; | 1918 my $checkdata_ref = $_[0]->{"check"}; |
1198 my $testfncdata = $_[0]->{"testfnc"}; | 1919 my $testfncdata = $_[0]->{"testfnc"}; |
1199 my $sumfnccount = $_[0]->{"sumfnc"}; | 1920 my $sumfnccount = $_[0]->{"sumfnc"}; |
| 1921 my $testbrdata = $_[0]->{"testbr"}; |
| 1922 my $sumbrcount = $_[0]->{"sumbr"}; |
1200 my $lines_found = $_[0]->{"found"}; | 1923 my $lines_found = $_[0]->{"found"}; |
1201 my $lines_hit = $_[0]->{"hit"}; | 1924 my $lines_hit = $_[0]->{"hit"}; |
1202 my $f_found = $_[0]->{"f_found"}; | 1925 my $f_found = $_[0]->{"f_found"}; |
1203 my $f_hit = $_[0]->{"f_hit"}; | 1926 my $f_hit = $_[0]->{"f_hit"}; |
| 1927 my $br_found = $_[0]->{"b_found"}; |
| 1928 my $br_hit = $_[0]->{"b_hit"}; |
1204 | 1929 |
1205 return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref, | 1930 return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref, |
1206 » » $testfncdata, $sumfnccount, $lines_found, $lines_hit, | 1931 » » $testfncdata, $sumfnccount, $testbrdata, $sumbrcount, |
1207 » » $f_found, $f_hit); | 1932 » » $lines_found, $lines_hit, $f_found, $f_hit, |
| 1933 » » $br_found, $br_hit); |
1208 } | 1934 } |
1209 | 1935 |
1210 | 1936 |
1211 # | 1937 # |
1212 # set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref, | 1938 # set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref, |
1213 # checkdata_ref, testfncdata_ref, sumfcncount_ref[,lines_found, | 1939 # checkdata_ref, testfncdata_ref, sumfcncount_ref, |
1214 # lines_hit, f_found, f_hit]) | 1940 # testbrdata_ref, sumbrcount_ref[,lines_found, |
| 1941 # lines_hit, f_found, f_hit, $b_found, $b_hit]) |
1215 # | 1942 # |
1216 # Update the hash referenced by HASH_REF with the provided data references. | 1943 # Update the hash referenced by HASH_REF with the provided data references. |
1217 # | 1944 # |
1218 | 1945 |
1219 sub set_info_entry($$$$$$$;$$$$) | 1946 sub set_info_entry($$$$$$$$$;$$$$$$) |
1220 { | 1947 { |
1221 my $data_ref = $_[0]; | 1948 my $data_ref = $_[0]; |
1222 | 1949 |
1223 $data_ref->{"test"} = $_[1]; | 1950 $data_ref->{"test"} = $_[1]; |
1224 $data_ref->{"sum"} = $_[2]; | 1951 $data_ref->{"sum"} = $_[2]; |
1225 $data_ref->{"func"} = $_[3]; | 1952 $data_ref->{"func"} = $_[3]; |
1226 $data_ref->{"check"} = $_[4]; | 1953 $data_ref->{"check"} = $_[4]; |
1227 $data_ref->{"testfnc"} = $_[5]; | 1954 $data_ref->{"testfnc"} = $_[5]; |
1228 $data_ref->{"sumfnc"} = $_[6]; | 1955 $data_ref->{"sumfnc"} = $_[6]; |
| 1956 $data_ref->{"testbr"} = $_[7]; |
| 1957 $data_ref->{"sumbr"} = $_[8]; |
1229 | 1958 |
1230 » if (defined($_[7])) { $data_ref->{"found"} = $_[7]; } | 1959 » if (defined($_[9])) { $data_ref->{"found"} = $_[9]; } |
1231 » if (defined($_[8])) { $data_ref->{"hit"} = $_[8]; } | 1960 » if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; } |
1232 » if (defined($_[9])) { $data_ref->{"f_found"} = $_[9]; } | 1961 » if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; } |
1233 » if (defined($_[10])) { $data_ref->{"f_hit"} = $_[10]; } | 1962 » if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; } |
| 1963 » if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; } |
| 1964 » if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; } |
1234 } | 1965 } |
1235 | 1966 |
1236 | 1967 |
1237 # | 1968 # |
1238 # add_counts(data1_ref, data2_ref) | 1969 # add_counts(data1_ref, data2_ref) |
1239 # | 1970 # |
1240 # DATA1_REF and DATA2_REF are references to hashes containing a mapping | 1971 # DATA1_REF and DATA2_REF are references to hashes containing a mapping |
1241 # | 1972 # |
1242 # line number -> execution count | 1973 # line number -> execution count |
1243 # | 1974 # |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1331 # | 2062 # |
1332 # merge_func_data(funcdata1, funcdata2, filename) | 2063 # merge_func_data(funcdata1, funcdata2, filename) |
1333 # | 2064 # |
1334 | 2065 |
1335 sub merge_func_data($$$) | 2066 sub merge_func_data($$$) |
1336 { | 2067 { |
1337 my ($funcdata1, $funcdata2, $filename) = @_; | 2068 my ($funcdata1, $funcdata2, $filename) = @_; |
1338 my %result; | 2069 my %result; |
1339 my $func; | 2070 my $func; |
1340 | 2071 |
1341 » %result = %{$funcdata1}; | 2072 » if (defined($funcdata1)) { |
| 2073 » » %result = %{$funcdata1}; |
| 2074 » } |
1342 | 2075 |
1343 foreach $func (keys(%{$funcdata2})) { | 2076 foreach $func (keys(%{$funcdata2})) { |
1344 my $line1 = $result{$func}; | 2077 my $line1 = $result{$func}; |
1345 my $line2 = $funcdata2->{$func}; | 2078 my $line2 = $funcdata2->{$func}; |
1346 | 2079 |
1347 if (defined($line1) && ($line1 != $line2)) { | 2080 if (defined($line1) && ($line1 != $line2)) { |
1348 warn("WARNING: function data mismatch at ". | 2081 warn("WARNING: function data mismatch at ". |
1349 "$filename:$line2\n"); | 2082 "$filename:$line2\n"); |
1350 next; | 2083 next; |
1351 } | 2084 } |
(...skipping 11 matching lines...) Expand all Loading... |
1363 # | 2096 # |
1364 | 2097 |
1365 sub add_fnccount($$) | 2098 sub add_fnccount($$) |
1366 { | 2099 { |
1367 my ($fnccount1, $fnccount2) = @_; | 2100 my ($fnccount1, $fnccount2) = @_; |
1368 my %result; | 2101 my %result; |
1369 my $f_found; | 2102 my $f_found; |
1370 my $f_hit; | 2103 my $f_hit; |
1371 my $function; | 2104 my $function; |
1372 | 2105 |
1373 » %result = %{$fnccount1}; | 2106 » if (defined($fnccount1)) { |
| 2107 » » %result = %{$fnccount1}; |
| 2108 » } |
1374 foreach $function (keys(%{$fnccount2})) { | 2109 foreach $function (keys(%{$fnccount2})) { |
1375 $result{$function} += $fnccount2->{$function}; | 2110 $result{$function} += $fnccount2->{$function}; |
1376 } | 2111 } |
1377 $f_found = scalar(keys(%result)); | 2112 $f_found = scalar(keys(%result)); |
1378 $f_hit = 0; | 2113 $f_hit = 0; |
1379 foreach $function (keys(%result)) { | 2114 foreach $function (keys(%result)) { |
1380 if ($result{$function} > 0) { | 2115 if ($result{$function} > 0) { |
1381 $f_hit++; | 2116 $f_hit++; |
1382 } | 2117 } |
1383 } | 2118 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1417 | 2152 |
1418 # Add count data for testnames unique to data set 2 | 2153 # Add count data for testnames unique to data set 2 |
1419 foreach $testname (keys(%{$testfncdata2})) { | 2154 foreach $testname (keys(%{$testfncdata2})) { |
1420 if (!defined($result{$testname})) { | 2155 if (!defined($result{$testname})) { |
1421 $result{$testname} = $testfncdata2->{$testname}; | 2156 $result{$testname} = $testfncdata2->{$testname}; |
1422 } | 2157 } |
1423 } | 2158 } |
1424 return \%result; | 2159 return \%result; |
1425 } | 2160 } |
1426 | 2161 |
| 2162 |
| 2163 # |
| 2164 # brcount_to_db(brcount) |
| 2165 # |
| 2166 # Convert brcount data to the following format: |
| 2167 # |
| 2168 # db: line number -> block hash |
| 2169 # block hash: block number -> branch hash |
| 2170 # branch hash: branch number -> taken value |
| 2171 # |
| 2172 |
| 2173 sub brcount_to_db($) |
| 2174 { |
| 2175 my ($brcount) = @_; |
| 2176 my $line; |
| 2177 my $db; |
| 2178 |
| 2179 # Add branches from first count to database |
| 2180 foreach $line (keys(%{$brcount})) { |
| 2181 my $brdata = $brcount->{$line}; |
| 2182 my $i; |
| 2183 my $num = br_ivec_len($brdata); |
| 2184 |
| 2185 for ($i = 0; $i < $num; $i++) { |
| 2186 my ($block, $branch, $taken) = br_ivec_get($brdata, $i); |
| 2187 |
| 2188 $db->{$line}->{$block}->{$branch} = $taken; |
| 2189 } |
| 2190 } |
| 2191 |
| 2192 return $db; |
| 2193 } |
| 2194 |
| 2195 |
| 2196 # |
| 2197 # db_to_brcount(db) |
| 2198 # |
| 2199 # Convert branch coverage data back to brcount format. |
| 2200 # |
| 2201 |
| 2202 sub db_to_brcount($) |
| 2203 { |
| 2204 my ($db) = @_; |
| 2205 my $line; |
| 2206 my $brcount = {}; |
| 2207 my $br_found = 0; |
| 2208 my $br_hit = 0; |
| 2209 |
| 2210 # Convert database back to brcount format |
| 2211 foreach $line (sort({$a <=> $b} keys(%{$db}))) { |
| 2212 my $ldata = $db->{$line}; |
| 2213 my $brdata; |
| 2214 my $block; |
| 2215 |
| 2216 foreach $block (sort({$a <=> $b} keys(%{$ldata}))) { |
| 2217 my $bdata = $ldata->{$block}; |
| 2218 my $branch; |
| 2219 |
| 2220 foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) { |
| 2221 my $taken = $bdata->{$branch}; |
| 2222 |
| 2223 $br_found++; |
| 2224 $br_hit++ if ($taken ne "-" && $taken > 0); |
| 2225 $brdata = br_ivec_push($brdata, $block, |
| 2226 $branch, $taken); |
| 2227 } |
| 2228 } |
| 2229 $brcount->{$line} = $brdata; |
| 2230 } |
| 2231 |
| 2232 return ($brcount, $br_found, $br_hit); |
| 2233 } |
| 2234 |
| 2235 |
| 2236 # combine_brcount(brcount1, brcount2, type) |
| 2237 # |
| 2238 # If add is BR_ADD, add branch coverage data and return list (brcount_added, |
| 2239 # br_found, br_hit). If add is BR_SUB, subtract the taken values of brcount2 |
| 2240 # from brcount1 and return (brcount_sub, br_found, br_hit). |
| 2241 # |
| 2242 |
| 2243 sub combine_brcount($$$) |
| 2244 { |
| 2245 my ($brcount1, $brcount2, $type) = @_; |
| 2246 my $line; |
| 2247 my $block; |
| 2248 my $branch; |
| 2249 my $taken; |
| 2250 my $db; |
| 2251 my $br_found = 0; |
| 2252 my $br_hit = 0; |
| 2253 my $result; |
| 2254 |
| 2255 # Convert branches from first count to database |
| 2256 $db = brcount_to_db($brcount1); |
| 2257 # Combine values from database and second count |
| 2258 foreach $line (keys(%{$brcount2})) { |
| 2259 my $brdata = $brcount2->{$line}; |
| 2260 my $num = br_ivec_len($brdata); |
| 2261 my $i; |
| 2262 |
| 2263 for ($i = 0; $i < $num; $i++) { |
| 2264 ($block, $branch, $taken) = br_ivec_get($brdata, $i); |
| 2265 my $new_taken = $db->{$line}->{$block}->{$branch}; |
| 2266 |
| 2267 if ($type == $BR_ADD) { |
| 2268 $new_taken = br_taken_add($new_taken, $taken); |
| 2269 } elsif ($type == $BR_SUB) { |
| 2270 $new_taken = br_taken_sub($new_taken, $taken); |
| 2271 } |
| 2272 $db->{$line}->{$block}->{$branch} = $new_taken |
| 2273 if (defined($new_taken)); |
| 2274 } |
| 2275 } |
| 2276 # Convert database back to brcount format |
| 2277 ($result, $br_found, $br_hit) = db_to_brcount($db); |
| 2278 |
| 2279 return ($result, $br_found, $br_hit); |
| 2280 } |
| 2281 |
| 2282 |
| 2283 # |
| 2284 # add_testbrdata(testbrdata1, testbrdata2) |
| 2285 # |
| 2286 # Add branch coverage data for several tests. Return reference to |
| 2287 # added_testbrdata. |
| 2288 # |
| 2289 |
| 2290 sub add_testbrdata($$) |
| 2291 { |
| 2292 my ($testbrdata1, $testbrdata2) = @_; |
| 2293 my %result; |
| 2294 my $testname; |
| 2295 |
| 2296 foreach $testname (keys(%{$testbrdata1})) { |
| 2297 if (defined($testbrdata2->{$testname})) { |
| 2298 my $brcount; |
| 2299 |
| 2300 # Branch coverage data for this testname exists |
| 2301 # in both data sets: add |
| 2302 ($brcount) = combine_brcount( |
| 2303 $testbrdata1->{$testname}, |
| 2304 $testbrdata2->{$testname}, $BR_ADD); |
| 2305 $result{$testname} = $brcount; |
| 2306 next; |
| 2307 } |
| 2308 # Branch coverage data for this testname is unique to |
| 2309 # data set 1: copy |
| 2310 $result{$testname} = $testbrdata1->{$testname}; |
| 2311 } |
| 2312 |
| 2313 # Add count data for testnames unique to data set 2 |
| 2314 foreach $testname (keys(%{$testbrdata2})) { |
| 2315 if (!defined($result{$testname})) { |
| 2316 $result{$testname} = $testbrdata2->{$testname}; |
| 2317 } |
| 2318 } |
| 2319 return \%result; |
| 2320 } |
| 2321 |
| 2322 |
1427 # | 2323 # |
1428 # combine_info_entries(entry_ref1, entry_ref2, filename) | 2324 # combine_info_entries(entry_ref1, entry_ref2, filename) |
1429 # | 2325 # |
1430 # Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2. | 2326 # Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2. |
1431 # Return reference to resulting hash. | 2327 # Return reference to resulting hash. |
1432 # | 2328 # |
1433 | 2329 |
1434 sub combine_info_entries($$$) | 2330 sub combine_info_entries($$$) |
1435 { | 2331 { |
1436 my $entry1 = $_[0]; # Reference to hash containing first entry | 2332 my $entry1 = $_[0]; # Reference to hash containing first entry |
1437 my $testdata1; | 2333 my $testdata1; |
1438 my $sumcount1; | 2334 my $sumcount1; |
1439 my $funcdata1; | 2335 my $funcdata1; |
1440 my $checkdata1; | 2336 my $checkdata1; |
1441 my $testfncdata1; | 2337 my $testfncdata1; |
1442 my $sumfnccount1; | 2338 my $sumfnccount1; |
| 2339 my $testbrdata1; |
| 2340 my $sumbrcount1; |
1443 | 2341 |
1444 my $entry2 = $_[1]; # Reference to hash containing second entry | 2342 my $entry2 = $_[1]; # Reference to hash containing second entry |
1445 my $testdata2; | 2343 my $testdata2; |
1446 my $sumcount2; | 2344 my $sumcount2; |
1447 my $funcdata2; | 2345 my $funcdata2; |
1448 my $checkdata2; | 2346 my $checkdata2; |
1449 my $testfncdata2; | 2347 my $testfncdata2; |
1450 my $sumfnccount2; | 2348 my $sumfnccount2; |
| 2349 my $testbrdata2; |
| 2350 my $sumbrcount2; |
1451 | 2351 |
1452 my %result; # Hash containing combined entry | 2352 my %result; # Hash containing combined entry |
1453 my %result_testdata; | 2353 my %result_testdata; |
1454 my $result_sumcount = {}; | 2354 my $result_sumcount = {}; |
1455 my $result_funcdata; | 2355 my $result_funcdata; |
1456 my $result_testfncdata; | 2356 my $result_testfncdata; |
1457 my $result_sumfnccount; | 2357 my $result_sumfnccount; |
| 2358 my $result_testbrdata; |
| 2359 my $result_sumbrcount; |
1458 my $lines_found; | 2360 my $lines_found; |
1459 my $lines_hit; | 2361 my $lines_hit; |
1460 my $f_found; | 2362 my $f_found; |
1461 my $f_hit; | 2363 my $f_hit; |
| 2364 my $br_found; |
| 2365 my $br_hit; |
1462 | 2366 |
1463 my $testname; | 2367 my $testname; |
1464 my $filename = $_[2]; | 2368 my $filename = $_[2]; |
1465 | 2369 |
1466 # Retrieve data | 2370 # Retrieve data |
1467 ($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1, | 2371 ($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1, |
1468 » $sumfnccount1) = get_info_entry($entry1); | 2372 » $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1); |
1469 ($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2, | 2373 ($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2, |
1470 » $sumfnccount2) = get_info_entry($entry2); | 2374 » $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2); |
1471 | 2375 |
1472 # Merge checksums | 2376 # Merge checksums |
1473 $checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename); | 2377 $checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename); |
1474 | 2378 |
1475 # Combine funcdata | 2379 # Combine funcdata |
1476 $result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename); | 2380 $result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename); |
1477 | 2381 |
1478 # Combine function call count data | 2382 # Combine function call count data |
1479 $result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2); | 2383 $result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2); |
1480 ($result_sumfnccount, $f_found, $f_hit) = | 2384 ($result_sumfnccount, $f_found, $f_hit) = |
1481 add_fnccount($sumfnccount1, $sumfnccount2); | 2385 add_fnccount($sumfnccount1, $sumfnccount2); |
1482 » | 2386 |
| 2387 » # Combine branch coverage data |
| 2388 » $result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2); |
| 2389 » ($result_sumbrcount, $br_found, $br_hit) = |
| 2390 » » combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD); |
| 2391 |
1483 # Combine testdata | 2392 # Combine testdata |
1484 foreach $testname (keys(%{$testdata1})) | 2393 foreach $testname (keys(%{$testdata1})) |
1485 { | 2394 { |
1486 if (defined($testdata2->{$testname})) | 2395 if (defined($testdata2->{$testname})) |
1487 { | 2396 { |
1488 # testname is present in both entries, requires | 2397 # testname is present in both entries, requires |
1489 # combination | 2398 # combination |
1490 ($result_testdata{$testname}) = | 2399 ($result_testdata{$testname}) = |
1491 add_counts($testdata1->{$testname}, | 2400 add_counts($testdata1->{$testname}, |
1492 $testdata2->{$testname}); | 2401 $testdata2->{$testname}); |
(...skipping 22 matching lines...) Expand all Loading... |
1515 ($result_sumcount, $lines_found, $lines_hit) = | 2424 ($result_sumcount, $lines_found, $lines_hit) = |
1516 add_counts($result_sumcount, | 2425 add_counts($result_sumcount, |
1517 $result_testdata{$testname}); | 2426 $result_testdata{$testname}); |
1518 } | 2427 } |
1519 | 2428 |
1520 # Calculate resulting sumcount | 2429 # Calculate resulting sumcount |
1521 | 2430 |
1522 # Store result | 2431 # Store result |
1523 set_info_entry(\%result, \%result_testdata, $result_sumcount, | 2432 set_info_entry(\%result, \%result_testdata, $result_sumcount, |
1524 $result_funcdata, $checkdata1, $result_testfncdata, | 2433 $result_funcdata, $checkdata1, $result_testfncdata, |
1525 » » $result_sumfnccount, $lines_found, $lines_hit, | 2434 » » $result_sumfnccount, $result_testbrdata, |
1526 » » $f_found, $f_hit); | 2435 » » $result_sumbrcount, $lines_found, $lines_hit, |
| 2436 » » $f_found, $f_hit, $br_found, $br_hit); |
1527 | 2437 |
1528 return(\%result); | 2438 return(\%result); |
1529 } | 2439 } |
1530 | 2440 |
1531 | 2441 |
1532 # | 2442 # |
1533 # combine_info_files(info_ref1, info_ref2) | 2443 # combine_info_files(info_ref1, info_ref2) |
1534 # | 2444 # |
1535 # Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return | 2445 # Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return |
1536 # reference to resulting hash. | 2446 # reference to resulting hash. |
(...skipping 29 matching lines...) Expand all Loading... |
1566 | 2476 |
1567 # | 2477 # |
1568 # add_traces() | 2478 # add_traces() |
1569 # | 2479 # |
1570 | 2480 |
1571 sub add_traces() | 2481 sub add_traces() |
1572 { | 2482 { |
1573 my $total_trace; | 2483 my $total_trace; |
1574 my $current_trace; | 2484 my $current_trace; |
1575 my $tracefile; | 2485 my $tracefile; |
| 2486 my @result; |
1576 local *INFO_HANDLE; | 2487 local *INFO_HANDLE; |
1577 | 2488 |
1578 info("Combining tracefiles.\n"); | 2489 info("Combining tracefiles.\n"); |
1579 | 2490 |
1580 foreach $tracefile (@add_tracefile) | 2491 foreach $tracefile (@add_tracefile) |
1581 { | 2492 { |
1582 $current_trace = read_info_file($tracefile); | 2493 $current_trace = read_info_file($tracefile); |
1583 if ($total_trace) | 2494 if ($total_trace) |
1584 { | 2495 { |
1585 $total_trace = combine_info_files($total_trace, | 2496 $total_trace = combine_info_files($total_trace, |
1586 $current_trace); | 2497 $current_trace); |
1587 } | 2498 } |
1588 else | 2499 else |
1589 { | 2500 { |
1590 $total_trace = $current_trace; | 2501 $total_trace = $current_trace; |
1591 } | 2502 } |
1592 } | 2503 } |
1593 | 2504 |
1594 # Write combined data | 2505 # Write combined data |
1595 if ($to_file) | 2506 if ($to_file) |
1596 { | 2507 { |
1597 info("Writing data to $output_filename\n"); | 2508 info("Writing data to $output_filename\n"); |
1598 » » open(INFO_HANDLE, ">$output_filename") | 2509 » » open(INFO_HANDLE, ">", $output_filename) |
1599 or die("ERROR: cannot write to $output_filename!\n"); | 2510 or die("ERROR: cannot write to $output_filename!\n"); |
1600 » » write_info_file(*INFO_HANDLE, $total_trace); | 2511 » » @result = write_info_file(*INFO_HANDLE, $total_trace); |
1601 close(*INFO_HANDLE); | 2512 close(*INFO_HANDLE); |
1602 } | 2513 } |
1603 else | 2514 else |
1604 { | 2515 { |
1605 » » write_info_file(*STDOUT, $total_trace); | 2516 » » @result = write_info_file(*STDOUT, $total_trace); |
1606 } | 2517 } |
| 2518 |
| 2519 return @result; |
1607 } | 2520 } |
1608 | 2521 |
1609 | 2522 |
1610 # | 2523 # |
1611 # write_info_file(filehandle, data) | 2524 # write_info_file(filehandle, data) |
1612 # | 2525 # |
1613 | 2526 |
1614 sub write_info_file(*$) | 2527 sub write_info_file(*$) |
1615 { | 2528 { |
1616 local *INFO_HANDLE = $_[0]; | 2529 local *INFO_HANDLE = $_[0]; |
1617 my %data = %{$_[1]}; | 2530 my %data = %{$_[1]}; |
1618 my $source_file; | 2531 my $source_file; |
1619 my $entry; | 2532 my $entry; |
1620 my $testdata; | 2533 my $testdata; |
1621 my $sumcount; | 2534 my $sumcount; |
1622 my $funcdata; | 2535 my $funcdata; |
1623 my $checkdata; | 2536 my $checkdata; |
1624 my $testfncdata; | 2537 my $testfncdata; |
1625 my $sumfnccount; | 2538 my $sumfnccount; |
| 2539 my $testbrdata; |
| 2540 my $sumbrcount; |
1626 my $testname; | 2541 my $testname; |
1627 my $line; | 2542 my $line; |
1628 my $func; | 2543 my $func; |
1629 my $testcount; | 2544 my $testcount; |
1630 my $testfnccount; | 2545 my $testfnccount; |
| 2546 my $testbrcount; |
1631 my $found; | 2547 my $found; |
1632 my $hit; | 2548 my $hit; |
1633 my $f_found; | 2549 my $f_found; |
1634 my $f_hit; | 2550 my $f_hit; |
| 2551 my $br_found; |
| 2552 my $br_hit; |
| 2553 my $ln_total_found = 0; |
| 2554 my $ln_total_hit = 0; |
| 2555 my $fn_total_found = 0; |
| 2556 my $fn_total_hit = 0; |
| 2557 my $br_total_found = 0; |
| 2558 my $br_total_hit = 0; |
1635 | 2559 |
1636 » foreach $source_file (keys(%data)) | 2560 » foreach $source_file (sort(keys(%data))) |
1637 { | 2561 { |
1638 $entry = $data{$source_file}; | 2562 $entry = $data{$source_file}; |
1639 ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata, | 2563 ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata, |
1640 » » $sumfnccount) = get_info_entry($entry); | 2564 » » $sumfnccount, $testbrdata, $sumbrcount, $found, $hit, |
1641 » » foreach $testname (keys(%{$testdata})) | 2565 » » $f_found, $f_hit, $br_found, $br_hit) = |
| 2566 » » » get_info_entry($entry); |
| 2567 |
| 2568 » » # Add to totals |
| 2569 » » $ln_total_found += $found; |
| 2570 » » $ln_total_hit += $hit; |
| 2571 » » $fn_total_found += $f_found; |
| 2572 » » $fn_total_hit += $f_hit; |
| 2573 » » $br_total_found += $br_found; |
| 2574 » » $br_total_hit += $br_hit; |
| 2575 |
| 2576 » » foreach $testname (sort(keys(%{$testdata}))) |
1642 { | 2577 { |
1643 $testcount = $testdata->{$testname}; | 2578 $testcount = $testdata->{$testname}; |
1644 $testfnccount = $testfncdata->{$testname}; | 2579 $testfnccount = $testfncdata->{$testname}; |
| 2580 $testbrcount = $testbrdata->{$testname}; |
1645 $found = 0; | 2581 $found = 0; |
1646 $hit = 0; | 2582 $hit = 0; |
1647 | 2583 |
1648 print(INFO_HANDLE "TN:$testname\n"); | 2584 print(INFO_HANDLE "TN:$testname\n"); |
1649 print(INFO_HANDLE "SF:$source_file\n"); | 2585 print(INFO_HANDLE "SF:$source_file\n"); |
1650 | 2586 |
1651 # Write function related data | 2587 # Write function related data |
1652 foreach $func ( | 2588 foreach $func ( |
1653 sort({$funcdata->{$a} <=> $funcdata->{$b}} | 2589 sort({$funcdata->{$a} <=> $funcdata->{$b}} |
1654 keys(%{$funcdata}))) | 2590 keys(%{$funcdata}))) |
1655 { | 2591 { |
1656 print(INFO_HANDLE "FN:".$funcdata->{$func}. | 2592 print(INFO_HANDLE "FN:".$funcdata->{$func}. |
1657 ",$func\n"); | 2593 ",$func\n"); |
1658 } | 2594 } |
1659 foreach $func (keys(%{$testfnccount})) { | 2595 foreach $func (keys(%{$testfnccount})) { |
1660 print(INFO_HANDLE "FNDA:". | 2596 print(INFO_HANDLE "FNDA:". |
1661 $testfnccount->{$func}. | 2597 $testfnccount->{$func}. |
1662 ",$func\n"); | 2598 ",$func\n"); |
1663 } | 2599 } |
1664 ($f_found, $f_hit) = | 2600 ($f_found, $f_hit) = |
1665 get_func_found_and_hit($testfnccount); | 2601 get_func_found_and_hit($testfnccount); |
1666 print(INFO_HANDLE "FNF:$f_found\n"); | 2602 print(INFO_HANDLE "FNF:$f_found\n"); |
1667 print(INFO_HANDLE "FNH:$f_hit\n"); | 2603 print(INFO_HANDLE "FNH:$f_hit\n"); |
1668 | 2604 |
| 2605 # Write branch related data |
| 2606 $br_found = 0; |
| 2607 $br_hit = 0; |
| 2608 foreach $line (sort({$a <=> $b} |
| 2609 keys(%{$testbrcount}))) { |
| 2610 my $brdata = $testbrcount->{$line}; |
| 2611 my $num = br_ivec_len($brdata); |
| 2612 my $i; |
| 2613 |
| 2614 for ($i = 0; $i < $num; $i++) { |
| 2615 my ($block, $branch, $taken) = |
| 2616 br_ivec_get($brdata, $i); |
| 2617 |
| 2618 print(INFO_HANDLE "BRDA:$line,$block,". |
| 2619 "$branch,$taken\n"); |
| 2620 $br_found++; |
| 2621 $br_hit++ if ($taken ne '-' && |
| 2622 $taken > 0); |
| 2623 } |
| 2624 } |
| 2625 if ($br_found > 0) { |
| 2626 print(INFO_HANDLE "BRF:$br_found\n"); |
| 2627 print(INFO_HANDLE "BRH:$br_hit\n"); |
| 2628 } |
| 2629 |
1669 # Write line related data | 2630 # Write line related data |
1670 foreach $line (sort({$a <=> $b} keys(%{$testcount}))) | 2631 foreach $line (sort({$a <=> $b} keys(%{$testcount}))) |
1671 { | 2632 { |
1672 print(INFO_HANDLE "DA:$line,". | 2633 print(INFO_HANDLE "DA:$line,". |
1673 $testcount->{$line}. | 2634 $testcount->{$line}. |
1674 (defined($checkdata->{$line}) && | 2635 (defined($checkdata->{$line}) && |
1675 $checksum ? | 2636 $checksum ? |
1676 ",".$checkdata->{$line} : "")."\n"); | 2637 ",".$checkdata->{$line} : "")."\n"); |
1677 $found++; | 2638 $found++; |
1678 if ($testcount->{$line} > 0) | 2639 if ($testcount->{$line} > 0) |
1679 { | 2640 { |
1680 $hit++; | 2641 $hit++; |
1681 } | 2642 } |
1682 | 2643 |
1683 } | 2644 } |
1684 print(INFO_HANDLE "LF:$found\n"); | 2645 print(INFO_HANDLE "LF:$found\n"); |
1685 print(INFO_HANDLE "LH:$hit\n"); | 2646 print(INFO_HANDLE "LH:$hit\n"); |
1686 print(INFO_HANDLE "end_of_record\n"); | 2647 print(INFO_HANDLE "end_of_record\n"); |
1687 } | 2648 } |
1688 } | 2649 } |
| 2650 |
| 2651 return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit, |
| 2652 $br_total_found, $br_total_hit); |
1689 } | 2653 } |
1690 | 2654 |
1691 | 2655 |
1692 # | 2656 # |
1693 # transform_pattern(pattern) | 2657 # transform_pattern(pattern) |
1694 # | 2658 # |
1695 # Transform shell wildcard expression to equivalent PERL regular expression. | 2659 # Transform shell wildcard expression to equivalent Perl regular expression. |
1696 # Return transformed pattern. | 2660 # Return transformed pattern. |
1697 # | 2661 # |
1698 | 2662 |
1699 sub transform_pattern($) | 2663 sub transform_pattern($) |
1700 { | 2664 { |
1701 my $pattern = $_[0]; | 2665 my $pattern = $_[0]; |
1702 | 2666 |
1703 # Escape special chars | 2667 # Escape special chars |
1704 | 2668 |
1705 $pattern =~ s/\\/\\\\/g; | 2669 $pattern =~ s/\\/\\\\/g; |
(...skipping 26 matching lines...) Expand all Loading... |
1732 # | 2696 # |
1733 | 2697 |
1734 sub extract() | 2698 sub extract() |
1735 { | 2699 { |
1736 my $data = read_info_file($extract); | 2700 my $data = read_info_file($extract); |
1737 my $filename; | 2701 my $filename; |
1738 my $keep; | 2702 my $keep; |
1739 my $pattern; | 2703 my $pattern; |
1740 my @pattern_list; | 2704 my @pattern_list; |
1741 my $extracted = 0; | 2705 my $extracted = 0; |
| 2706 my @result; |
1742 local *INFO_HANDLE; | 2707 local *INFO_HANDLE; |
1743 | 2708 |
1744 # Need perlreg expressions instead of shell pattern | 2709 # Need perlreg expressions instead of shell pattern |
1745 @pattern_list = map({ transform_pattern($_); } @ARGV); | 2710 @pattern_list = map({ transform_pattern($_); } @ARGV); |
1746 | 2711 |
1747 # Filter out files which do not match any pattern | 2712 # Filter out files which do not match any pattern |
1748 foreach $filename (sort(keys(%{$data}))) | 2713 foreach $filename (sort(keys(%{$data}))) |
1749 { | 2714 { |
1750 $keep = 0; | 2715 $keep = 0; |
1751 | 2716 |
(...skipping 12 matching lines...) Expand all Loading... |
1764 info("Extracting $filename\n"), | 2729 info("Extracting $filename\n"), |
1765 $extracted++; | 2730 $extracted++; |
1766 } | 2731 } |
1767 } | 2732 } |
1768 | 2733 |
1769 # Write extracted data | 2734 # Write extracted data |
1770 if ($to_file) | 2735 if ($to_file) |
1771 { | 2736 { |
1772 info("Extracted $extracted files\n"); | 2737 info("Extracted $extracted files\n"); |
1773 info("Writing data to $output_filename\n"); | 2738 info("Writing data to $output_filename\n"); |
1774 » » open(INFO_HANDLE, ">$output_filename") | 2739 » » open(INFO_HANDLE, ">", $output_filename) |
1775 or die("ERROR: cannot write to $output_filename!\n"); | 2740 or die("ERROR: cannot write to $output_filename!\n"); |
1776 » » write_info_file(*INFO_HANDLE, $data); | 2741 » » @result = write_info_file(*INFO_HANDLE, $data); |
1777 close(*INFO_HANDLE); | 2742 close(*INFO_HANDLE); |
1778 } | 2743 } |
1779 else | 2744 else |
1780 { | 2745 { |
1781 » » write_info_file(*STDOUT, $data); | 2746 » » @result = write_info_file(*STDOUT, $data); |
1782 } | 2747 } |
| 2748 |
| 2749 return @result; |
1783 } | 2750 } |
1784 | 2751 |
1785 | 2752 |
1786 # | 2753 # |
1787 # remove() | 2754 # remove() |
1788 # | 2755 # |
1789 | 2756 |
1790 sub remove() | 2757 sub remove() |
1791 { | 2758 { |
1792 my $data = read_info_file($remove); | 2759 my $data = read_info_file($remove); |
1793 my $filename; | 2760 my $filename; |
1794 my $match_found; | 2761 my $match_found; |
1795 my $pattern; | 2762 my $pattern; |
1796 my @pattern_list; | 2763 my @pattern_list; |
1797 my $removed = 0; | 2764 my $removed = 0; |
| 2765 my @result; |
1798 local *INFO_HANDLE; | 2766 local *INFO_HANDLE; |
1799 | 2767 |
1800 # Need perlreg expressions instead of shell pattern | 2768 # Need perlreg expressions instead of shell pattern |
1801 @pattern_list = map({ transform_pattern($_); } @ARGV); | 2769 @pattern_list = map({ transform_pattern($_); } @ARGV); |
1802 | 2770 |
1803 # Filter out files that match the pattern | 2771 # Filter out files that match the pattern |
1804 foreach $filename (sort(keys(%{$data}))) | 2772 foreach $filename (sort(keys(%{$data}))) |
1805 { | 2773 { |
1806 $match_found = 0; | 2774 $match_found = 0; |
1807 | 2775 |
1808 foreach $pattern (@pattern_list) | 2776 foreach $pattern (@pattern_list) |
1809 { | 2777 { |
1810 $match_found ||= ($filename =~ (/$pattern$/)); | 2778 $match_found ||= ($filename =~ (/$pattern$/)); |
1811 } | 2779 } |
1812 | 2780 |
1813 | 2781 |
1814 if ($match_found) | 2782 if ($match_found) |
1815 { | 2783 { |
1816 delete($data->{$filename}); | 2784 delete($data->{$filename}); |
1817 info("Removing $filename\n"), | 2785 info("Removing $filename\n"), |
1818 $removed++; | 2786 $removed++; |
1819 } | 2787 } |
1820 } | 2788 } |
1821 | 2789 |
1822 # Write data | 2790 # Write data |
1823 if ($to_file) | 2791 if ($to_file) |
1824 { | 2792 { |
1825 info("Deleted $removed files\n"); | 2793 info("Deleted $removed files\n"); |
1826 info("Writing data to $output_filename\n"); | 2794 info("Writing data to $output_filename\n"); |
1827 » » open(INFO_HANDLE, ">$output_filename") | 2795 » » open(INFO_HANDLE, ">", $output_filename) |
1828 or die("ERROR: cannot write to $output_filename!\n"); | 2796 or die("ERROR: cannot write to $output_filename!\n"); |
1829 » » write_info_file(*INFO_HANDLE, $data); | 2797 » » @result = write_info_file(*INFO_HANDLE, $data); |
1830 close(*INFO_HANDLE); | 2798 close(*INFO_HANDLE); |
1831 } | 2799 } |
1832 else | 2800 else |
1833 { | 2801 { |
1834 » » write_info_file(*STDOUT, $data); | 2802 » » @result = write_info_file(*STDOUT, $data); |
1835 } | 2803 } |
| 2804 |
| 2805 return @result; |
| 2806 } |
| 2807 |
| 2808 |
| 2809 # get_prefix(max_width, max_percentage_too_long, path_list) |
| 2810 # |
| 2811 # Return a path prefix that satisfies the following requirements: |
| 2812 # - is shared by more paths in path_list than any other prefix |
| 2813 # - the percentage of paths which would exceed the given max_width length |
| 2814 # after applying the prefix does not exceed max_percentage_too_long |
| 2815 # |
| 2816 # If multiple prefixes satisfy all requirements, the longest prefix is |
| 2817 # returned. Return an empty string if no prefix could be found. |
| 2818 |
| 2819 sub get_prefix($$@) |
| 2820 { |
| 2821 my ($max_width, $max_long, @path_list) = @_; |
| 2822 my $path; |
| 2823 my $ENTRY_NUM = 0; |
| 2824 my $ENTRY_LONG = 1; |
| 2825 my %prefix; |
| 2826 |
| 2827 # Build prefix hash |
| 2828 foreach $path (@path_list) { |
| 2829 my ($v, $d, $f) = splitpath($path); |
| 2830 my @dirs = splitdir($d); |
| 2831 my $p_len = length($path); |
| 2832 my $i; |
| 2833 |
| 2834 # Remove trailing '/' |
| 2835 pop(@dirs) if ($dirs[scalar(@dirs) - 1] eq ''); |
| 2836 for ($i = 0; $i < scalar(@dirs); $i++) { |
| 2837 my $subpath = catpath($v, catdir(@dirs[0..$i]), ''); |
| 2838 my $entry = $prefix{$subpath}; |
| 2839 |
| 2840 $entry = [ 0, 0 ] if (!defined($entry)); |
| 2841 $entry->[$ENTRY_NUM]++; |
| 2842 if (($p_len - length($subpath) - 1) > $max_width) { |
| 2843 $entry->[$ENTRY_LONG]++; |
| 2844 } |
| 2845 $prefix{$subpath} = $entry; |
| 2846 } |
| 2847 } |
| 2848 # Find suitable prefix (sort descending by two keys: 1. number of |
| 2849 # entries covered by a prefix, 2. length of prefix) |
| 2850 foreach $path (sort {($prefix{$a}->[$ENTRY_NUM] == |
| 2851 $prefix{$b}->[$ENTRY_NUM]) ? |
| 2852 length($b) <=> length($a) : |
| 2853 $prefix{$b}->[$ENTRY_NUM] <=> |
| 2854 $prefix{$a}->[$ENTRY_NUM]} |
| 2855 keys(%prefix)) { |
| 2856 my ($num, $long) = @{$prefix{$path}}; |
| 2857 |
| 2858 # Check for additional requirement: number of filenames |
| 2859 # that would be too long may not exceed a certain percentage |
| 2860 if ($long <= $num * $max_long / 100) { |
| 2861 return $path; |
| 2862 } |
| 2863 } |
| 2864 |
| 2865 return ""; |
1836 } | 2866 } |
1837 | 2867 |
1838 | 2868 |
1839 # | 2869 # |
| 2870 # shorten_filename(filename, width) |
| 2871 # |
| 2872 # Truncate filename if it is longer than width characters. |
| 2873 # |
| 2874 |
| 2875 sub shorten_filename($$) |
| 2876 { |
| 2877 my ($filename, $width) = @_; |
| 2878 my $l = length($filename); |
| 2879 my $s; |
| 2880 my $e; |
| 2881 |
| 2882 return $filename if ($l <= $width); |
| 2883 $e = int(($width - 3) / 2); |
| 2884 $s = $width - 3 - $e; |
| 2885 |
| 2886 return substr($filename, 0, $s).'...'.substr($filename, $l - $e); |
| 2887 } |
| 2888 |
| 2889 |
| 2890 sub shorten_number($$) |
| 2891 { |
| 2892 my ($number, $width) = @_; |
| 2893 my $result = sprintf("%*d", $width, $number); |
| 2894 |
| 2895 return $result if (length($result) <= $width); |
| 2896 $number = $number / 1000; |
| 2897 return $result if (length($result) <= $width); |
| 2898 $result = sprintf("%*dk", $width - 1, $number); |
| 2899 return $result if (length($result) <= $width); |
| 2900 $number = $number / 1000; |
| 2901 $result = sprintf("%*dM", $width - 1, $number); |
| 2902 return $result if (length($result) <= $width); |
| 2903 return '#'; |
| 2904 } |
| 2905 |
| 2906 sub shorten_rate($$$) |
| 2907 { |
| 2908 my ($hit, $found, $width) = @_; |
| 2909 my $result = rate($hit, $found, "%", 1, $width); |
| 2910 |
| 2911 return $result if (length($result) <= $width); |
| 2912 $result = rate($hit, $found, "%", 0, $width); |
| 2913 return $result if (length($result) <= $width); |
| 2914 return "#"; |
| 2915 } |
| 2916 |
| 2917 # |
1840 # list() | 2918 # list() |
1841 # | 2919 # |
1842 | 2920 |
1843 sub list() | 2921 sub list() |
1844 { | 2922 { |
1845 my $data = read_info_file($list); | 2923 my $data = read_info_file($list); |
1846 my $filename; | 2924 my $filename; |
1847 my $found; | 2925 my $found; |
1848 my $hit; | 2926 my $hit; |
1849 my $entry; | 2927 my $entry; |
1850 | 2928 » my $fn_found; |
1851 » info("Listing contents of $list:\n"); | 2929 » my $fn_hit; |
1852 | 2930 » my $br_found; |
1853 » # List all files | 2931 » my $br_hit; |
| 2932 » my $total_found = 0; |
| 2933 » my $total_hit = 0; |
| 2934 » my $fn_total_found = 0; |
| 2935 » my $fn_total_hit = 0; |
| 2936 » my $br_total_found = 0; |
| 2937 » my $br_total_hit = 0; |
| 2938 » my $prefix; |
| 2939 » my $strlen = length("Filename"); |
| 2940 » my $format; |
| 2941 » my $heading1; |
| 2942 » my $heading2; |
| 2943 » my @footer; |
| 2944 » my $barlen; |
| 2945 » my $rate; |
| 2946 » my $fnrate; |
| 2947 » my $brrate; |
| 2948 » my $lastpath; |
| 2949 » my $F_LN_NUM = 0; |
| 2950 » my $F_LN_RATE = 1; |
| 2951 » my $F_FN_NUM = 2; |
| 2952 » my $F_FN_RATE = 3; |
| 2953 » my $F_BR_NUM = 4; |
| 2954 » my $F_BR_RATE = 5; |
| 2955 » my @fwidth_narrow = (5, 5, 3, 5, 4, 5); |
| 2956 » my @fwidth_wide = (6, 5, 5, 5, 6, 5); |
| 2957 » my @fwidth = @fwidth_wide; |
| 2958 » my $w; |
| 2959 » my $max_width = $opt_list_width; |
| 2960 » my $max_long = $opt_list_truncate_max; |
| 2961 » my $fwidth_narrow_length; |
| 2962 » my $fwidth_wide_length; |
| 2963 » my $got_prefix = 0; |
| 2964 » my $root_prefix = 0; |
| 2965 |
| 2966 » # Calculate total width of narrow fields |
| 2967 » $fwidth_narrow_length = 0; |
| 2968 » foreach $w (@fwidth_narrow) { |
| 2969 » » $fwidth_narrow_length += $w + 1; |
| 2970 » } |
| 2971 » # Calculate total width of wide fields |
| 2972 » $fwidth_wide_length = 0; |
| 2973 » foreach $w (@fwidth_wide) { |
| 2974 » » $fwidth_wide_length += $w + 1; |
| 2975 » } |
| 2976 » # Get common file path prefix |
| 2977 » $prefix = get_prefix($max_width - $fwidth_narrow_length, $max_long, |
| 2978 » » » keys(%{$data})); |
| 2979 » $root_prefix = 1 if ($prefix eq rootdir()); |
| 2980 » $got_prefix = 1 if (length($prefix) > 0); |
| 2981 » $prefix =~ s/\/$//; |
| 2982 » # Get longest filename length |
| 2983 » foreach $filename (keys(%{$data})) { |
| 2984 » » if (!$opt_list_full_path) { |
| 2985 » » » if (!$got_prefix || !$root_prefix && |
| 2986 » » » !($filename =~ s/^\Q$prefix\/\E//)) { |
| 2987 » » » » my ($v, $d, $f) = splitpath($filename); |
| 2988 |
| 2989 » » » » $filename = $f; |
| 2990 » » » } |
| 2991 » » } |
| 2992 » » # Determine maximum length of entries |
| 2993 » » if (length($filename) > $strlen) { |
| 2994 » » » $strlen = length($filename) |
| 2995 » » } |
| 2996 » } |
| 2997 » if (!$opt_list_full_path) { |
| 2998 » » my $blanks; |
| 2999 |
| 3000 » » $w = $fwidth_wide_length; |
| 3001 » » # Check if all columns fit into max_width characters |
| 3002 » » if ($strlen + $fwidth_wide_length > $max_width) { |
| 3003 » » » # Use narrow fields |
| 3004 » » » @fwidth = @fwidth_narrow; |
| 3005 » » » $w = $fwidth_narrow_length; |
| 3006 » » » if (($strlen + $fwidth_narrow_length) > $max_width) { |
| 3007 » » » » # Truncate filenames at max width |
| 3008 » » » » $strlen = $max_width - $fwidth_narrow_length; |
| 3009 » » » } |
| 3010 » » } |
| 3011 » » # Add some blanks between filename and fields if possible |
| 3012 » » $blanks = int($strlen * 0.5); |
| 3013 » » $blanks = 4 if ($blanks < 4); |
| 3014 » » $blanks = 8 if ($blanks > 8); |
| 3015 » » if (($strlen + $w + $blanks) < $max_width) { |
| 3016 » » » $strlen += $blanks; |
| 3017 » » } else { |
| 3018 » » » $strlen = $max_width - $w; |
| 3019 » » } |
| 3020 » } |
| 3021 » # Filename |
| 3022 » $w = $strlen; |
| 3023 » $format»» = "%-${w}s|"; |
| 3024 » $heading1 » = sprintf("%*s|", $w, ""); |
| 3025 » $heading2 » = sprintf("%-*s|", $w, "Filename"); |
| 3026 » $barlen»» = $w + 1; |
| 3027 » # Line coverage rate |
| 3028 » $w = $fwidth[$F_LN_RATE]; |
| 3029 » $format»» .= "%${w}s "; |
| 3030 » $heading1 » .= sprintf("%-*s |", $w + $fwidth[$F_LN_NUM], |
| 3031 » » » » "Lines"); |
| 3032 » $heading2 » .= sprintf("%-*s ", $w, "Rate"); |
| 3033 » $barlen»» += $w + 1; |
| 3034 » # Number of lines |
| 3035 » $w = $fwidth[$F_LN_NUM]; |
| 3036 » $format»» .= "%${w}s|"; |
| 3037 » $heading2» .= sprintf("%*s|", $w, "Num"); |
| 3038 » $barlen»» += $w + 1; |
| 3039 » # Function coverage rate |
| 3040 » $w = $fwidth[$F_FN_RATE]; |
| 3041 » $format»» .= "%${w}s "; |
| 3042 » $heading1 » .= sprintf("%-*s|", $w + $fwidth[$F_FN_NUM] + 1, |
| 3043 » » » » "Functions"); |
| 3044 » $heading2 » .= sprintf("%-*s ", $w, "Rate"); |
| 3045 » $barlen»» += $w + 1; |
| 3046 » # Number of functions |
| 3047 » $w = $fwidth[$F_FN_NUM]; |
| 3048 » $format»» .= "%${w}s|"; |
| 3049 » $heading2» .= sprintf("%*s|", $w, "Num"); |
| 3050 » $barlen»» += $w + 1; |
| 3051 » # Branch coverage rate |
| 3052 » $w = $fwidth[$F_BR_RATE]; |
| 3053 » $format»» .= "%${w}s "; |
| 3054 » $heading1 » .= sprintf("%-*s", $w + $fwidth[$F_BR_NUM] + 1, |
| 3055 » » » » "Branches"); |
| 3056 » $heading2 » .= sprintf("%-*s ", $w, "Rate"); |
| 3057 » $barlen»» += $w + 1; |
| 3058 » # Number of branches |
| 3059 » $w = $fwidth[$F_BR_NUM]; |
| 3060 » $format»» .= "%${w}s"; |
| 3061 » $heading2» .= sprintf("%*s", $w, "Num"); |
| 3062 » $barlen»» += $w; |
| 3063 » # Line end |
| 3064 » $format»» .= "\n"; |
| 3065 » $heading1» .= "\n"; |
| 3066 » $heading2» .= "\n"; |
| 3067 |
| 3068 » # Print heading |
| 3069 » print($heading1); |
| 3070 » print($heading2); |
| 3071 » print(("="x$barlen)."\n"); |
| 3072 |
| 3073 » # Print per file information |
1854 foreach $filename (sort(keys(%{$data}))) | 3074 foreach $filename (sort(keys(%{$data}))) |
1855 { | 3075 { |
| 3076 my @file_data; |
| 3077 my $print_filename = $filename; |
| 3078 |
1856 $entry = $data->{$filename}; | 3079 $entry = $data->{$filename}; |
1857 » » (undef, undef, undef, undef, undef, undef, $found, $hit) = | 3080 » » if (!$opt_list_full_path) { |
| 3081 » » » my $p; |
| 3082 |
| 3083 » » » $print_filename = $filename; |
| 3084 » » » if (!$got_prefix || !$root_prefix && |
| 3085 » » » !($print_filename =~ s/^\Q$prefix\/\E//)) { |
| 3086 » » » » my ($v, $d, $f) = splitpath($filename); |
| 3087 |
| 3088 » » » » $p = catpath($v, $d, ""); |
| 3089 » » » » $p =~ s/\/$//; |
| 3090 » » » » $print_filename = $f; |
| 3091 » » » } else { |
| 3092 » » » » $p = $prefix; |
| 3093 » » » } |
| 3094 |
| 3095 » » » if (!defined($lastpath) || $lastpath ne $p) { |
| 3096 » » » » print("\n") if (defined($lastpath)); |
| 3097 » » » » $lastpath = $p; |
| 3098 » » » » print("[$lastpath/]\n") if (!$root_prefix); |
| 3099 » » » } |
| 3100 » » » $print_filename = shorten_filename($print_filename, |
| 3101 » » » » » » » $strlen); |
| 3102 » » } |
| 3103 |
| 3104 » » (undef, undef, undef, undef, undef, undef, undef, undef, |
| 3105 » » $found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) = |
1858 get_info_entry($entry); | 3106 get_info_entry($entry); |
1859 » » printf("$filename: $hit of $found lines hit\n"); | 3107 |
1860 » } | 3108 » » # Assume zero count if there is no function data for this file |
| 3109 » » if (!defined($fn_found) || !defined($fn_hit)) { |
| 3110 » » » $fn_found = 0; |
| 3111 » » » $fn_hit = 0; |
| 3112 » » } |
| 3113 » » # Assume zero count if there is no branch data for this file |
| 3114 » » if (!defined($br_found) || !defined($br_hit)) { |
| 3115 » » » $br_found = 0; |
| 3116 » » » $br_hit = 0; |
| 3117 » » } |
| 3118 |
| 3119 » » # Add line coverage totals |
| 3120 » » $total_found += $found; |
| 3121 » » $total_hit += $hit; |
| 3122 » » # Add function coverage totals |
| 3123 » » $fn_total_found += $fn_found; |
| 3124 » » $fn_total_hit += $fn_hit; |
| 3125 » » # Add branch coverage totals |
| 3126 » » $br_total_found += $br_found; |
| 3127 » » $br_total_hit += $br_hit; |
| 3128 |
| 3129 » » # Determine line coverage rate for this file |
| 3130 » » $rate = shorten_rate($hit, $found, $fwidth[$F_LN_RATE]); |
| 3131 » » # Determine function coverage rate for this file |
| 3132 » » $fnrate = shorten_rate($fn_hit, $fn_found, $fwidth[$F_FN_RATE]); |
| 3133 » » # Determine branch coverage rate for this file |
| 3134 » » $brrate = shorten_rate($br_hit, $br_found, $fwidth[$F_BR_RATE]); |
| 3135 |
| 3136 » » # Assemble line parameters |
| 3137 » » push(@file_data, $print_filename); |
| 3138 » » push(@file_data, $rate); |
| 3139 » » push(@file_data, shorten_number($found, $fwidth[$F_LN_NUM])); |
| 3140 » » push(@file_data, $fnrate); |
| 3141 » » push(@file_data, shorten_number($fn_found, $fwidth[$F_FN_NUM])); |
| 3142 » » push(@file_data, $brrate); |
| 3143 » » push(@file_data, shorten_number($br_found, $fwidth[$F_BR_NUM])); |
| 3144 |
| 3145 » » # Print assembled line |
| 3146 » » printf($format, @file_data); |
| 3147 » } |
| 3148 |
| 3149 » # Determine total line coverage rate |
| 3150 » $rate = shorten_rate($total_hit, $total_found, $fwidth[$F_LN_RATE]); |
| 3151 » # Determine total function coverage rate |
| 3152 » $fnrate = shorten_rate($fn_total_hit, $fn_total_found, |
| 3153 » » » $fwidth[$F_FN_RATE]); |
| 3154 » # Determine total branch coverage rate |
| 3155 » $brrate = shorten_rate($br_total_hit, $br_total_found, |
| 3156 » » » $fwidth[$F_BR_RATE]); |
| 3157 |
| 3158 » # Print separator |
| 3159 » print(("="x$barlen)."\n"); |
| 3160 |
| 3161 » # Assemble line parameters |
| 3162 » push(@footer, sprintf("%*s", $strlen, "Total:")); |
| 3163 » push(@footer, $rate); |
| 3164 » push(@footer, shorten_number($total_found, $fwidth[$F_LN_NUM])); |
| 3165 » push(@footer, $fnrate); |
| 3166 » push(@footer, shorten_number($fn_total_found, $fwidth[$F_FN_NUM])); |
| 3167 » push(@footer, $brrate); |
| 3168 » push(@footer, shorten_number($br_total_found, $fwidth[$F_BR_NUM])); |
| 3169 |
| 3170 » # Print assembled line |
| 3171 » printf($format, @footer); |
1861 } | 3172 } |
1862 | 3173 |
1863 | 3174 |
1864 # | 3175 # |
1865 # get_common_filename(filename1, filename2) | 3176 # get_common_filename(filename1, filename2) |
1866 # | 3177 # |
1867 # Check for filename components which are common to FILENAME1 and FILENAME2. | 3178 # Check for filename components which are common to FILENAME1 and FILENAME2. |
1868 # Upon success, return | 3179 # Upon success, return |
1869 # | 3180 # |
1870 # (common, path1, path2) | 3181 # (common, path1, path2) |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1974 # Check for availability of GZIP tool | 3285 # Check for availability of GZIP tool |
1975 system_no_output(1, "gunzip", "-h") | 3286 system_no_output(1, "gunzip", "-h") |
1976 and die("ERROR: gunzip command not available!\n"); | 3287 and die("ERROR: gunzip command not available!\n"); |
1977 | 3288 |
1978 # Check integrity of compressed file | 3289 # Check integrity of compressed file |
1979 system_no_output(1, "gunzip", "-t", $diff_file) | 3290 system_no_output(1, "gunzip", "-t", $diff_file) |
1980 and die("ERROR: integrity check failed for ". | 3291 and die("ERROR: integrity check failed for ". |
1981 "compressed file $diff_file!\n"); | 3292 "compressed file $diff_file!\n"); |
1982 | 3293 |
1983 # Open compressed file | 3294 # Open compressed file |
1984 » » open(HANDLE, "gunzip -c $diff_file|") | 3295 » » open(HANDLE, "-|", "gunzip -c '$diff_file'") |
1985 or die("ERROR: cannot start gunzip to decompress ". | 3296 or die("ERROR: cannot start gunzip to decompress ". |
1986 "file $_[0]!\n"); | 3297 "file $_[0]!\n"); |
1987 } | 3298 } |
1988 else | 3299 else |
1989 { | 3300 { |
1990 # Open decompressed file | 3301 # Open decompressed file |
1991 » » open(HANDLE, $diff_file) | 3302 » » open(HANDLE, "<", $diff_file) |
1992 or die("ERROR: cannot read file $_[0]!\n"); | 3303 or die("ERROR: cannot read file $_[0]!\n"); |
1993 } | 3304 } |
1994 | 3305 |
1995 # Parse diff file line by line | 3306 # Parse diff file line by line |
1996 while (<HANDLE>) | 3307 while (<HANDLE>) |
1997 { | 3308 { |
1998 chomp($_); | 3309 chomp($_); |
1999 $line = $_; | 3310 $line = $_; |
2000 | 3311 |
2001 foreach ($line) | 3312 foreach ($line) |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2148 } | 3459 } |
2149 # Copy data to new hash with an offset | 3460 # Copy data to new hash with an offset |
2150 $result{$_ + ($last_new - $last_old)} = $count_data->{$_}; | 3461 $result{$_ + ($last_new - $last_old)} = $count_data->{$_}; |
2151 } | 3462 } |
2152 | 3463 |
2153 return \%result; | 3464 return \%result; |
2154 } | 3465 } |
2155 | 3466 |
2156 | 3467 |
2157 # | 3468 # |
| 3469 # apply_diff_to_brcount(brcount, linedata) |
| 3470 # |
| 3471 # Adjust line numbers of branch coverage data according to linedata. |
| 3472 # |
| 3473 |
| 3474 sub apply_diff_to_brcount($$) |
| 3475 { |
| 3476 my ($brcount, $linedata) = @_; |
| 3477 my $db; |
| 3478 |
| 3479 # Convert brcount to db format |
| 3480 $db = brcount_to_db($brcount); |
| 3481 # Apply diff to db format |
| 3482 $db = apply_diff($db, $linedata); |
| 3483 # Convert db format back to brcount format |
| 3484 ($brcount) = db_to_brcount($db); |
| 3485 |
| 3486 return $brcount; |
| 3487 } |
| 3488 |
| 3489 |
| 3490 # |
2158 # get_hash_max(hash_ref) | 3491 # get_hash_max(hash_ref) |
2159 # | 3492 # |
2160 # Return the highest integer key from hash. | 3493 # Return the highest integer key from hash. |
2161 # | 3494 # |
2162 | 3495 |
2163 sub get_hash_max($) | 3496 sub get_hash_max($) |
2164 { | 3497 { |
2165 my ($hash) = @_; | 3498 my ($hash) = @_; |
2166 my $max; | 3499 my $max; |
2167 | 3500 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2228 my $diff_data = $_[1]; | 3561 my $diff_data = $_[1]; |
2229 my $path_data = $_[2]; | 3562 my $path_data = $_[2]; |
2230 my $conversion; | 3563 my $conversion; |
2231 my $old_path; | 3564 my $old_path; |
2232 my $new_path; | 3565 my $new_path; |
2233 my $diff_name; | 3566 my $diff_name; |
2234 my $common; | 3567 my $common; |
2235 my $old_depth; | 3568 my $old_depth; |
2236 my $new_depth; | 3569 my $new_depth; |
2237 | 3570 |
| 3571 # Remove trailing slash from diff path |
| 3572 $diff_path =~ s/\/$//; |
2238 foreach (keys(%{$diff_data})) | 3573 foreach (keys(%{$diff_data})) |
2239 { | 3574 { |
| 3575 my $sep = ""; |
| 3576 |
| 3577 $sep = '/' if (!/^\//); |
| 3578 |
2240 # Try to match diff filename with filename | 3579 # Try to match diff filename with filename |
2241 » » if ($filename =~ /^\Q$diff_path\E\/$_$/) | 3580 » » if ($filename =~ /^\Q$diff_path$sep$_\E$/) |
2242 { | 3581 { |
2243 if ($diff_name) | 3582 if ($diff_name) |
2244 { | 3583 { |
2245 # Two files match, choose the more specific one | 3584 # Two files match, choose the more specific one |
2246 # (the one with more path components) | 3585 # (the one with more path components) |
2247 $old_depth = ($diff_name =~ tr/\///); | 3586 $old_depth = ($diff_name =~ tr/\///); |
2248 $new_depth = (tr/\///); | 3587 $new_depth = (tr/\///); |
2249 if ($old_depth == $new_depth) | 3588 if ($old_depth == $new_depth) |
2250 { | 3589 { |
2251 die("ERROR: diff file contains ". | 3590 die("ERROR: diff file contains ". |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2425 my $line_hash; | 3764 my $line_hash; |
2426 my $new_name; | 3765 my $new_name; |
2427 my $entry; | 3766 my $entry; |
2428 my $testdata; | 3767 my $testdata; |
2429 my $testname; | 3768 my $testname; |
2430 my $sumcount; | 3769 my $sumcount; |
2431 my $funcdata; | 3770 my $funcdata; |
2432 my $checkdata; | 3771 my $checkdata; |
2433 my $testfncdata; | 3772 my $testfncdata; |
2434 my $sumfnccount; | 3773 my $sumfnccount; |
| 3774 my $testbrdata; |
| 3775 my $sumbrcount; |
2435 my $found; | 3776 my $found; |
2436 my $hit; | 3777 my $hit; |
2437 my $f_found; | 3778 my $f_found; |
2438 my $f_hit; | 3779 my $f_hit; |
| 3780 my $br_found; |
| 3781 my $br_hit; |
2439 my $converted = 0; | 3782 my $converted = 0; |
2440 my $unchanged = 0; | 3783 my $unchanged = 0; |
| 3784 my @result; |
2441 local *INFO_HANDLE; | 3785 local *INFO_HANDLE; |
2442 | 3786 |
2443 ($diff_data, $path_data) = read_diff($ARGV[0]); | 3787 ($diff_data, $path_data) = read_diff($ARGV[0]); |
2444 | 3788 |
2445 foreach $filename (sort(keys(%{$trace_data}))) | 3789 foreach $filename (sort(keys(%{$trace_data}))) |
2446 { | 3790 { |
2447 # Find a diff section corresponding to this file | 3791 # Find a diff section corresponding to this file |
2448 ($line_hash, $old_path, $new_path) = | 3792 ($line_hash, $old_path, $new_path) = |
2449 get_line_hash($filename, $diff_data, $path_data); | 3793 get_line_hash($filename, $diff_data, $path_data); |
2450 if (!$line_hash) | 3794 if (!$line_hash) |
(...skipping 10 matching lines...) Expand all Loading... |
2461 # Check for deleted files | 3805 # Check for deleted files |
2462 if (scalar(keys(%{$line_hash})) == 0) | 3806 if (scalar(keys(%{$line_hash})) == 0) |
2463 { | 3807 { |
2464 info("Removing $filename\n"); | 3808 info("Removing $filename\n"); |
2465 delete($trace_data->{$filename}); | 3809 delete($trace_data->{$filename}); |
2466 next; | 3810 next; |
2467 } | 3811 } |
2468 info("Converting $filename\n"); | 3812 info("Converting $filename\n"); |
2469 $entry = $trace_data->{$filename}; | 3813 $entry = $trace_data->{$filename}; |
2470 ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata, | 3814 ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata, |
2471 » » $sumfnccount) = get_info_entry($entry); | 3815 » » $sumfnccount, $testbrdata, $sumbrcount) = |
| 3816 » » » get_info_entry($entry); |
2472 # Convert test data | 3817 # Convert test data |
2473 foreach $testname (keys(%{$testdata})) | 3818 foreach $testname (keys(%{$testdata})) |
2474 { | 3819 { |
| 3820 # Adjust line numbers of line coverage data |
2475 $testdata->{$testname} = | 3821 $testdata->{$testname} = |
2476 apply_diff($testdata->{$testname}, $line_hash); | 3822 apply_diff($testdata->{$testname}, $line_hash); |
| 3823 # Adjust line numbers of branch coverage data |
| 3824 $testbrdata->{$testname} = |
| 3825 apply_diff_to_brcount($testbrdata->{$testname}, |
| 3826 $line_hash); |
2477 # Remove empty sets of test data | 3827 # Remove empty sets of test data |
2478 if (scalar(keys(%{$testdata->{$testname}})) == 0) | 3828 if (scalar(keys(%{$testdata->{$testname}})) == 0) |
2479 { | 3829 { |
2480 delete($testdata->{$testname}); | 3830 delete($testdata->{$testname}); |
2481 delete($testfncdata->{$testname}); | 3831 delete($testfncdata->{$testname}); |
| 3832 delete($testbrdata->{$testname}); |
2482 } | 3833 } |
2483 } | 3834 } |
2484 # Rename test data to indicate conversion | 3835 # Rename test data to indicate conversion |
2485 foreach $testname (keys(%{$testdata})) | 3836 foreach $testname (keys(%{$testdata})) |
2486 { | 3837 { |
2487 # Skip testnames which already contain an extension | 3838 # Skip testnames which already contain an extension |
2488 if ($testname =~ /,[^,]+$/) | 3839 if ($testname =~ /,[^,]+$/) |
2489 { | 3840 { |
2490 next; | 3841 next; |
2491 } | 3842 } |
2492 # Check for name conflict | 3843 # Check for name conflict |
2493 if (defined($testdata->{$testname.",diff"})) | 3844 if (defined($testdata->{$testname.",diff"})) |
2494 { | 3845 { |
2495 # Add counts | 3846 # Add counts |
2496 ($testdata->{$testname}) = add_counts( | 3847 ($testdata->{$testname}) = add_counts( |
2497 $testdata->{$testname}, | 3848 $testdata->{$testname}, |
2498 $testdata->{$testname.",diff"}); | 3849 $testdata->{$testname.",diff"}); |
2499 delete($testdata->{$testname.",diff"}); | 3850 delete($testdata->{$testname.",diff"}); |
2500 # Add function call counts | 3851 # Add function call counts |
2501 ($testfncdata->{$testname}) = add_fnccount( | 3852 ($testfncdata->{$testname}) = add_fnccount( |
2502 $testfncdata->{$testname}, | 3853 $testfncdata->{$testname}, |
2503 $testfncdata->{$testname.",diff"}); | 3854 $testfncdata->{$testname.",diff"}); |
2504 delete($testfncdata->{$testname.",diff"}); | 3855 delete($testfncdata->{$testname.",diff"}); |
| 3856 # Add branch counts |
| 3857 ($testbrdata->{$testname}) = combine_brcount( |
| 3858 $testbrdata->{$testname}, |
| 3859 $testbrdata->{$testname.",diff"}, |
| 3860 $BR_ADD); |
| 3861 delete($testbrdata->{$testname.",diff"}); |
2505 } | 3862 } |
2506 # Move test data to new testname | 3863 # Move test data to new testname |
2507 $testdata->{$testname.",diff"} = $testdata->{$testname}; | 3864 $testdata->{$testname.",diff"} = $testdata->{$testname}; |
2508 delete($testdata->{$testname}); | 3865 delete($testdata->{$testname}); |
2509 # Move function call count data to new testname | 3866 # Move function call count data to new testname |
2510 $testfncdata->{$testname.",diff"} = | 3867 $testfncdata->{$testname.",diff"} = |
2511 $testfncdata->{$testname}; | 3868 $testfncdata->{$testname}; |
2512 delete($testfncdata->{$testname}); | 3869 delete($testfncdata->{$testname}); |
| 3870 # Move branch count data to new testname |
| 3871 $testbrdata->{$testname.",diff"} = |
| 3872 $testbrdata->{$testname}; |
| 3873 delete($testbrdata->{$testname}); |
2513 } | 3874 } |
2514 # Convert summary of test data | 3875 # Convert summary of test data |
2515 $sumcount = apply_diff($sumcount, $line_hash); | 3876 $sumcount = apply_diff($sumcount, $line_hash); |
2516 # Convert function data | 3877 # Convert function data |
2517 $funcdata = apply_diff_to_funcdata($funcdata, $line_hash); | 3878 $funcdata = apply_diff_to_funcdata($funcdata, $line_hash); |
| 3879 # Convert branch coverage data |
| 3880 $sumbrcount = apply_diff_to_brcount($sumbrcount, $line_hash); |
| 3881 # Update found/hit numbers |
2518 # Convert checksum data | 3882 # Convert checksum data |
2519 $checkdata = apply_diff($checkdata, $line_hash); | 3883 $checkdata = apply_diff($checkdata, $line_hash); |
2520 # Convert function call count data | 3884 # Convert function call count data |
2521 adjust_fncdata($funcdata, $testfncdata, $sumfnccount); | 3885 adjust_fncdata($funcdata, $testfncdata, $sumfnccount); |
2522 ($f_found, $f_hit) = get_func_found_and_hit($sumfnccount); | 3886 ($f_found, $f_hit) = get_func_found_and_hit($sumfnccount); |
| 3887 ($br_found, $br_hit) = get_br_found_and_hit($sumbrcount); |
2523 # Update found/hit numbers | 3888 # Update found/hit numbers |
2524 $found = 0; | 3889 $found = 0; |
2525 $hit = 0; | 3890 $hit = 0; |
2526 foreach (keys(%{$sumcount})) | 3891 foreach (keys(%{$sumcount})) |
2527 { | 3892 { |
2528 $found++; | 3893 $found++; |
2529 if ($sumcount->{$_} > 0) | 3894 if ($sumcount->{$_} > 0) |
2530 { | 3895 { |
2531 $hit++; | 3896 $hit++; |
2532 } | 3897 } |
2533 } | 3898 } |
2534 if ($found > 0) | 3899 if ($found > 0) |
2535 { | 3900 { |
2536 # Store converted entry | 3901 # Store converted entry |
2537 set_info_entry($entry, $testdata, $sumcount, $funcdata, | 3902 set_info_entry($entry, $testdata, $sumcount, $funcdata, |
2538 $checkdata, $testfncdata, $sumfnccount, | 3903 $checkdata, $testfncdata, $sumfnccount, |
2539 » » » » $found, $hit, $f_found, $f_hit); | 3904 » » » » $testbrdata, $sumbrcount, $found, $hit, |
| 3905 » » » » $f_found, $f_hit, $br_found, $br_hit); |
2540 } | 3906 } |
2541 else | 3907 else |
2542 { | 3908 { |
2543 # Remove empty data set | 3909 # Remove empty data set |
2544 delete($trace_data->{$filename}); | 3910 delete($trace_data->{$filename}); |
2545 } | 3911 } |
2546 } | 3912 } |
2547 | 3913 |
2548 # Convert filenames as well if requested | 3914 # Convert filenames as well if requested |
2549 if ($convert_filenames) | 3915 if ($convert_filenames) |
2550 { | 3916 { |
2551 convert_paths($trace_data, \%path_conversion_data); | 3917 convert_paths($trace_data, \%path_conversion_data); |
2552 } | 3918 } |
2553 | 3919 |
2554 info("$converted entr".($converted != 1 ? "ies" : "y")." converted, ". | 3920 info("$converted entr".($converted != 1 ? "ies" : "y")." converted, ". |
2555 "$unchanged entr".($unchanged != 1 ? "ies" : "y")." left ". | 3921 "$unchanged entr".($unchanged != 1 ? "ies" : "y")." left ". |
2556 "unchanged.\n"); | 3922 "unchanged.\n"); |
2557 | 3923 |
2558 # Write data | 3924 # Write data |
2559 if ($to_file) | 3925 if ($to_file) |
2560 { | 3926 { |
2561 info("Writing data to $output_filename\n"); | 3927 info("Writing data to $output_filename\n"); |
2562 » » open(INFO_HANDLE, ">$output_filename") | 3928 » » open(INFO_HANDLE, ">", $output_filename) |
2563 or die("ERROR: cannot write to $output_filename!\n"); | 3929 or die("ERROR: cannot write to $output_filename!\n"); |
2564 » » write_info_file(*INFO_HANDLE, $trace_data); | 3930 » » @result = write_info_file(*INFO_HANDLE, $trace_data); |
2565 close(*INFO_HANDLE); | 3931 close(*INFO_HANDLE); |
2566 } | 3932 } |
2567 else | 3933 else |
2568 { | 3934 { |
2569 » » write_info_file(*STDOUT, $trace_data); | 3935 » » @result = write_info_file(*STDOUT, $trace_data); |
2570 } | 3936 } |
| 3937 |
| 3938 return @result; |
2571 } | 3939 } |
2572 | 3940 |
| 3941 # |
| 3942 # summary() |
| 3943 # |
| 3944 |
| 3945 sub summary() |
| 3946 { |
| 3947 my $filename; |
| 3948 my $current; |
| 3949 my $total; |
| 3950 my $ln_total_found; |
| 3951 my $ln_total_hit; |
| 3952 my $fn_total_found; |
| 3953 my $fn_total_hit; |
| 3954 my $br_total_found; |
| 3955 my $br_total_hit; |
| 3956 |
| 3957 # Read and combine trace files |
| 3958 foreach $filename (@opt_summary) { |
| 3959 $current = read_info_file($filename); |
| 3960 if (!defined($total)) { |
| 3961 $total = $current; |
| 3962 } else { |
| 3963 $total = combine_info_files($total, $current); |
| 3964 } |
| 3965 } |
| 3966 # Calculate coverage data |
| 3967 foreach $filename (keys(%{$total})) |
| 3968 { |
| 3969 my $entry = $total->{$filename}; |
| 3970 my $ln_found; |
| 3971 my $ln_hit; |
| 3972 my $fn_found; |
| 3973 my $fn_hit; |
| 3974 my $br_found; |
| 3975 my $br_hit; |
| 3976 |
| 3977 (undef, undef, undef, undef, undef, undef, undef, undef, |
| 3978 $ln_found, $ln_hit, $fn_found, $fn_hit, $br_found, |
| 3979 $br_hit) = get_info_entry($entry); |
| 3980 |
| 3981 # Add to totals |
| 3982 $ln_total_found += $ln_found; |
| 3983 $ln_total_hit += $ln_hit; |
| 3984 $fn_total_found += $fn_found; |
| 3985 $fn_total_hit += $fn_hit; |
| 3986 $br_total_found += $br_found; |
| 3987 $br_total_hit += $br_hit; |
| 3988 } |
| 3989 |
| 3990 |
| 3991 return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit, |
| 3992 $br_total_found, $br_total_hit); |
| 3993 } |
2573 | 3994 |
2574 # | 3995 # |
2575 # system_no_output(mode, parameters) | 3996 # system_no_output(mode, parameters) |
2576 # | 3997 # |
2577 # Call an external program using PARAMETERS while suppressing depending on | 3998 # Call an external program using PARAMETERS while suppressing depending on |
2578 # the value of MODE: | 3999 # the value of MODE: |
2579 # | 4000 # |
2580 # MODE & 1: suppress STDOUT | 4001 # MODE & 1: suppress STDOUT |
2581 # MODE & 2: suppress STDERR | 4002 # MODE & 2: suppress STDERR |
2582 # | 4003 # |
2583 # Return 0 on success, non-zero otherwise. | 4004 # Return 0 on success, non-zero otherwise. |
2584 # | 4005 # |
2585 | 4006 |
2586 sub system_no_output($@) | 4007 sub system_no_output($@) |
2587 { | 4008 { |
2588 my $mode = shift; | 4009 my $mode = shift; |
2589 my $result; | 4010 my $result; |
2590 local *OLD_STDERR; | 4011 local *OLD_STDERR; |
2591 local *OLD_STDOUT; | 4012 local *OLD_STDOUT; |
2592 | 4013 |
2593 # Save old stdout and stderr handles | 4014 # Save old stdout and stderr handles |
2594 » ($mode & 1) && open(OLD_STDOUT, ">>&STDOUT"); | 4015 » ($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT"); |
2595 » ($mode & 2) && open(OLD_STDERR, ">>&STDERR"); | 4016 » ($mode & 2) && open(OLD_STDERR, ">>&", "STDERR"); |
2596 | 4017 |
2597 # Redirect to /dev/null | 4018 # Redirect to /dev/null |
2598 » ($mode & 1) && open(STDOUT, ">/dev/null"); | 4019 » ($mode & 1) && open(STDOUT, ">", "/dev/null"); |
2599 » ($mode & 2) && open(STDERR, ">/dev/null"); | 4020 » ($mode & 2) && open(STDERR, ">", "/dev/null"); |
2600 | 4021 |
2601 system(@_); | 4022 system(@_); |
2602 $result = $?; | 4023 $result = $?; |
2603 | 4024 |
2604 # Close redirected handles | 4025 # Close redirected handles |
2605 ($mode & 1) && close(STDOUT); | 4026 ($mode & 1) && close(STDOUT); |
2606 ($mode & 2) && close(STDERR); | 4027 ($mode & 2) && close(STDERR); |
2607 | 4028 |
2608 # Restore old handles | 4029 # Restore old handles |
2609 » ($mode & 1) && open(STDOUT, ">>&OLD_STDOUT"); | 4030 » ($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT"); |
2610 » ($mode & 2) && open(STDERR, ">>&OLD_STDERR"); | 4031 » ($mode & 2) && open(STDERR, ">>&", "OLD_STDERR"); |
2611 | 4032 |
2612 return $result; | 4033 return $result; |
2613 } | 4034 } |
2614 | 4035 |
2615 | 4036 |
2616 # | 4037 # |
2617 # read_config(filename) | 4038 # read_config(filename) |
2618 # | 4039 # |
2619 # Read configuration file FILENAME and return a reference to a hash containing | 4040 # Read configuration file FILENAME and return a reference to a hash containing |
2620 # all valid key=value pairs found. | 4041 # all valid key=value pairs found. |
2621 # | 4042 # |
2622 | 4043 |
2623 sub read_config($) | 4044 sub read_config($) |
2624 { | 4045 { |
2625 my $filename = $_[0]; | 4046 my $filename = $_[0]; |
2626 my %result; | 4047 my %result; |
2627 my $key; | 4048 my $key; |
2628 my $value; | 4049 my $value; |
2629 local *HANDLE; | 4050 local *HANDLE; |
2630 | 4051 |
2631 » if (!open(HANDLE, "<$filename")) | 4052 » if (!open(HANDLE, "<", $filename)) |
2632 { | 4053 { |
2633 warn("WARNING: cannot read configuration file $filename\n"); | 4054 warn("WARNING: cannot read configuration file $filename\n"); |
2634 return undef; | 4055 return undef; |
2635 } | 4056 } |
2636 while (<HANDLE>) | 4057 while (<HANDLE>) |
2637 { | 4058 { |
2638 chomp; | 4059 chomp; |
2639 # Skip comments | 4060 # Skip comments |
2640 s/#.*//; | 4061 s/#.*//; |
2641 # Remove leading blanks | 4062 # Remove leading blanks |
(...skipping 18 matching lines...) Expand all Loading... |
2660 | 4081 |
2661 | 4082 |
2662 # | 4083 # |
2663 # apply_config(REF) | 4084 # apply_config(REF) |
2664 # | 4085 # |
2665 # REF is a reference to a hash containing the following mapping: | 4086 # REF is a reference to a hash containing the following mapping: |
2666 # | 4087 # |
2667 # key_string => var_ref | 4088 # key_string => var_ref |
2668 # | 4089 # |
2669 # where KEY_STRING is a keyword and VAR_REF is a reference to an associated | 4090 # where KEY_STRING is a keyword and VAR_REF is a reference to an associated |
2670 # variable. If the global configuration hash CONFIG contains a value for | 4091 # variable. If the global configuration hashes CONFIG or OPT_RC contain a value |
2671 # keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. | 4092 # for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. |
2672 # | 4093 # |
2673 | 4094 |
2674 sub apply_config($) | 4095 sub apply_config($) |
2675 { | 4096 { |
2676 my $ref = $_[0]; | 4097 my $ref = $_[0]; |
2677 | 4098 |
2678 foreach (keys(%{$ref})) | 4099 foreach (keys(%{$ref})) |
2679 { | 4100 { |
2680 » » if (defined($config->{$_})) | 4101 » » if (defined($opt_rc{$_})) { |
2681 » » { | 4102 » » » ${$ref->{$_}} = $opt_rc{$_}; |
| 4103 » » } elsif (defined($config->{$_})) { |
2682 ${$ref->{$_}} = $config->{$_}; | 4104 ${$ref->{$_}} = $config->{$_}; |
2683 } | 4105 } |
2684 } | 4106 } |
2685 } | 4107 } |
2686 | 4108 |
2687 sub warn_handler($) | 4109 sub warn_handler($) |
2688 { | 4110 { |
2689 my ($msg) = @_; | 4111 my ($msg) = @_; |
2690 | 4112 |
| 4113 temp_cleanup(); |
2691 warn("$tool_name: $msg"); | 4114 warn("$tool_name: $msg"); |
2692 } | 4115 } |
2693 | 4116 |
2694 sub die_handler($) | 4117 sub die_handler($) |
2695 { | 4118 { |
2696 my ($msg) = @_; | 4119 my ($msg) = @_; |
2697 | 4120 |
| 4121 temp_cleanup(); |
2698 die("$tool_name: $msg"); | 4122 die("$tool_name: $msg"); |
2699 } | 4123 } |
| 4124 |
| 4125 sub abort_handler($) |
| 4126 { |
| 4127 temp_cleanup(); |
| 4128 exit(1); |
| 4129 } |
| 4130 |
| 4131 sub temp_cleanup() |
| 4132 { |
| 4133 if (@temp_dirs) { |
| 4134 info("Removing temporary directories.\n"); |
| 4135 foreach (@temp_dirs) { |
| 4136 rmtree($_); |
| 4137 } |
| 4138 @temp_dirs = (); |
| 4139 } |
| 4140 } |
| 4141 |
| 4142 sub setup_gkv_sys() |
| 4143 { |
| 4144 system_no_output(3, "mount", "-t", "debugfs", "nodev", |
| 4145 "/sys/kernel/debug"); |
| 4146 } |
| 4147 |
| 4148 sub setup_gkv_proc() |
| 4149 { |
| 4150 if (system_no_output(3, "modprobe", "gcov_proc")) { |
| 4151 system_no_output(3, "modprobe", "gcov_prof"); |
| 4152 } |
| 4153 } |
| 4154 |
| 4155 sub check_gkv_sys($) |
| 4156 { |
| 4157 my ($dir) = @_; |
| 4158 |
| 4159 if (-e "$dir/reset") { |
| 4160 return 1; |
| 4161 } |
| 4162 return 0; |
| 4163 } |
| 4164 |
| 4165 sub check_gkv_proc($) |
| 4166 { |
| 4167 my ($dir) = @_; |
| 4168 |
| 4169 if (-e "$dir/vmlinux") { |
| 4170 return 1; |
| 4171 } |
| 4172 return 0; |
| 4173 } |
| 4174 |
| 4175 sub setup_gkv() |
| 4176 { |
| 4177 my $dir; |
| 4178 my $sys_dir = "/sys/kernel/debug/gcov"; |
| 4179 my $proc_dir = "/proc/gcov"; |
| 4180 my @todo; |
| 4181 |
| 4182 if (!defined($gcov_dir)) { |
| 4183 info("Auto-detecting gcov kernel support.\n"); |
| 4184 @todo = ( "cs", "cp", "ss", "cs", "sp", "cp" ); |
| 4185 } elsif ($gcov_dir =~ /proc/) { |
| 4186 info("Checking gcov kernel support at $gcov_dir ". |
| 4187 "(user-specified).\n"); |
| 4188 @todo = ( "cp", "sp", "cp", "cs", "ss", "cs"); |
| 4189 } else { |
| 4190 info("Checking gcov kernel support at $gcov_dir ". |
| 4191 "(user-specified).\n"); |
| 4192 @todo = ( "cs", "ss", "cs", "cp", "sp", "cp", ); |
| 4193 } |
| 4194 foreach (@todo) { |
| 4195 if ($_ eq "cs") { |
| 4196 # Check /sys |
| 4197 $dir = defined($gcov_dir) ? $gcov_dir : $sys_dir; |
| 4198 if (check_gkv_sys($dir)) { |
| 4199 info("Found ".$GKV_NAME[$GKV_SYS]." gcov ". |
| 4200 "kernel support at $dir\n"); |
| 4201 return ($GKV_SYS, $dir); |
| 4202 } |
| 4203 } elsif ($_ eq "cp") { |
| 4204 # Check /proc |
| 4205 $dir = defined($gcov_dir) ? $gcov_dir : $proc_dir; |
| 4206 if (check_gkv_proc($dir)) { |
| 4207 info("Found ".$GKV_NAME[$GKV_PROC]." gcov ". |
| 4208 "kernel support at $dir\n"); |
| 4209 return ($GKV_PROC, $dir); |
| 4210 } |
| 4211 } elsif ($_ eq "ss") { |
| 4212 # Setup /sys |
| 4213 setup_gkv_sys(); |
| 4214 } elsif ($_ eq "sp") { |
| 4215 # Setup /proc |
| 4216 setup_gkv_proc(); |
| 4217 } |
| 4218 } |
| 4219 if (defined($gcov_dir)) { |
| 4220 die("ERROR: could not find gcov kernel data at $gcov_dir\n"); |
| 4221 } else { |
| 4222 die("ERROR: no gcov kernel data found\n"); |
| 4223 } |
| 4224 } |
| 4225 |
| 4226 |
| 4227 # |
| 4228 # get_overall_line(found, hit, name_singular, name_plural) |
| 4229 # |
| 4230 # Return a string containing overall information for the specified |
| 4231 # found/hit data. |
| 4232 # |
| 4233 |
| 4234 sub get_overall_line($$$$) |
| 4235 { |
| 4236 my ($found, $hit, $name_sn, $name_pl) = @_; |
| 4237 my $name; |
| 4238 |
| 4239 return "no data found" if (!defined($found) || $found == 0); |
| 4240 $name = ($found == 1) ? $name_sn : $name_pl; |
| 4241 |
| 4242 return rate($hit, $found, "% ($hit of $found $name)"); |
| 4243 } |
| 4244 |
| 4245 |
| 4246 # |
| 4247 # print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do |
| 4248 # br_found, br_hit) |
| 4249 # |
| 4250 # Print overall coverage rates for the specified coverage types. |
| 4251 # |
| 4252 |
| 4253 sub print_overall_rate($$$$$$$$$) |
| 4254 { |
| 4255 my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit, |
| 4256 $br_do, $br_found, $br_hit) = @_; |
| 4257 |
| 4258 info("Summary coverage rate:\n"); |
| 4259 info(" lines......: %s\n", |
| 4260 get_overall_line($ln_found, $ln_hit, "line", "lines")) |
| 4261 if ($ln_do); |
| 4262 info(" functions..: %s\n", |
| 4263 get_overall_line($fn_found, $fn_hit, "function", "functions")) |
| 4264 if ($fn_do); |
| 4265 info(" branches...: %s\n", |
| 4266 get_overall_line($br_found, $br_hit, "branch", "branches")) |
| 4267 if ($br_do); |
| 4268 } |
| 4269 |
| 4270 |
| 4271 # |
| 4272 # rate(hit, found[, suffix, precision, width]) |
| 4273 # |
| 4274 # Return the coverage rate [0..100] for HIT and FOUND values. 0 is only |
| 4275 # returned when HIT is 0. 100 is only returned when HIT equals FOUND. |
| 4276 # PRECISION specifies the precision of the result. SUFFIX defines a |
| 4277 # string that is appended to the result if FOUND is non-zero. Spaces |
| 4278 # are added to the start of the resulting string until it is at least WIDTH |
| 4279 # characters wide. |
| 4280 # |
| 4281 |
| 4282 sub rate($$;$$$) |
| 4283 { |
| 4284 my ($hit, $found, $suffix, $precision, $width) = @_; |
| 4285 my $rate; |
| 4286 |
| 4287 # Assign defaults if necessary |
| 4288 $precision = 1 if (!defined($precision)); |
| 4289 $suffix = "" if (!defined($suffix)); |
| 4290 $width = 0 if (!defined($width)); |
| 4291 |
| 4292 return sprintf("%*s", $width, "-") if (!defined($found) || $found == 0); |
| 4293 $rate = sprintf("%.*f", $precision, $hit * 100 / $found); |
| 4294 |
| 4295 # Adjust rates if necessary |
| 4296 if ($rate == 0 && $hit > 0) { |
| 4297 $rate = sprintf("%.*f", $precision, 1 / 10 ** $precision); |
| 4298 } elsif ($rate == 100 && $hit != $found) { |
| 4299 $rate = sprintf("%.*f", $precision, 100 - 1 / 10 ** $precision); |
| 4300 } |
| 4301 |
| 4302 return sprintf("%*s", $width, $rate.$suffix); |
| 4303 } |
OLD | NEW |