diff --git a/.travis.yml b/.travis.yml index 931e58835..ff73fb9b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ before_install: # Not listing Bit::Vector as slow to install, and only skips one test - touch temp.cpp ; g++ -E -dM -c temp.cpp | sort ; rm -rf temp.cpp - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker - - sudo apt-get install gdb gtkwave + - sudo apt-get install gdb gtkwave lcov - sudo apt-get install libfl-dev || true - sudo apt-get install libgoogle-perftools-dev before_script: diff --git a/docs/install.adoc b/docs/install.adoc index 61d665091..a61171896 100644 --- a/docs/install.adoc +++ b/docs/install.adoc @@ -98,7 +98,7 @@ need to be present to run Verilator: Those developing Verilator itself may also want these (see internals.adoc): - sudo apt-get install gdb asciidoctor graphviz cmake clang clang-format gprof + sudo apt-get install gdb asciidoctor graphviz cmake clang clang-format gprof lcov cpan install Pod::Perldoc cpan install Unix::Processors cpan install Parallel::Forker diff --git a/nodist/code_coverage b/nodist/code_coverage index 9659bedbd..4f4cd17d7 100755 --- a/nodist/code_coverage +++ b/nodist/code_coverage @@ -12,7 +12,10 @@ use Pod::Usage; use strict; use vars qw($Debug); +our $Opt_Stop; our $Exclude_Line_Regexp; +our $Remove_Gcda_Regexp; + our @Remove_Sources; our @Source_Globs; @@ -27,7 +30,8 @@ Getopt::Long::config("no_auto_abbrev"); if (! GetOptions( "debug" => sub { $Debug = 1; }, "<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; }, - "stage=i" => \$Opt_Stage, + "stage=i" => \$Opt_Stage, # starting stage number + "stop!" => \$Opt_Stop, # stop/do not stop on error in tests )) { die "%Error: Bad usage, try 'install_test --help'\n"; } @@ -42,45 +46,85 @@ sub test { require "./nodist/code_coverage.dat"; if ($Opt_Stage <= 0) { + travis_fold_start("configure"); print "Stage 0: configure (coverage on)\n"; - run("make distclean"); + run("make distclean || true"); run("./configure --enable-longtests CXX='g++ --coverage'"); run("make -k"); # The optimized versions will not collect good coverage, overwrite them run("cp bin/verilator_bin_dbg bin/verilator_bin"); run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin"); + travis_fold_end(); } if ($Opt_Stage <= 1) { + travis_fold_start("test"); print "Stage 1: make examples (with coverage on)\n"; run("make examples"); - run("make test_regress"); + run("make test_regress" + . ($Opt_Stop ? '' : ' || true')); + travis_fold_end(); } my $cc_dir = "nodist/obj_dir/coverage"; if ($Opt_Stage <= 2) { + travis_fold_start("info"); print "Stage 2: Create info files under $cc_dir\n"; mkpath($cc_dir); mkpath("$cc_dir/info"); my $dats = `find . -print | grep .gcda`; - my %dirs; + my %dats; foreach my $dat (split '\n', $dats) { - $dat =~ s!/[^/]+$!!; - $dirs{$dat} = 1; + $dats{$dat} = 1; + } + my %dirs; + my %gcnos; + foreach my $dat (sort keys %dats) { + (my $gcno = $dat) =~ s!\.gcda$!.gcno!; + if ($dat =~ /$Remove_Gcda_Regexp/) { + # Remove .gcda/.gcno for files we don't care about before we slowly + # read them + unlink $dat; + unlink $gcno; + delete $dats{$dat}; + next; + } + (my $gbase = $gcno) =~ s!.*/!!; + if (!$gcnos{$gbase} && -r $gcno) { + $gcnos{$gbase} = $gcno; + } + } + # We need a matching .gcno for every .gcda, try to find a matching file elsewhere + foreach my $dat (sort keys %dats) { + (my $gcno = $dat) =~ s!\.gcda$!.gcno!; + (my $gbase = $gcno) =~ s!.*/!!; + if (!-r $gcno) { + if ($gcnos{$gbase}) { + cp($gcnos{$gbase}, $gcno); + } else { + warn "MISSING .gcno for a .gcda: $gcno\n"; + } + } + (my $dir = $dat) =~ s!/[^/]+$!!; + $dirs{$dir} = 1; } foreach my $dir (sort keys %dirs) { (my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g; run("cd $cc_dir/info ; lcov -c -d ../../../../$dir -o app_test_${outname}.info"); } + travis_fold_end(); } if ($Opt_Stage <= 3) { + travis_fold_start("clone"); # lcov doesn't have a control file to override single lines, so replicate the sources print "Stage 3: Clone sources under $cc_dir\n"; clone_sources($cc_dir); + travis_fold_end(); } if ($Opt_Stage <= 4) { + travis_fold_start("copy"); print "Stage 4: Copy .gcno files\n"; my $dats = `find . -print | grep .gcno`; foreach my $dat (split '\n', $dats) { @@ -89,9 +133,11 @@ sub test { #print "cp $dat, $outdat);\n"; cp($dat, $outdat); } + travis_fold_end(); } if ($Opt_Stage <= 5) { + travis_fold_start("combine"); print "Stage 5: Combine data files\n"; run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info"); run("cd $cc_dir ; lcov -a app_base.info -o app_total.info"); @@ -106,22 +152,35 @@ sub test { $comb = ""; } } + travis_fold_end(); } if ($Opt_Stage <= 6) { + travis_fold_start("filter"); print "Stage 6: Filter processed source files\n"; my $cmd = ''; foreach my $glob (@Remove_Sources) { $cmd .= " '$glob'"; } run("cd $cc_dir ; lcov --remove app_total.info $cmd -o app_total.info"); + travis_fold_end(); } - if ($Opt_Stage <= 7) { + if ($Opt_Stage <= 8) { + travis_fold_start("report"); print "Stage 7: Create HTML\n"; cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info"); run("cd $cc_dir ; genhtml app_total.info --demangle-cpp" ." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html"); + travis_fold_end(); + } + + if ($Opt_Stage <= 9) { + travis_fold_start("upload"); + print "Stage 9: Upload\n"; + my $cmd = 'bash <(curl -s https://codecov.io/bash) -f $cc_dir/app_total.info'; + print "print: Not running: $cmd\n"; + travis_fold_end(); } if ($Opt_Stage <= 9) { @@ -184,12 +243,13 @@ sub cleanup_abs_paths { sub exclude_line_regexp { $Exclude_Line_Regexp = shift; } - +sub remove_gcda_regexp { + $Remove_Gcda_Regexp = shift; +} sub remove_source { my @srcs = @_; push @Remove_Sources, @srcs; } - sub source_globs { my @dirs = @_; push @Source_Globs, @dirs; @@ -206,6 +266,15 @@ sub run { ($status == 0) or die "%Error: Command Failed $command, $status, stopped"; } +our $_Travis_Action; +sub travis_fold_start { + $_Travis_Action = shift; + print "travis_fold:start:$_Travis_Action\n"; +} +sub travis_fold_end { + print "travis_fold:end:$_Travis_Action\n"; +} + ####################################################################### __END__ diff --git a/nodist/code_coverage.dat b/nodist/code_coverage.dat index 898b65cf7..58e4f8d5e 100644 --- a/nodist/code_coverage.dat +++ b/nodist/code_coverage.dat @@ -22,6 +22,7 @@ source_globs("src/*.cpp", ); remove_source("/usr/include/*"); +remove_source("/usr/lib/*"); remove_source("*/include/sysc/*"); remove_source("*/V3ClkGater.cpp"); remove_source("*/V3ClkGater.h"); @@ -37,7 +38,10 @@ remove_source("*include/gtkwave/*"); remove_source("*test_regress/*"); remove_source("*examples/*"); +# Remove collected coverage on each little test main file +# Would just be removed with remove_source in later step +remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!); -exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b)/); +exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b|\bVL_FATAL)/); 1; diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 6163f1b9b..81df6df4d 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -306,6 +306,8 @@ sub new { skip_msgs => [], fail_msgs => [], fail_tests => [], + # Per-task identifiers + running_ids => {}, @_}; bless $self, $class; return $self; @@ -322,14 +324,24 @@ sub one_test { $::Fork->schedule ( test_pl_filename => $params{pl_filename}, + run_pre_start => sub { + my $process = shift; + # Running in context of parent, before run_on_start + # Make an identifier that is unique across all current running jobs + my $i = 1; while (exists $self->{running_ids}{$i}) { ++$i; } + $process->{running_id} = $i; + $self->{running_ids}{$process->{running_id}} = 1; + }, run_on_start => sub { + my $process = shift; # Running in context of child, so can't pass data to parent directly if ($self->{quiet}) { open(STDOUT, ">/dev/null"); open(STDERR, ">&STDOUT"); } print("="x70,"\n"); - my $test = VTest->new(@params); + my $test = VTest->new(@params, + running_id => $process->{running_id}); $test->oprint("="x50,"\n"); unlink $test->{status_filename}; $test->_prep; @@ -340,7 +352,9 @@ sub one_test { }, run_on_finish => sub { # Running in context of parent - my $test = VTest->new(@params); + my $process = shift; + my $test = VTest->new(@params, + running_id => $process->{running_id}); $test->_read_status; if ($test->ok) { $self->{ok_cnt}++; @@ -374,6 +388,7 @@ sub one_test { } $self->{left_cnt}--; $self->print_summary; + delete $self->{running_ids}{$process->{running_id}}; }, )->ready(); } @@ -1062,6 +1077,7 @@ sub compile { tee => $param{tee}, expect => $param{expect}, expect_filename => $param{expect_filename}, + verilator_run => 1, cmd => \@vlt_cmd) if $::Opt_Verilation; return 1 if $self->errors || $self->skips || $self->unsupporteds; } @@ -1077,6 +1093,7 @@ sub compile { tee => $param{tee}, expect => $param{expect}, expect_filename => $param{expect_filename}, + verilator_run => 1, cmd => ["cd \"".$self->{obj_dir}."\" && cmake", "\"".$self->{t_dir}."/..\"", "-DTEST_VERILATOR_ROOT=$ENV{VERILATOR_ROOT}", @@ -1458,6 +1475,7 @@ sub _run { my $self = (ref $_[0]? shift : $Self); my %param = (tee => 1, #entering => # Print entering directory information + #verilator_run => # Move gcov data to parallel area @_); my $command = join(' ',@{$param{cmd}}); $command = "time $command" if $opt_benchmark && $command !~ /^cd /; @@ -1465,6 +1483,17 @@ sub _run { print " > $param{logfile}" if $param{logfile}; print "\n"; + if ($param{verilator_run}) { + # Gcov fails when parallel jobs write same data file, + # so we make sure output dir is unique across all running jobs. + # We can't just put each one in obj_dir as it uses too much disk. + $ENV{GCOV_PREFIX_STRIP} = 99; + $ENV{GCOV_PREFIX} = "$self->{t_dir}/obj_dist/gcov_$self->{running_id}"; + } else { + delete $ENV{GCOV_PREFIX_STRIP}; + delete $ENV{GCOV_PREFIX}; + } + # Execute command redirecting output, keeping order between stderr and stdout. # Must do low-level IO so GCC interaction works (can't be line-based) my $status; @@ -2271,6 +2300,7 @@ sub schedule { my $self = shift; my %params = (@_); + $params{run_pre_start}->($self); if (my $pid = fork()) { # Parent waitpid($pid, 0); } else { # Child diff --git a/test_regress/t/t_a1_first_cc.pl b/test_regress/t/t_a1_first_cc.pl index 9e03d8e8a..50fc6fcd9 100755 --- a/test_regress/t/t_a1_first_cc.pl +++ b/test_regress/t/t_a1_first_cc.pl @@ -16,7 +16,9 @@ scenarios(simulator => 1); $DEBUG_QUIET = "--debug --debugi 0 --gdbbt --no-dump-tree"; -run(cmd => ["perl", "../bin/verilator", $DEBUG_QUIET, "-V"]); +run(cmd => ["perl", "../bin/verilator", $DEBUG_QUIET, "-V"], + verilator_run => 1, + ); compile( verilator_flags2 => [$DEBUG_QUIET, "--trace"], diff --git a/test_regress/t/t_cover_line_cc.pl b/test_regress/t/t_cover_line_cc.pl index 8782e89bb..563ce9ffd 100755 --- a/test_regress/t/t_cover_line_cc.pl +++ b/test_regress/t/t_cover_line_cc.pl @@ -25,8 +25,9 @@ inline_checks(); run(cmd => ["../bin/verilator_coverage", "--annotate", "$Self->{obj_dir}/annotated", - "$Self->{obj_dir}/coverage.dat", - ]); + "$Self->{obj_dir}/coverage.dat"], + verilator_run => 1, + ); files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out"); diff --git a/test_regress/t/t_cover_line_cc_vlt.pl b/test_regress/t/t_cover_line_cc_vlt.pl index 3b1a9ddff..1d21931e1 100755 --- a/test_regress/t/t_cover_line_cc_vlt.pl +++ b/test_regress/t/t_cover_line_cc_vlt.pl @@ -26,7 +26,9 @@ inline_checks(); run(cmd => ["../bin/verilator_coverage", "--annotate", "$Self->{obj_dir}/annotated", "$Self->{obj_dir}/coverage.dat", - ]); + ], + verilator_run => 1, + ); files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out"); diff --git a/test_regress/t/t_cover_line_trace.pl b/test_regress/t/t_cover_line_trace.pl index adf5699f7..a3763b8c5 100755 --- a/test_regress/t/t_cover_line_trace.pl +++ b/test_regress/t/t_cover_line_trace.pl @@ -23,7 +23,9 @@ execute( run(cmd => ["../bin/verilator_coverage", "--annotate", "$Self->{obj_dir}/annotated", "$Self->{obj_dir}/coverage.dat", - ]); + ], + verilator_run => 1, + ); files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out"); vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); diff --git a/test_regress/t/t_flag_help.pl b/test_regress/t/t_flag_help.pl index 12f95bee3..f3dc0cca4 100755 --- a/test_regress/t/t_flag_help.pl +++ b/test_regress/t/t_flag_help.pl @@ -23,6 +23,7 @@ foreach my $prog ( "--help"], logfile => "$Self->{obj_dir}/t_help.log", tee => 0, + verilator_run => 1, ); file_grep("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i); } diff --git a/test_regress/t/t_flag_version.pl b/test_regress/t/t_flag_version.pl index 571a4904e..2b145b855 100755 --- a/test_regress/t/t_flag_version.pl +++ b/test_regress/t/t_flag_version.pl @@ -24,6 +24,7 @@ foreach my $prog ( tee => $self->{verbose}, logfile => "$Self->{obj_dir}/t_help.log", expect => qr/^Verilator/, + verilator_run => 1, ); run(fails => 0, @@ -32,6 +33,7 @@ foreach my $prog ( tee => $self->{verbose}, logfile => "$Self->{obj_dir}/t_help.log", expect => qr/^Verilator/, + verilator_run => 1, ); run(fails => 0, @@ -39,6 +41,7 @@ foreach my $prog ( "-V"], logfile => "$Self->{obj_dir}/t_help.log", expect => qr/^Verilator/, + verilator_run => 1, ); } diff --git a/test_regress/t/t_gantt.pl b/test_regress/t/t_gantt.pl index 80b72c677..e38cd63b7 100755 --- a/test_regress/t/t_gantt.pl +++ b/test_regress/t/t_gantt.pl @@ -40,7 +40,9 @@ execute( run(cmd => ["$ENV{VERILATOR_ROOT}/bin/verilator_gantt", "$Self->{obj_dir}/profile_threads.dat", "--vcd $Self->{obj_dir}/profile_threads.vcd", - "> $Self->{obj_dir}/gantt.log"]); + "> $Self->{obj_dir}/gantt.log"], + verilator_run => 1, + ); # We should have three lines of gantt chart, each with # an even number of mtask-bars (eg "[123--]") diff --git a/test_regress/t/t_lint_only.pl b/test_regress/t/t_lint_only.pl index 06fd4329a..d1e2ac8bc 100755 --- a/test_regress/t/t_lint_only.pl +++ b/test_regress/t/t_lint_only.pl @@ -13,8 +13,9 @@ scenarios(vlt => 1); lint(); foreach my $file (glob("$Self->{obj_dir}/*")) { - next if $file =~ /\.log/; # Made by driver.pl, not Verilator - next if $file =~ /\.status/; # Made by driver.pl, not Verilator + next if $file =~ /\.log/; # Made by driver.pl, not Verilator sources + next if $file =~ /\.status/; # Made by driver.pl, not Verilator sources + next if $file =~ /\.gcda/; # Made by gcov, not Verilator sources error("%Error: Created $file, but --lint-only shouldn't create files"); } diff --git a/test_regress/t/t_prot_lib.pl b/test_regress/t/t_prot_lib.pl index 441859d33..7f79aaf76 100755 --- a/test_regress/t/t_prot_lib.pl +++ b/test_regress/t/t_prot_lib.pl @@ -35,7 +35,9 @@ while (1) { $secret_dir, "--protect-lib", $secret_prefix, - "t/t_prot_lib_secret.v"]); + "t/t_prot_lib_secret.v"], + verilator_run => 1, + ); last if $Self->{errors}; run(logfile => "$secret_dir/secret_gcc.log", diff --git a/test_regress/t/t_prot_lib_clk_gated.pl b/test_regress/t/t_prot_lib_clk_gated.pl index fd97a715a..f271e3cbb 100755 --- a/test_regress/t/t_prot_lib_clk_gated.pl +++ b/test_regress/t/t_prot_lib_clk_gated.pl @@ -37,7 +37,9 @@ while (1) { "-GGATED_CLK=1", "--protect-lib", $secret_prefix, - "t/t_prot_lib_secret.v"]); + "t/t_prot_lib_secret.v"], + verilator_run => 1, + ); last if $Self->{errors}; run(logfile => "$secret_dir/secret_gcc.log", diff --git a/test_regress/t/t_vlcov_debugi.pl b/test_regress/t/t_vlcov_debugi.pl index 0600b969f..8cc5f0d57 100755 --- a/test_regress/t/t_vlcov_debugi.pl +++ b/test_regress/t/t_vlcov_debugi.pl @@ -20,6 +20,7 @@ foreach my $basename ("t_vlcov_data_a.dat", "--debugi 9", ], tee => $Self->{verbose}, + verilator_run => 1, ); } diff --git a/test_regress/t/t_vlcov_merge.pl b/test_regress/t/t_vlcov_merge.pl index 8f92b7eb4..181c9ecbd 100755 --- a/test_regress/t/t_vlcov_merge.pl +++ b/test_regress/t/t_vlcov_merge.pl @@ -16,7 +16,9 @@ run(cmd => ["../bin/verilator_coverage", "t/t_vlcov_data_b.dat", "t/t_vlcov_data_c.dat", "t/t_vlcov_data_d.dat", - ]); + ], + verilator_run => 1, + ); # Older clib's didn't properly sort maps, but the coverage data doesn't # really care about ordering. So avoid false failures by sorting. diff --git a/test_regress/t/t_vlcov_nfound_bad.pl b/test_regress/t/t_vlcov_nfound_bad.pl index fc34cc0cf..e38aabd39 100755 --- a/test_regress/t/t_vlcov_nfound_bad.pl +++ b/test_regress/t/t_vlcov_nfound_bad.pl @@ -15,6 +15,7 @@ run(fails => 1, "t/t_NOT_FOUND",], logfile => $Self->{run_log_filename}, expect_filename => $Self->{golden_filename}, + verilator_run => 1, ); ok(1); diff --git a/test_regress/t/t_vlcov_rank.pl b/test_regress/t/t_vlcov_rank.pl index fdcbb8e79..ca5917c16 100755 --- a/test_regress/t/t_vlcov_rank.pl +++ b/test_regress/t/t_vlcov_rank.pl @@ -19,6 +19,7 @@ run(cmd => ["../bin/verilator_coverage", ], logfile => "$Self->{obj_dir}/vlcov.log", tee => 0, + verilator_run => 1, ); files_identical("$Self->{obj_dir}/vlcov.log", $Self->{golden_filename}); diff --git a/test_regress/t/t_vlcov_rewrite.pl b/test_regress/t/t_vlcov_rewrite.pl index c3c4543a2..6611d4e00 100755 --- a/test_regress/t/t_vlcov_rewrite.pl +++ b/test_regress/t/t_vlcov_rewrite.pl @@ -20,6 +20,7 @@ foreach my $basename ("t_vlcov_data_a.dat", "--write", "$Self->{obj_dir}/${basename}" ], tee => 0, + verilator_run => 1, ); files_identical("$Self->{obj_dir}/${basename}", "t/${basename}"); }