Perl Part II · Module 22 · Synthesis Report Parsing
What Synthesis Reports Are For
A synthesis run leaves behind a log and a handful of reports, and the usual mistake is to parse the log — because it is the file whose name you know. The log is a record of what the tool did; the reports are the answers. This chapter measures which file answers which question, finds that the mapping is exactly one-to-one, and then uses the fact that three reports describe the same design to build the cross-check every report parser should have.
Intermediate13 min readPerlPart IISynthesis Reports
Part II · Module 22 · Chapter 22.1 · What Synthesis Reports Are For
1. Four Questions, Four Files
use strict;
use warnings;
# Four questions a QoR dashboard asks, and four files that might answer them.
# The reports are GENERATED by gen_reports.pl from the real Module 20 netlist
# (no synthesis tool exists on this machine); the FORMAT follows what a
# synthesis tool emits and every NUMBER is derived from the netlist.
my @FILES = qw(
reports/counter_syn.area.rpt
reports/counter_syn.cells.rpt
reports/counter_syn.hier.rpt
reports/counter_syn.syn.log
);
# each question: a name and a pattern that would answer it
my @QUESTIONS = (
[ "total cell area", qr/^\s*Total cell area:\s+([\d.]+)/m ],
[ "sequential cell count",qr/^\s*Number of sequential cells:\s+(\d+)/m ],
[ "count of one cell type",qr/^(DFCNQD1)\s+\S+\s+[\d.]+\s+(\d+)/m ],
[ "area of one sub-block",qr/^\s+(bit0)\s+(\d+)\s+([\d.]+)/m ],
[ "constraint warnings", qr/^Warning:.*\((TIM-\d+)\)/m ],
);
my %text;
for my $f (@FILES) {
open my $fh, "<", $f or die "$f: $!";
local $/;
$text{$f} = <$fh>;
close $fh;
}
sub short { my ($f) = @_; return ($f =~ m{counter_syn\.(\w+)\.}) ? $1 : "log" }
printf "%-24s %s\n", "QUESTION", join(" ", map { sprintf "%-8s", short($_) } @FILES);
for my $q (@QUESTIONS) {
my ($label, $pat) = @$q;
my @cells;
for my $f (@FILES) {
push @cells, sprintf("%-8s", ($text{$f} =~ $pat) ? "YES" : "-");
}
printf "%-24s %s\n", $label, join(" ", @cells);
}
print "\nevery question is answered by EXACTLY ONE file:\n";
for my $q (@QUESTIONS) {
my ($label, $pat) = @$q;
my @hits = grep { $text{$_} =~ $pat } @FILES;
printf " %-24s %s\n", $label,
(@hits == 1 ? (($hits[0] =~ m{([^/]+)$})[0]) : scalar(@hits) . " files: @hits");
}
print "\nand what the LOG does NOT contain:\n";
my $log = $text{"reports/counter_syn.syn.log"};
for my $q (@QUESTIONS) {
my ($label, $pat) = @$q;
next if $log =~ $pat;
printf " the log cannot answer '%s'\n", $label;
}
print " so scanning the log for a number that lives in a report finds\n";
print " nothing -- and finding nothing is indistinguishable from zero.\n";
# ---- the one number every file agrees on, as a cross-check
print "\ncross-check: the cell count, from three different files\n";
my ($a) = $text{"reports/counter_syn.area.rpt"} =~ /^\s*Number of cells:\s+(\d+)/m;
my $c = 0;
$c += $1 while $text{"reports/counter_syn.cells.rpt"} =~ /^\w+\s+\S+\s+[\d.]+\s+(\d+)\s/mg;
my ($h) = $text{"reports/counter_syn.hier.rpt"} =~ /^counter_top\s+(\d+)\s/m;
printf " area report 'Number of cells': %s\n", $a;
printf " sum of the cells report's Count: %s\n", $c;
printf " hierarchy report's top-level Cells: %s\n", $h;
printf " all three agree? %s\n", ($a == $c && $c == $h ? "YES" : "NO");
print " (and 23 is the leaf-cell count Module 20 established three ways)\n";QUESTION area cells hier syn
total cell area YES - - -
sequential cell count YES - - -
count of one cell type - YES - -
area of one sub-block - - YES -
constraint warnings - - - YES
every question is answered by EXACTLY ONE file:
total cell area counter_syn.area.rpt
sequential cell count counter_syn.area.rpt
count of one cell type counter_syn.cells.rpt
area of one sub-block counter_syn.hier.rpt
constraint warnings counter_syn.syn.log
and what the LOG does NOT contain:
the log cannot answer 'total cell area'
the log cannot answer 'sequential cell count'
the log cannot answer 'count of one cell type'
the log cannot answer 'area of one sub-block'
so scanning the log for a number that lives in a report finds
nothing -- and finding nothing is indistinguishable from zero.
cross-check: the cell count, from three different files
area report 'Number of cells': 23
sum of the cells report's Count: 23
hierarchy report's top-level Cells: 23
all three agree? YES
(and 23 is the leaf-cell count Module 20 established three ways)The answer matrix is a perfect diagonal. No file answers two of these questions, and no question is answered by two files.
That is worth pausing on, because it means "which report should I parse" is a real decision with exactly one right answer per question — not a preference, and not something to resolve by grepping everything.
2. Why The Log Is The Wrong File
Figure 22.1.1 — Which file answers which question
The measurement states the negative explicitly:
the log cannot answer 'total cell area'
the log cannot answer 'sequential cell count'
the log cannot answer 'count of one cell type'
the log cannot answer 'area of one sub-block'Four questions, four failures — and each one fails silently. A pattern for Total cell area: run against the log matches nothing, the variable stays undef, and Chapter 18.9 measured what happens next: undef becomes 0 the moment anybody does arithmetic with it, and an area of zero is a plausible number that no downstream check rejects.
So the division is:
The log answers "what happened". Warnings, the order of optimisation steps, which library was loaded, what the tool chose not to do. Chapter 22.6 parses it, and that is the only chapter that should.
The reports answer "what is true of the result". They are projections of one design along different axes, and each is small, tabular and stable — which is why a report parser is a dozen lines and a log parser is a module.
3. Three Files, One Number
The last block of the measurement is the habit worth taking from this chapter:
area report 'Number of cells': 23
sum of the cells report's Count: 23
hierarchy report's top-level Cells: 23
all three agree? YESThe same quantity appears in three reports, so you get a free cross-check — and it is the same argument Chapter 21.7 made about UVM's own severity counts, and Chapter 20.4 made about the simulator's VCD scopes. A parser verified only against itself is verified against its own assumptions.
And the number has history: 23 is the leaf-cell count Chapter 20.4 established three independent ways — a recursive expansion, an independent iterative one, and the simulator's own elaborated hierarchy. So four separate routes now agree on it, two of them outside this module entirely.
When they disagree, the direction tells you what happened, exactly as Chapter 21.7's three cases did:
The cells report sums low — your row pattern is missing rows. A cell type whose name contains a character your \w+ does not match, or a continuation line.
The hierarchy top is low — you are reading the wrong row as the top, or the report is truncated.
The area report differs from both — the tool counted something the other two do not, which usually means physical-only cells are included in one place and not another.
4. Before Writing Any Parser
Three steps, in order, and they take less time than the parser does.
List the questions. Not the files — the questions somebody will actually ask of the dashboard. "Did area grow?" "Did the flop count change?" "Which block got bigger?" "Are there new warnings?" Four questions is a realistic number, and this chapter's matrix is what you get by writing them down.
Find which file answers each one. grep for the number by hand, once, in each candidate file. This is the step that is skipped, and skipping it is what produces a log parser that hunts for an area figure.
Then check which file is authoritative when two contain it. Section 3's cross-check exists because three files carried the cell count. When two files disagree about a number, the report whose subject is that number wins — the area report for area, the reference report for counts.
And one habit that pays for itself immediately: record the file and the line you took each number from.
area => { value => 34.58, from => "counter_syn.area.rpt:21" }Six months later, when a number looks wrong, the question is always "where did this come from" — and Chapter 21.10 made the same argument about carrying a log line number into a report.
5. What To Remember
- The log records what the tool did; the reports answer what is true of the result.
- No synthesis tool exists here, so this module's reports are generated from the real Module 20 netlist, with the generators shipped and the format labelled (16.1).
- Measured: four questions against four files is a perfect diagonal — one file per question, no overlaps.
- "Which report" is a real decision with one right answer, not a preference.
- Measured: the log answers none of the four numeric questions, and each failure is silent.
- A pattern that matches nothing leaves
undef, which becomes0— and zero area is plausible enough to survive review (18.9). - Parse the log only for warnings (22.6); parse reports for everything else.
- Reports are small, tabular and stable — a report parser is a dozen lines.
- Measured: three reports agree on the cell count, 23.
- And 23 is the number Module 20 verified three independent ways — so four routes agree, two from outside this module.
- A parser verified only against itself is verified against its own assumptions (20.4, 21.7).
- When the three disagree, the direction localises the bug: a low cells sum means missing rows; a low hierarchy top means the wrong top row or a truncated file.
- Slurp a report, stream a log. 13.3's warning applies to the log, not to a few-hundred-line report (18.10).
- Before writing a parser: list the questions, find which file answers each, and decide which file is authoritative where two overlap.
- Record the file and line each number came from — six months later that is the only question (21.10).
Chapter 22.2 starts on the first of those files. Pulling three numbers out of an area report is four lines of Perl, and the chapter is mostly about the fact that the labels on those three numbers are not the same in every tool or every version.
Where this fits
Part of the Perl curriculum.
