Skip to content
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

Adding Number of Logic levels and number of timing graph levels to ti… #2383

Open
wants to merge 2 commits into
base: openfpga
Choose a base branch
from
Open
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
22 changes: 13 additions & 9 deletions libs/EXTERNAL/libtatum/libtatum/tatum/TimingReporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,32 +86,32 @@ TimingReporter::TimingReporter(const TimingGraphNameResolver& name_resolver,

void TimingReporter::report_timing_setup(std::string filename,
const SetupTimingAnalyzer& setup_analyzer,
size_t npaths) const {
size_t npaths, const int num_logic_levels) const {
std::ofstream os(filename);
report_timing_setup(os, setup_analyzer, npaths);
report_timing_setup(os, setup_analyzer, npaths, num_logic_levels);
}

void TimingReporter::report_timing_setup(std::ostream& os,
const SetupTimingAnalyzer& setup_analyzer,
size_t npaths) const {
size_t npaths, const int num_logic_levels) const {
auto paths = path_collector_.collect_worst_setup_timing_paths(timing_graph_, setup_analyzer, npaths);

report_timing(os, paths);
report_timing(os, paths, num_logic_levels);
}

void TimingReporter::report_timing_hold(std::string filename,
const HoldTimingAnalyzer& hold_analyzer,
size_t npaths) const {
size_t npaths, const int num_logic_levels) const {
std::ofstream os(filename);
report_timing_hold(os, hold_analyzer, npaths);
report_timing_hold(os, hold_analyzer, npaths, num_logic_levels);
}

void TimingReporter::report_timing_hold(std::ostream& os,
const HoldTimingAnalyzer& hold_analyzer,
size_t npaths) const {
size_t npaths, const int num_logic_levels) const {
auto paths = path_collector_.collect_worst_hold_timing_paths(timing_graph_, hold_analyzer, npaths);

report_timing(os, paths);
report_timing(os, paths, num_logic_levels);
}

void TimingReporter::report_skew_setup(std::string filename,
Expand Down Expand Up @@ -195,14 +195,18 @@ void TimingReporter::report_unconstrained_hold(std::ostream& os,
*/

void TimingReporter::report_timing(std::ostream& os,
const std::vector<TimingPath>& paths) const {
const std::vector<TimingPath>& paths, const int num_logic_levels) const {
tatum::OsFormatGuard flag_guard(os);

os << "#Timing report of worst " << paths.size() << " path(s)\n";
os << "# Unit scale: " << std::setprecision(0) << std::scientific << unit_scale_ << " seconds\n";
os << "# Output precision: " << precision_ << "\n";
os << "\n";

os << "# Logical Levels: " << num_logic_levels << "\n";
os << "# Timing Graph Levels: " << timing_graph_.levels().size() << "\n";
os << "\n";

size_t i = 0;
for(const auto& path : paths) {
os << "#Path " << ++i << "\n";
Expand Down
10 changes: 5 additions & 5 deletions libs/EXTERNAL/libtatum/libtatum/tatum/TimingReporter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ class TimingReporter {
float unit_scale=1e-9,
size_t precision=3);
public:
void report_timing_setup(std::string filename, const tatum::SetupTimingAnalyzer& setup_analyzer, size_t npaths=REPORT_TIMING_DEFAULT_NPATHS) const;
void report_timing_setup(std::ostream& os, const tatum::SetupTimingAnalyzer& setup_analyzer, size_t npaths=REPORT_TIMING_DEFAULT_NPATHS) const;
void report_timing_setup(std::string filename, const tatum::SetupTimingAnalyzer& setup_analyzer, size_t npaths=REPORT_TIMING_DEFAULT_NPATHS, const int num_logic_levels=0) const;
void report_timing_setup(std::ostream& os, const tatum::SetupTimingAnalyzer& setup_analyzer, size_t npaths=REPORT_TIMING_DEFAULT_NPATHS, const int num_logic_levels=0) const;

void report_timing_hold(std::string filename, const tatum::HoldTimingAnalyzer& hold_analyzer, size_t npaths=REPORT_TIMING_DEFAULT_NPATHS) const;
void report_timing_hold(std::ostream& os, const tatum::HoldTimingAnalyzer& hold_analyzer, size_t npaths=REPORT_TIMING_DEFAULT_NPATHS) const;
void report_timing_hold(std::string filename, const tatum::HoldTimingAnalyzer& hold_analyzer, size_t npaths=REPORT_TIMING_DEFAULT_NPATHS, const int num_logic_levels=0) const;
void report_timing_hold(std::ostream& os, const tatum::HoldTimingAnalyzer& hold_analyzer, size_t npaths=REPORT_TIMING_DEFAULT_NPATHS, const int num_logic_levels=0) const;

void report_skew_setup(std::string filename, const tatum::SetupTimingAnalyzer& setup_analyzer, size_t nworst=REPORT_TIMING_DEFAULT_NPATHS) const;
void report_skew_setup(std::ostream& os, const tatum::SetupTimingAnalyzer& setup_analyzer, size_t nworst=REPORT_TIMING_DEFAULT_NPATHS) const;
Expand Down Expand Up @@ -94,7 +94,7 @@ class TimingReporter {
};

private:
void report_timing(std::ostream& os, const std::vector<TimingPath>& paths) const;
void report_timing(std::ostream& os, const std::vector<TimingPath>& paths, const int num_logic_levels) const;

void report_timing_path(std::ostream& os, const TimingPath& path) const;

Expand Down
4 changes: 2 additions & 2 deletions vpr/src/analysis/timing_reports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void generate_setup_timing_stats(const std::string& prefix, const SetupTimingInf

tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, *timing_ctx.constraints);

timing_reporter.report_timing_setup(prefix + "report_timing.setup.rpt", *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths);
timing_reporter.report_timing_setup(prefix + "report_timing.setup.rpt", *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths, g_vpr_ctx.logic_levels().num_logic_levels());

if (analysis_opts.timing_report_skew) {
timing_reporter.report_skew_setup(prefix + "report_skew.setup.rpt", *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths);
Expand All @@ -43,7 +43,7 @@ void generate_hold_timing_stats(const std::string& prefix, const HoldTimingInfo&

tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, *timing_ctx.constraints);

timing_reporter.report_timing_hold(prefix + "report_timing.hold.rpt", *timing_info.hold_analyzer(), analysis_opts.timing_report_npaths);
timing_reporter.report_timing_hold(prefix + "report_timing.hold.rpt", *timing_info.hold_analyzer(), analysis_opts.timing_report_npaths, g_vpr_ctx.logic_levels().num_logic_levels());

if (analysis_opts.timing_report_skew) {
timing_reporter.report_skew_hold(prefix + "report_skew.hold.rpt", *timing_info.hold_analyzer(), analysis_opts.timing_report_npaths);
Expand Down
4 changes: 3 additions & 1 deletion vpr/src/base/vpr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,8 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {
return true;
}

g_vpr_ctx.mutable_logic_levels().levelize();

{ //Pack
bool pack_success = vpr_pack_flow(vpr_setup, arch);

Expand Down Expand Up @@ -1596,4 +1598,4 @@ void vpr_print_error(const VprError& vpr_error) {
VTR_LOG_ERROR("\nType: %s\nFile: %s\nLine: %d\nMessage: %s\n",
error_type, filename.c_str(), vpr_error.line(),
msg.c_str());
}
}
10 changes: 10 additions & 0 deletions vpr/src/base/vpr_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,9 @@ class VprContext : public Context {
const PackingMultithreadingContext& packing_multithreading() const { return packing_multithreading_; }
PackingMultithreadingContext& mutable_packing_multithreading() { return packing_multithreading_; }

const Levelized& logic_levels() const {return logic_levels_;}
Levelized& mutable_logic_levels() {return logic_levels_;}

private:
DeviceContext device_;

Expand All @@ -656,6 +659,13 @@ class VprContext : public Context {
NocContext noc_;

PackingMultithreadingContext packing_multithreading_;

/**
* @brief The Levelized class represents a graph that has been levelized, allowing efficient traversal and analysis.
* It provides methods to perform graph levelization, check if the graph has been levelized, and access information about
* nodes in each logic level and the total number of logic levels.
*/
Levelized logic_levels_;
};

#endif
136 changes: 133 additions & 3 deletions vpr/src/util/vpr_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ const t_port* find_pb_graph_port(const t_pb_graph_node* pb_gnode, std::string po

const t_pb_graph_pin* find_pb_graph_pin(const t_pb_graph_node* pb_gnode, std::string port_name, int index) {
for (int iport = 0; iport < pb_gnode->num_input_ports; iport++) {
if (pb_gnode->num_input_pins[iport] < index) continue;
if (pb_gnode->num_input_pins[iport] <= index) continue;

const t_pb_graph_pin* gpin = &pb_gnode->input_pins[iport][index];

Expand All @@ -1191,7 +1191,7 @@ const t_pb_graph_pin* find_pb_graph_pin(const t_pb_graph_node* pb_gnode, std::st
}
}
for (int iport = 0; iport < pb_gnode->num_output_ports; iport++) {
if (pb_gnode->num_output_pins[iport] < index) continue;
if (pb_gnode->num_output_pins[iport] <= index) continue;

const t_pb_graph_pin* gpin = &pb_gnode->output_pins[iport][index];

Expand All @@ -1200,7 +1200,7 @@ const t_pb_graph_pin* find_pb_graph_pin(const t_pb_graph_node* pb_gnode, std::st
}
}
for (int iport = 0; iport < pb_gnode->num_clock_ports; iport++) {
if (pb_gnode->num_clock_pins[iport] < index) continue;
if (pb_gnode->num_clock_pins[iport] <= index) continue;

const t_pb_graph_pin* gpin = &pb_gnode->clock_pins[iport][index];

Expand Down Expand Up @@ -2523,3 +2523,133 @@ void add_pb_child_to_list(std::list<const t_pb*>& pb_list, const t_pb* parent_pb
}
}
}


// Function to perform graph levelization
void Levelized::levelize() {
//Levelizes the graph
const auto& atom_nlist = g_vpr_ctx.atom().nlist;
const auto atom_lookup = g_vpr_ctx.atom().lookup;

const auto tg_ = g_vpr_ctx.timing().graph;
// vtr::vector_map<int , std::vector<AtomBlockId>> level_nodes; //Nodes in each level

//Allocate space for the first level
level_nodes_.resize(1);

//Copy the number of input edges per-node
//These will be decremented to know when all a node's upstream parents have been
//placed in a previous level (indicating that the node goes in the current level)
//
//Also initialize the first level (nodes with no fanin)
std::vector<int> node_fanin_remaining(atom_nlist.blocks().size());
for(auto node_id : atom_nlist.blocks()) {
size_t node_fanin = 0;
for(auto in_pin: atom_nlist.block_input_pins(node_id)){
auto sink_tnode = atom_lookup.atom_pin_tnode(in_pin);
auto net_id = atom_nlist.pin_net(in_pin);
auto source_pin = atom_nlist.net_driver(net_id);
auto source_tnode = atom_lookup.atom_pin_tnode(source_pin);
auto edge = tg_->find_edge(source_tnode, sink_tnode);
if(tg_->edge_disabled(edge)) continue;
++node_fanin;
}
node_fanin_remaining[size_t(node_id)] = node_fanin;

//Initialize the first level
if(node_fanin == 0) {
level_nodes_[0].push_back(node_id);

// if (atom_nlist.block_type(node_id) == AtomBlockType::INPAD) {
// //We require that all primary inputs (i.e. top-level circuit inputs) to
// //be SOURCEs. Due to disconnected nodes we may have non-SOURCEs which
// //otherwise appear in the first level.
// primary_inputs.push_back(node_id);
// }
}
}

//Walk the graph from primary inputs (no fanin) to generate a topological sort
//
//We inspect the output edges of each node and decrement the fanin count of the
//target node. Once the fanin count for a node reaches zero it can be added
//to the current level.
int level_idx = 0;

std::vector<AtomBlockId> last_level;
vtr::vector<AtomBlockId, bool> visited(atom_nlist.blocks().size(), false);

bool inserted_node_in_level = true;
while(inserted_node_in_level) { //If nothing was inserted we are finished
inserted_node_in_level = false;

for(const auto node_id : level_nodes_[level_idx]) {
//Inspect the fanout
for(auto out_pin: atom_nlist.block_output_pins(node_id)){
auto source_tnode = atom_lookup.atom_pin_tnode(out_pin);
auto net_id = atom_nlist.pin_net(out_pin);
for(auto sink_pin: atom_nlist.net_sinks(net_id)){
auto sink_tnode = atom_lookup.atom_pin_tnode(sink_pin);
auto edge = tg_->find_edge(source_tnode, sink_tnode);
if(tg_->edge_disabled(edge)) continue;
auto blk_id = atom_nlist.pin_block(sink_pin);
VTR_ASSERT((node_fanin_remaining[(size_t)blk_id] > 0 && !visited[blk_id]) ||
(node_fanin_remaining[(size_t)blk_id] <= 0 && visited[blk_id]));
node_fanin_remaining[(size_t)blk_id]--;

if(node_fanin_remaining[(size_t)blk_id] == 0){
if (atom_nlist.block_type(node_id) != AtomBlockType::OUTPAD){
level_nodes_.resize(level_idx+2);
level_nodes_[level_idx+1].push_back(blk_id);
inserted_node_in_level = true;
visited[blk_id] = true;
}
else{
VTR_ASSERT(atom_nlist.block_output_pins(blk_id).size() == 0);
last_level.push_back(blk_id);
}
}
}

}
}

if(inserted_node_in_level) {
level_idx++;
}
}

//Add the last level to the end of the levelization
level_nodes_.emplace_back(last_level);
level_idx++;

//Add SINK type nodes in the last level to logical outputs
//Note that we only do this for sinks, since non-sink nodes may end up
//in the last level (e.g. due to breaking combinational loops)
// auto is_sink = [this](NodeId id) {
// return this->node_type(id) == NodeType::SINK;
// };
// std::copy_if(last_level.begin(), last_level.end(), std::back_inserter(logical_outputs_), is_sink);

//Mark the levelization as valid
is_levelized_ = true;
num_logic_levels_ = level_idx;
}


// Function to check if the graph has been levelized
bool Levelized::is_levelized() const{
return is_levelized_;
}


// Function to get a pointer to the map of nodes in each level
vtr::vector_map<int , std::vector<AtomBlockId>>* Levelized::level_nodes(){
return &level_nodes_;
}


// Function to get the number of logic levels in the levelized graph
int Levelized::num_logic_levels() const{
return num_logic_levels_;
}
19 changes: 19 additions & 0 deletions vpr/src/util/vpr_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,4 +317,23 @@ void add_pb_child_to_list(std::list<const t_pb*>& pb_list, const t_pb* parent_pb
class VprConstraints;
void apply_route_constraints(VprConstraints& constraint);


// Class definition for a levelized graph
/**
* @brief The Levelized class represents a graph that has been levelized, allowing efficient traversal and analysis.
* It provides methods to perform graph levelization, check if the graph has been levelized, and access information about
* nodes in each logic level and the total number of logic levels.
*/
class Levelized{
public:
void levelize(); // Function to perform graph levelization
bool is_levelized() const; // Check if the graph has been levelized
vtr::vector_map<int , std::vector<AtomBlockId>>* level_nodes(); // Get a pointer to the map of nodes in each level
int num_logic_levels() const; // Get the number of logic levels in the levelized graph
private:
vtr::vector_map<int , std::vector<AtomBlockId>> level_nodes_; //Nodes in each level
bool is_levelized_; // Flag to indicate whether graph has been levelized
int num_logic_levels_; // Number of logic levels in the levelized graph
};

#endif