Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(621)

Side by Side Diff: third_party/lcov/bin/lcov

Issue 23189008: Upgrades lcov to 1.10, removes lcov-1.9 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Re-adds UNKNOWN suppression Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/lcov/bin/install.sh ('k') | third_party/lcov/bin/updateversion.pl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « third_party/lcov/bin/install.sh ('k') | third_party/lcov/bin/updateversion.pl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698