Skip to content

VPR: Add options for writing machine readable summary files #1947

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions doc/src/vpr/command_line_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,12 @@ For people not working on CAD, you can probably leave all the options to their d

**Default:** ``2``

.. option:: --write_block_usage <file>

Writes out to the file under path <file> cluster-level block usage summary in machine
readable (JSON or XML) or human readable (TXT) format. Format is selected
based on the extension of <file>.

.. _placer_options:

Placer Options
Expand Down Expand Up @@ -1035,6 +1041,17 @@ VPR uses a negotiated congestion algorithm (based on Pathfinder) to perform rout

**Default:** ``off``

.. option:: --write_timing_summary <file>

Writes out to the file under path <file> final timing summary in machine
readable (JSON or XML) or human readable (TXT) format. Format is selected
based on the extension of <file>. The summary consists of parameters:

* `cpd` - Final critical path delay (least slack) [ns]
* `fmax` - Maximal frequency of the implemented circuit [MHz]
* `swns` - setup Worst Negative Slack (sWNS) [ns]
* `stns` - Setup Total Negative Slack (sTNS) [ns]

.. _timing_driven_router_options:

Timing-Driven Router Options
Expand Down
156 changes: 156 additions & 0 deletions doc/src/vpr/file_formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1046,3 +1046,159 @@ An example of what a generated routing resource graph file would look like is sh
</rr_edges>
</rr_graph>
.. _end:

Block types usage summary (.txt .xml or .json)
-----------------------------------------

Block types usage summary is a file written in human or machine readable format.
It describes types and the amount of cluster-level FPGA resources that are used
by implemented design. This file is generated after the placement step with
option: `--write_block_usage <filename>`. It can be saved as a human readable
text file or in XML or JSON file to provide machine readable output. Format is
selected based on the extension of the `<filename>`.

The summary consists of 4 parameters:

* `nets number` - the amount of created nets
* `blocks number` - sum of blocks used to implement the design
* `input pins` - sum of input pins
* `output pins` - sum of output pins

and a list of `block types` followed by the number of specific block types that
are used in the design.

TXT
~~~

Presents the information in human readable format, the same as in log output:

.. code-block:: none
:caption: TXT format of block types usage summary
:linenos:

Netlist num_nets: <int>
Netlist num_blocks: <int>
Netlist <block_type_name_0> blocks: <int>
Netlist <block_type_name_1> blocks: <int>
...
Netlist <block_type_name_n> blocks: <int>
Netlist inputs pins: <int>
Netlist output pins: <int>

.. _end:

JSON
~~~~

One of two available machine readable formats. The information is written as follows:

.. code-block:: json
:caption: JSON format of block types usage summary
:linenos:

{
"num_nets": "<int>",
"num_blocks": "<int>",
"input_pins": "<int>",
"output_pins": "<int>",
"blocks": {
"<block_type_name_0>": <int>,
"<block_type_name_1>": <int>,
...
"<block_type_name_n>": <int>
}
}

.. _end:

XML
~~~

Second machine readable format. The information is written as follows:

.. code-block:: xml
:caption: XML format of block types usage summary
:linenos:

<?xml version="1.0" encoding="UTF-8"?>
<block_usage_report>
<nets num="<int>"></nets>
<blocks num="<int>">
<block type="<block_type_name_0>" usage="<int>"></block>
<block type="<block_type_name_1>" usage="<int>"></block>
...
<block type="<block_type_name_n>" usage="<int>"></block>
</blocks>
<input_pins num="<int>"></input_pins>
<output_pins num="<int>"></output_pins>
</block_usage_report>

.. _end:

Timing summary (.txt .xml or .json)
-----------------------------------------

Timing summary is a file written in human or machine readable format.
It describes final timing parameters of design implemented for the FPGA device.
This file is generated after the routing step with option: `--write_timing_summary <filename>`.
It can be saved as a human readable text file or in XML or JSON file to provide
machine readable output. Format is selected based on the extension of the `<filename>`.

The summary consists of 4 parameters:

* `Critical Path Delay (cpd) [ns]`
* `Max Circuit Frequency (Fmax) [MHz]`
* `setup Worst Negative Slack (sWNS) [ns]`
* `setup Total Negative Slack (sTNS) [ns]`

TXT
~~~

Presents the information in human readable format, the same as in log output:

.. code-block:: none
:caption: TXT format of timing summary
:linenos:

Final critical path delay (least slack): <double> ns, Fmax: <double> MHz
Final setup Worst Negative Slack (sWNS): <double> ns
Final setup Total Negative Slack (sTNS): <double> ns

.. _end:

JSON
~~~~

One of two available machine readable formats. The information is written as follows:

.. code-block:: json
:caption: JSON format of timing summary
:linenos:

{
"cpd": <double>,
"fmax": <double>,
"swns": <double>,
"stns": <double>
}

.. _end:

XML
~~~

Second machine readable format. The information is written as follows:

.. code-block:: xml
:caption: XML format of timing summary
:linenos:

<?xml version="1.0" encoding="UTF-8"?>
<timing_summary_report>
<cpd value="<double>" unit="ns" description="Final critical path delay"></nets>
<fmax value="<double>" unit="MHz" description="Max circuit frequency"></fmax>
<swns value="<double>" unit="ns" description="setup Worst Negative Slack (sWNS)"></swns>
<stns value="<double>" unit="ns" description="setup Total Negative Slack (sTNS)"></stns>
</block_usage_report>

.. _end:
2 changes: 1 addition & 1 deletion vpr/src/analysis/timing_reports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void generate_setup_timing_stats(const std::string& prefix, const SetupTimingInf
auto& timing_ctx = g_vpr_ctx.timing();
auto& atom_ctx = g_vpr_ctx.atom();

print_setup_timing_summary(*timing_ctx.constraints, *timing_info.setup_analyzer(), "Final ");
print_setup_timing_summary(*timing_ctx.constraints, *timing_info.setup_analyzer(), "Final ", analysis_opts.write_timing_summary);

VprTimingGraphResolver resolver(atom_ctx.nlist, atom_ctx.lookup, *timing_ctx.graph, delay_calc);
resolver.set_detail_level(analysis_opts.timing_report_detail);
Expand Down
2 changes: 2 additions & 0 deletions vpr/src/base/SetupVPR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ void SetupVPR(const t_options* Options,
FileNameOpts->out_file_prefix = Options->out_file_prefix;
FileNameOpts->read_vpr_constraints_file = Options->read_vpr_constraints_file;
FileNameOpts->write_vpr_constraints_file = Options->write_vpr_constraints_file;
FileNameOpts->write_block_usage = Options->write_block_usage;

FileNameOpts->verify_file_digests = Options->verify_file_digests;

Expand Down Expand Up @@ -630,6 +631,7 @@ static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysi
analysis_opts.post_synth_netlist_unconn_output_handling = Options.post_synth_netlist_unconn_output_handling;

analysis_opts.timing_update_type = Options.timing_update_type;
analysis_opts.write_timing_summary = Options.write_timing_summary;
}

static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t_arch* Arch) {
Expand Down
119 changes: 103 additions & 16 deletions vpr/src/base/ShowSetup.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <fstream>

#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_memory.h"
Expand Down Expand Up @@ -61,21 +63,70 @@ void ShowSetup(const t_vpr_setup& vpr_setup) {
}
}

void printClusteredNetlistStats() {
auto& device_ctx = g_vpr_ctx.device();
auto& cluster_ctx = g_vpr_ctx.clustering();
void ClusteredNetlistStats::writeHuman(std::ostream& output) const {
output << "Cluster level netlist and block usage statistics\n";
output << "Netlist num_nets: " << num_nets << "\n";
output << "Netlist num_blocks: " << num_blocks << "\n";
for (const auto& type : logical_block_types) {
output << "Netlist " << type.name << " blocks: " << num_blocks_type[type.index] << ".\n";
}

output << "Netlist inputs pins: " << L_num_p_inputs << "\n";
output << "Netlist output pins: " << L_num_p_outputs << "\n";
}
void ClusteredNetlistStats::writeJSON(std::ostream& output) const {
output << "{\n";

int j, L_num_p_inputs, L_num_p_outputs;
std::vector<int> num_blocks_type(device_ctx.logical_block_types.size(), 0);
output << " \"num_nets\": \"" << num_nets << "\",\n";
output << " \"num_blocks\": \"" << num_blocks << "\",\n";

VTR_LOG("\n");
VTR_LOG("Netlist num_nets: %d\n", (int)cluster_ctx.clb_nlist.nets().size());
VTR_LOG("Netlist num_blocks: %d\n", (int)cluster_ctx.clb_nlist.blocks().size());
output << " \"input_pins\": \"" << L_num_p_inputs << "\",\n";
output << " \"output_pins\": \"" << L_num_p_outputs << "\",\n";

/* Count I/O input and output pads */
output << " \"blocks\": {\n";

for (const auto& type : logical_block_types) {
output << " \"" << type.name << "\": " << num_blocks_type[type.index];
if ((int)type.index < (int)logical_block_types.size() - 1)
output << ",\n";
else
output << "\n";
}
output << " }\n";
output << "}\n";
}

void ClusteredNetlistStats::writeXML(std::ostream& output) const {
output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
output << "<block_usage_report>\n";

output << " <nets num=\"" << num_nets << "\"></nets>\n";
output << " <blocks num=\"" << num_blocks << "\">\n";

for (const auto& type : logical_block_types) {
output << " <block type=\"" << type.name << "\" usage=\"" << num_blocks_type[type.index] << "\"></block>\n";
}
output << " </blocks>\n";

output << " <input_pins num=\"" << L_num_p_inputs << "\"></input_pins>\n";
output << " <output_pins num=\"" << L_num_p_outputs << "\"></output_pins>\n";

output << "</block_usage_report>\n";
}

ClusteredNetlistStats::ClusteredNetlistStats() {
auto& device_ctx = g_vpr_ctx.device();
auto& cluster_ctx = g_vpr_ctx.clustering();

int j;
L_num_p_inputs = 0;
L_num_p_outputs = 0;
num_blocks_type = std::vector<int>(device_ctx.logical_block_types.size(), 0);
num_nets = (int)cluster_ctx.clb_nlist.nets().size();
num_blocks = (int)cluster_ctx.clb_nlist.blocks().size();
logical_block_types = device_ctx.logical_block_types;

/* Count I/O input and output pads */
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id);
auto physical_tile = pick_physical_type(logical_block);
Expand All @@ -97,16 +148,52 @@ void printClusteredNetlistStats() {
}
}
}
}

for (const auto& type : device_ctx.logical_block_types) {
VTR_LOG("Netlist %s blocks: %d.\n", type.name, num_blocks_type[type.index]);
void ClusteredNetlistStats::write(OutputFormat fmt, std::ostream& output) const {
switch (fmt) {
case HumanReadable:
writeHuman(output);
break;
case JSON:
writeJSON(output);
break;
case XML:
writeXML(output);
break;
default:
VPR_FATAL_ERROR(VPR_ERROR_PACK,
"Unknown extension on in block usage summary file");
break;
}
}

/* Print out each block separately instead */
VTR_LOG("Netlist inputs pins: %d\n", L_num_p_inputs);
VTR_LOG("Netlist output pins: %d\n", L_num_p_outputs);
VTR_LOG("\n");
num_blocks_type.clear();
void writeClusteredNetlistStats(std::string block_usage_filename) {
const auto stats = ClusteredNetlistStats();

// Print out the human readable version to stdout

stats.write(ClusteredNetlistStats::OutputFormat::HumanReadable, std::cout);

if (block_usage_filename.size() > 0) {
ClusteredNetlistStats::OutputFormat fmt;

if (vtr::check_file_name_extension(block_usage_filename.c_str(), ".json")) {
fmt = ClusteredNetlistStats::OutputFormat::JSON;
} else if (vtr::check_file_name_extension(block_usage_filename.c_str(), ".xml")) {
fmt = ClusteredNetlistStats::OutputFormat::XML;
} else if (vtr::check_file_name_extension(block_usage_filename.c_str(), ".txt")) {
fmt = ClusteredNetlistStats::OutputFormat::HumanReadable;
} else {
VPR_FATAL_ERROR(VPR_ERROR_PACK, "Unknown extension on output %s", block_usage_filename.c_str());
}

std::fstream fp;

fp.open(block_usage_filename, std::fstream::out | std::fstream::trunc);
stats.write(fmt, fp);
fp.close();
}
}

static void ShowAnnealSched(const t_annealing_sched& AnnealSched) {
Expand Down
27 changes: 26 additions & 1 deletion vpr/src/base/ShowSetup.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
#ifndef SHOWSETUP_H
#define SHOWSETUP_H

struct ClusteredNetlistStats {
private:
void writeHuman(std::ostream& output) const;
void writeJSON(std::ostream& output) const;
void writeXML(std::ostream& output) const;

public:
ClusteredNetlistStats();

enum OutputFormat {
HumanReadable,
JSON,
XML
};

int num_nets;
int num_blocks;
int L_num_p_inputs;
int L_num_p_outputs;
std::vector<int> num_blocks_type;
std::vector<t_logical_block_type> logical_block_types;

void write(OutputFormat fmt, std::ostream& output) const;
};

void ShowSetup(const t_vpr_setup& vpr_setup);
void printClusteredNetlistStats();
void writeClusteredNetlistStats(std::string block_usage_filename);

#endif
Loading