#!/usr/bin/perl # Currently, we implement only the directory option # The following features have been requested for # # 1. Get the name of the directory and produce a # statistic for all the files which have been touched # in all the subdirectories starting from that # directory # # 2. Since gcov spits out a statistic for all the header # files included by all the source files, we need to # aggregate them somehow into a single file. This might # have to be done manually by going through all the lines # which have been executed in that file since a header # file may have multiple inclusions meaning that they # might have multiple .gcov files in different directories # # 3. Support command line parsing of arguments # # 4. Support giving a listing of all the files which have # been covered less than a certain percentage, say for # eg., all files which have been covered less that 5% # use strict; use Switch; use File::Basename; #global variables my $index = 0; my $num_args = scalar(@ARGV); my $percentage = 0.0; my $ret1 = 0; my $ret2 = 0; my $dir_list_given = 0; my $req_list_given = 0; $ret1 = open(DIR_FILE, "dir_list.txt"); $ret2 = open(REQ_FILE, "req_list.txt"); if ($ret1 < 0 || $ret2 < 0) { print "ERROR: opening dir_list.txt or req_list.txt\n"; exit(3); } # check the error condition if (0 == ($num_args % 2)) { } else { print "ERROR: the number of arguments has to be even\n"; exit(3); } # process the arguments while($num_args > 0) { switch ($ARGV[$index]) { case "-d" { print DIR_FILE $ARGV[$index+1]; $index += 2; $num_args -= 2; $dir_list_given = 1; } case "-f" { my $filename = `find . -name $ARGV[$index+1]`; print REQ_FILE $filename; $index += 2; $num_args -= 2; $req_list_given = 1; } case "-p" { $percentage = $ARGV[$index]; $index += 2; $num_args -= 2; } else { print "ERROR: Incorrect command line option\n"; exit(3); } } } close(DIR_FILE); close(REQ_FILE); # when nothing is specified, everything defaults to just "src" if (0 == $dir_list_given && 0 == $req_list_given) { print "WARN: No directory or file has been requested\ndefaulting to src directory\n"; system("echo src > dir_list.txt"); $dir_list_given = 1; } #Now, we have both the requested file list and the directory list #So simply call the procedure generate_stats with the required arguments if (1 == $dir_list_given) { get_file_list("./dir_list.txt", "touched_files.txt", "untouched_files.txt"); generate_stats("touched_files.txt", # file_list "coverage_stats.txt",# generic coverage numbers "percent_stats.txt", # files below a certain % $percentage, # percentage below which we report 1); # 1 to report } if (1 == $req_list_given) { generate_stats("req_list.txt", # file_list "req_stats.txt",# generic coverage "", # no percentage coverage required 0, # not required 0); # 0 to not report percentages } sub get_file_list { my ($input, $touched, $untouched) = @_; my $ret = open(DIRFILES, "< $input"); if ($ret < 0) { print "ERROR: could not open directory listing\n"; exit(3); } while() { chomp(); my $c_files = `find $_ -name \"*.c\"`; my $cc_files = `find $_ -name \"*.cc\"`; $cc_files =~ s/\.cc//g; $c_files =~ s/\.c//g; $c_files = $c_files . $cc_files; my @C_FILES = split(/\n/, $c_files); my $da_files = `find $_ -name \"*.da\" -o -name \"*.gcda\"`; $da_files =~ s/\.gcda//g; $da_files =~ s/\.da//g; my @DA_FILES = split(/\n/, $da_files); open (TEMP1, "> temp1"); open (TEMP2, "> temp2"); print TEMP1 $c_files; print TEMP2 $da_files; close(TEMP1); close(TEMP2); # Now do the manual diff open(TEMP1, "< temp1"); open(UNTOUCHED_FILES, ">> $untouched"); open(TOUCHED_FILES, ">> $touched"); while() { my $c_file = $_; my $found = 0; my $file_name; my $dir_name; my $file_ext; my $search_file; ($file_name, $dir_name, $file_ext) = fileparse($c_file, ('\.c') ); # For our libtool build, every .gcda and .gcno file lands in the .libs dir. $search_file = $dir_name . ".libs/" . $file_name; open(TEMP2, "< temp2"); while() { if ($search_file eq $_) { $found = 1; } } close(TEMP2); if ($found == 0) { print UNTOUCHED_FILES $c_file; } else { chomp($c_file); $c_file = $c_file . ".c\n"; print TOUCHED_FILES $c_file; } } close(UNTOUCHED_FILES); close(TOUCHED_FILES); close(TEMP1); system("rm temp1 temp2"); } close(DIRFILES); #Now to print the stats of all the files which are touched system("sort $touched -o temp; uniq temp $touched"); system("sort $untouched -o temp; uniq temp $untouched"); } # This is the function which generates the statistics and dumps it out # to a file. Details are pretty straightforward at this point sub generate_stats { my ($input_file, $coverage_file, $percent_file, $percentage, $calculate) = @_; my $k = 0; my $l = 0; open (INPUT, "< $input_file"); open (COVERAGE, "> $coverage_file"); if ($calculate == 1) { open (PERCENT, "> percent_coverage.txt"); } print COVERAGE "#Index Directory Filename Usage(%)\n"; print COVERAGE "#======================================================================================================\n"; if ($calculate == 1) { print PERCENT "#Index Directory Filename Usage(%)\n"; print PERCENT "#======================================================================================================\n"; } my $average = 0.0; my $num_files = `wc -l touched_files.txt`; print "num_files:", $num_files; while () { #generate the gcov file for this particular file #1. Get the directory name and filename seperately #2. Invoke gcov on the file #3. Print the statistic onto a file chomp(); my $full_name = $_; my $dir_name; my $file_name; my $file_ext; my $file_gcda; my $found_file; ($file_name, $dir_name, $file_ext) = fileparse($full_name, ('\.c') ); $file_gcda = $file_name . ".gcda"; open(RESULT, "cd $dir_name; gcov $file_gcda -o .libs 2> /dev/null | "); while () { if (/Creating/) { $found_file = 0; } else { # print "check: ", $_; # Do not check including the file_extension; might be .c or .cc or .C if (/^File '$file_name/) { # print "Found File:\n", $_; $found_file = 1; } #Now we are doing the right line. Search for this file if (/^Lines/ && $found_file == 1) { # print "Found Lines:\n", $_; s/([\s,0-9]*\.[0-9]+\%)\.*/$1/; my $val = $1; $average += $val; $k++; my $print_string = sprintf("%4d %40s %40s %3.2f\n", $k, $dir_name, $file_name, $val); if ($calculate == 1) { if ($val <= $percentage) { $l++; my $zero_string = sprintf("%4d %40s %40s %3.2f\n", $l, $dir_name, $file_name, $val); print PERCENT $zero_string; } } print COVERAGE $print_string; # Need to detect the next round $found_file = 0; } } } close(RESULT); } if ($num_files != 0){ print COVERAGE "==============================================================\n"; print COVERAGE "Average coverage was: ", $average/$num_files, " \n"; print COVERAGE "==============================================================\n"; } close(INPUT); close(COVERAGE); if ($calculate == 1) { close(PERCENT); } }