Support verilator_coverage --write-info for lcov HTML reports.
This commit is contained in:
parent
6fd7f45cef
commit
d33d0301f8
2
Changes
2
Changes
|
@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||||
|
|
||||||
* Verilator 4.035 devel
|
* Verilator 4.035 devel
|
||||||
|
|
||||||
|
*** Support verilator_coverage --write-info for lcov HTML reports.
|
||||||
|
|
||||||
**** Support multi channel descriptor I/O (#2190) [Stephen Henry]
|
**** Support multi channel descriptor I/O (#2190) [Stephen Henry]
|
||||||
|
|
||||||
**** Support $countbits. (#2287) [Yossi Nivin]
|
**** Support $countbits. (#2287) [Yossi Nivin]
|
||||||
|
|
|
@ -5171,6 +5171,10 @@ For an example, after running 'make test' in the Verilator distribution,
|
||||||
see the examples/make_tracing_c/logs directory. Grep for lines starting
|
see the examples/make_tracing_c/logs directory. Grep for lines starting
|
||||||
with '%' to see what lines Verilator believes need more coverage.
|
with '%' to see what lines Verilator believes need more coverage.
|
||||||
|
|
||||||
|
Info files can be written by verilator_coverage for import to C<lcov>.
|
||||||
|
This enables use of C<genhtml> for HTML reports and importing reports to
|
||||||
|
sites such as L<https://codecov.io>.
|
||||||
|
|
||||||
=item Where is the translate_off command? (How do I ignore a construct?)
|
=item Where is the translate_off command? (How do I ignore a construct?)
|
||||||
|
|
||||||
Translate on/off pragmas are generally a bad idea, as it's easy to have
|
Translate on/off pragmas are generally a bad idea, as it's easy to have
|
||||||
|
|
|
@ -156,6 +156,8 @@ verilator_coverage - Verilator coverage analyzer
|
||||||
|
|
||||||
verilator_coverage -write merged.dat -read <datafiles>...
|
verilator_coverage -write merged.dat -read <datafiles>...
|
||||||
|
|
||||||
|
verilator_coverage -write-info merged.info -read <datafiles>...
|
||||||
|
|
||||||
Verilator_coverage processes Verilator coverage reports.
|
Verilator_coverage processes Verilator coverage reports.
|
||||||
|
|
||||||
With --anotate, it reads the specified data file and generates annotated
|
With --anotate, it reads the specified data file and generates annotated
|
||||||
|
@ -224,8 +226,20 @@ Displays program version and exits.
|
||||||
=item --write I<filename>
|
=item --write I<filename>
|
||||||
|
|
||||||
Specifies the aggregate coverage results, summed across all the files,
|
Specifies the aggregate coverage results, summed across all the files,
|
||||||
should be written to the given filename. This is useful in scripts to
|
should be written to the given filename in verilator_coverage data format.
|
||||||
combine many sequential runs into one master coverage file.
|
This is useful in scripts to combine many sequential runs into one master
|
||||||
|
coverage file.
|
||||||
|
|
||||||
|
=item --write-info I<filename.info>
|
||||||
|
|
||||||
|
Specifies the aggregate coverage results, summed across all the files,
|
||||||
|
should be written to the given filename in C<lcov> .info format.
|
||||||
|
This may be used to use C<lcov> to aggregate or generate reports.
|
||||||
|
|
||||||
|
The info format loses data compared to the Verilator coverage data format;
|
||||||
|
the info will all forms of coverage converted to line style coverage, and
|
||||||
|
if there are multiple coverage points on a single line, the minimum
|
||||||
|
coverage across those points will be used to report coverage of the line.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
@ -277,7 +291,7 @@ Wilson Snyder <wsnyder@wsnyder.org>
|
||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
C<verilator>
|
C<verilator>, C<lcov>
|
||||||
|
|
||||||
L<verilator_coverage --help> which is the source for this document.
|
L<verilator_coverage --help> which is the source for this document.
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,9 @@ void VlcOptions::parseOptsList(int argc, char** argv) {
|
||||||
} else if (!strcmp(sw, "-write") && (i + 1) < argc) {
|
} else if (!strcmp(sw, "-write") && (i + 1) < argc) {
|
||||||
shift;
|
shift;
|
||||||
m_writeFile = argv[i];
|
m_writeFile = argv[i];
|
||||||
|
} else if (!strcmp(sw, "-write-info") && (i + 1) < argc) {
|
||||||
|
shift;
|
||||||
|
m_writeInfoFile = argv[i];
|
||||||
} else {
|
} else {
|
||||||
v3fatal("Invalid option: " << argv[i]);
|
v3fatal("Invalid option: " << argv[i]);
|
||||||
}
|
}
|
||||||
|
@ -170,8 +173,9 @@ int main(int argc, char** argv, char** /*env*/) {
|
||||||
top.tests().dump(false);
|
top.tests().dump(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!top.opt.writeFile().empty()) {
|
if (!top.opt.writeFile().empty() || !top.opt.writeInfoFile().empty()) {
|
||||||
top.writeCoverage(top.opt.writeFile());
|
if (!top.opt.writeFile().empty()) top.writeCoverage(top.opt.writeFile());
|
||||||
|
if (!top.opt.writeInfoFile().empty()) top.writeInfo(top.opt.writeInfoFile());
|
||||||
V3Error::abortIfWarnings();
|
V3Error::abortIfWarnings();
|
||||||
if (top.opt.unlink()) {
|
if (top.opt.unlink()) {
|
||||||
const VlStringSet& readFiles = top.opt.readFiles();
|
const VlStringSet& readFiles = top.opt.readFiles();
|
||||||
|
|
|
@ -42,6 +42,7 @@ class VlcOptions {
|
||||||
bool m_rank; // main switch: --rank
|
bool m_rank; // main switch: --rank
|
||||||
bool m_unlink; // main switch: --unlink
|
bool m_unlink; // main switch: --unlink
|
||||||
string m_writeFile; // main switch: --write
|
string m_writeFile; // main switch: --write
|
||||||
|
string m_writeInfoFile; // main switch: --write-info
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -72,6 +73,7 @@ public:
|
||||||
bool rank() const { return m_rank; }
|
bool rank() const { return m_rank; }
|
||||||
bool unlink() const { return m_unlink; }
|
bool unlink() const { return m_unlink; }
|
||||||
string writeFile() const { return m_writeFile; }
|
string writeFile() const { return m_writeFile; }
|
||||||
|
string writeInfoFile() const { return m_writeInfoFile; }
|
||||||
|
|
||||||
// METHODS (from main)
|
// METHODS (from main)
|
||||||
static string version();
|
static string version();
|
||||||
|
|
|
@ -77,6 +77,61 @@ void VlcTop::writeCoverage(const string& filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VlcTop::writeInfo(const string& filename) {
|
||||||
|
UINFO(2, "writeInfo " << filename << endl);
|
||||||
|
|
||||||
|
std::ofstream os(filename.c_str());
|
||||||
|
if (!os) {
|
||||||
|
v3fatal("Can't write " << filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
annotateCalc();
|
||||||
|
|
||||||
|
// See 'man lcov' for format details
|
||||||
|
// TN:<trace_file_name>
|
||||||
|
// Source file:
|
||||||
|
// SF:<absolute_path_to_source_file>
|
||||||
|
// FN:<line_number_of_function_start>,<function_name>
|
||||||
|
// FNDA:<execution_count>,<function_name>
|
||||||
|
// FNF:<number_functions_found>
|
||||||
|
// FNH:<number_functions_hit>
|
||||||
|
// Branches:
|
||||||
|
// BRDA:<line_number>,<block_number>,<branch_number>,<taken_count_or_-_for_zero>
|
||||||
|
// BRF:<number_of_branches_found>
|
||||||
|
// BRH:<number_of_branches_hit>
|
||||||
|
// Line counts:
|
||||||
|
// DA:<line_number>,<execution_count>
|
||||||
|
// LF:<number_of_lines_found>
|
||||||
|
// LH:<number_of_lines_hit>
|
||||||
|
// Section ending:
|
||||||
|
// end_of_record
|
||||||
|
|
||||||
|
os << "TN:verilator_coverage\n";
|
||||||
|
for (VlcSources::NameMap::iterator sit = m_sources.begin(); sit != m_sources.end(); ++sit) {
|
||||||
|
VlcSource& source = sit->second;
|
||||||
|
os << "SF:" << source.name() << endl;
|
||||||
|
VlcSource::LinenoMap& lines = source.lines();
|
||||||
|
for (VlcSource::LinenoMap::iterator lit = lines.begin(); lit != lines.end(); ++lit) {
|
||||||
|
int lineno = lit->first;
|
||||||
|
VlcSource::ColumnMap& cmap = lit->second;
|
||||||
|
bool first = true;
|
||||||
|
vluint64_t min_count = 0; // Minimum across all columns on line
|
||||||
|
for (VlcSource::ColumnMap::iterator cit = cmap.begin(); cit != cmap.end(); ++cit) {
|
||||||
|
VlcSourceCount& col = cit->second;
|
||||||
|
if (first) {
|
||||||
|
min_count = col.count();
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
min_count = std::min(min_count, col.count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "DA:" << lineno << "," << min_count << "\n";
|
||||||
|
}
|
||||||
|
os << "end_of_record\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//********************************************************************
|
//********************************************************************
|
||||||
|
|
||||||
struct CmpComputrons {
|
struct CmpComputrons {
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
void annotate(const string& dirname);
|
void annotate(const string& dirname);
|
||||||
void readCoverage(const string& filename, bool nonfatal = false);
|
void readCoverage(const string& filename, bool nonfatal = false);
|
||||||
void writeCoverage(const string& filename);
|
void writeCoverage(const string& filename);
|
||||||
|
void writeInfo(const string& filename);
|
||||||
|
|
||||||
void rank();
|
void rank();
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,5 +31,24 @@ run(cmd => ["../bin/verilator_coverage",
|
||||||
|
|
||||||
files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out");
|
files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out");
|
||||||
|
|
||||||
|
# Also try lcov
|
||||||
|
run(cmd => ["../bin/verilator_coverage",
|
||||||
|
"--write-info", "$Self->{obj_dir}/coverage.info",
|
||||||
|
"$Self->{obj_dir}/coverage.dat"],
|
||||||
|
verilator_run => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
# If installed
|
||||||
|
if (`lcov --help` !~ /Usage:/
|
||||||
|
|| `genhtml --help` !~ /Usage:/) {
|
||||||
|
skip("lcov or genhtml not installed");
|
||||||
|
} else {
|
||||||
|
run(cmd => ["genhtml",
|
||||||
|
"$Self->{obj_dir}/coverage.info",
|
||||||
|
"--output-directory $Self->{obj_dir}/html",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
TN:verilator_coverage
|
||||||
|
SF:file1.sp
|
||||||
|
DA:159,53
|
||||||
|
end_of_record
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(dist => 1);
|
||||||
|
|
||||||
|
run(cmd => ["../bin/verilator_coverage",
|
||||||
|
"--write-info", "$Self->{obj_dir}/coverage.info",
|
||||||
|
"t/t_vlcov_data_a.dat",
|
||||||
|
"t/t_vlcov_data_b.dat",
|
||||||
|
"t/t_vlcov_data_c.dat",
|
||||||
|
"t/t_vlcov_data_d.dat",
|
||||||
|
],
|
||||||
|
verilator_run => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
files_identical("$Self->{obj_dir}/coverage.info", $Self->{golden_filename});
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
Loading…
Reference in New Issue