Skip to content

Commit d14e705

Browse files
committed
Squashed 'libs/EXTERNAL/libtatum/' changes from ef121c8..f15f474
f15f474 Include Node and Edge IDs when throwing exceptions 3ef0e61 Report time spent re-ordering timing graph 4d4246c Add option to disable reporting 1fff3be Disable dumping .dot file by default 71d8f91 Add VTR multi-clock test case with non-default constraints git-subtree-dir: libs/EXTERNAL/libtatum git-subtree-split: f15f47439ba0f726dfd1a9e89361ff4ddc5302f3
1 parent 2152525 commit d14e705

File tree

5 files changed

+704
-50
lines changed

5 files changed

+704
-50
lines changed

libtatum/tatum/TimingGraph.cpp

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -575,39 +575,42 @@ bool TimingGraph::validate_values() const {
575575

576576
for(NodeId node_id : nodes()) {
577577
if(!valid_node_id(node_id)) {
578-
throw tatum::Error("Invalid node id");
578+
throw tatum::Error("Invalid node id", node_id);
579579
}
580580

581581
for(EdgeId edge_id : node_in_edges_[node_id]) {
582582
if(!valid_edge_id(edge_id)) {
583-
throw tatum::Error("Invalid node-in-edge reference");
583+
throw tatum::Error("Invalid node-in-edge reference", node_id, edge_id);
584584
}
585585

586586
//Check that the references are consistent
587587
if(edge_sink_nodes_[edge_id] != node_id) {
588-
throw tatum::Error("Mismatched edge-sink/node-in-edge reference");
588+
throw tatum::Error("Mismatched edge-sink/node-in-edge reference", node_id, edge_id);
589589
}
590590
}
591591
for(EdgeId edge_id : node_out_edges_[node_id]) {
592592
if(!valid_edge_id(edge_id)) {
593-
throw tatum::Error("Invalid node-out-edge reference");
593+
throw tatum::Error("Invalid node-out-edge reference", node_id, edge_id);
594594
}
595595

596596
//Check that the references are consistent
597597
if(edge_src_nodes_[edge_id] != node_id) {
598-
throw tatum::Error("Mismatched edge-src/node-out-edge reference");
598+
throw tatum::Error("Mismatched edge-src/node-out-edge reference", node_id, edge_id);
599599
}
600600
}
601601
}
602602
for(EdgeId edge_id : edges()) {
603603
if(!valid_edge_id(edge_id)) {
604-
throw tatum::Error("Invalid edge id");
604+
throw tatum::Error("Invalid edge id", edge_id);
605605
}
606-
if(!valid_node_id(edge_src_nodes_[edge_id])) {
607-
throw tatum::Error("Invalid edge source node");
606+
NodeId src_node = edge_src_nodes_[edge_id];
607+
if(!valid_node_id(src_node)) {
608+
throw tatum::Error("Invalid edge source node", src_node, edge_id);
608609
}
609-
if(!valid_node_id(edge_sink_nodes_[edge_id])) {
610-
throw tatum::Error("Invalid edge sink node");
610+
611+
NodeId sink_node = edge_sink_nodes_[edge_id];
612+
if(!valid_node_id(sink_node)) {
613+
throw tatum::Error("Invalid edge sink node", sink_node, edge_id);
611614
}
612615
}
613616

@@ -633,29 +636,29 @@ bool TimingGraph::validate_structure() const {
633636
//Check expected number of fan-in/fan-out edges
634637
if(src_type == NodeType::SOURCE) {
635638
if(in_edges.size() > 1) {
636-
throw tatum::Error("SOURCE node has more than one active incoming edge (expected 0 if primary input, or 1 if clocked)");
639+
throw tatum::Error("SOURCE node has more than one active incoming edge (expected 0 if primary input, or 1 if clocked)", src_node);
637640
}
638641
} else if (src_type == NodeType::SINK) {
639642
if(out_edges.size() > 0) {
640-
throw tatum::Error("SINK node has out-going edges");
643+
throw tatum::Error("SINK node has out-going edges", src_node);
641644
}
642645
} else if (src_type == NodeType::IPIN) {
643646
if(in_edges.size() == 0 && !allow_dangling_combinational_nodes_) {
644-
throw tatum::Error("IPIN has no in-coming edges");
647+
throw tatum::Error("IPIN has no in-coming edges", src_node);
645648
}
646649
if(out_edges.size() == 0 && !allow_dangling_combinational_nodes_) {
647-
throw tatum::Error("IPIN has no out-going edges");
650+
throw tatum::Error("IPIN has no out-going edges", src_node);
648651
}
649652
} else if (src_type == NodeType::OPIN) {
650653
//May have no incoming edges if a constant generator, so don't check that case
651654

652655
if(out_edges.size() == 0 && !allow_dangling_combinational_nodes_) {
653-
throw tatum::Error("OPIN has no out-going edges");
656+
throw tatum::Error("OPIN has no out-going edges", src_node);
654657
}
655658
} else {
656659
TATUM_ASSERT(src_type == NodeType::CPIN);
657660
if(in_edges.size() == 0) {
658-
throw tatum::Error("CPIN has no in-coming edges");
661+
throw tatum::Error("CPIN has no in-coming edges", src_node);
659662
}
660663
//We do not check for out-going cpin edges, since there is no reason that
661664
//a clock pin must be used
@@ -675,61 +678,61 @@ bool TimingGraph::validate_structure() const {
675678
&& sink_type != NodeType::OPIN
676679
&& sink_type != NodeType::CPIN
677680
&& sink_type != NodeType::SINK) {
678-
throw tatum::Error("SOURCE nodes should only drive IPIN, OPIN, CPIN or SINK nodes");
681+
throw tatum::Error("SOURCE nodes should only drive IPIN, OPIN, CPIN or SINK nodes", src_node, out_edge);
679682
}
680683

681684
if(sink_type == NodeType::SINK) {
682685
if( out_edge_type != EdgeType::INTERCONNECT
683686
&& out_edge_type != EdgeType::PRIMITIVE_COMBINATIONAL) {
684-
throw tatum::Error("SOURCE to SINK edges should always be either INTERCONNECT or PRIMTIIVE_COMBINATIONAL type edges");
687+
throw tatum::Error("SOURCE to SINK edges should always be either INTERCONNECT or PRIMTIIVE_COMBINATIONAL type edges", src_node, out_edge);
685688
}
686689

687690
} else if (sink_type == NodeType::OPIN) {
688691
if(out_edge_type != EdgeType::PRIMITIVE_COMBINATIONAL) {
689-
throw tatum::Error("SOURCE to OPIN edges should always be PRIMITIVE_COMBINATIONAL type edges");
692+
throw tatum::Error("SOURCE to OPIN edges should always be PRIMITIVE_COMBINATIONAL type edges", src_node, out_edge);
690693
}
691694
} else {
692695
TATUM_ASSERT(sink_type == NodeType::IPIN || sink_type == NodeType::CPIN);
693696
if(out_edge_type != EdgeType::INTERCONNECT) {
694-
throw tatum::Error("SOURCE to IPIN/CPIN edges should always be INTERCONNECT type edges");
697+
throw tatum::Error("SOURCE to IPIN/CPIN edges should always be INTERCONNECT type edges", src_node, out_edge);
695698
}
696699
}
697700

698701
} else if (src_type == NodeType::SINK) {
699-
throw tatum::Error("SINK nodes should not have out-going edges");
702+
throw tatum::Error("SINK nodes should not have out-going edges", sink_node);
700703
} else if (src_type == NodeType::IPIN) {
701704
if(sink_type != NodeType::OPIN && sink_type != NodeType::SINK) {
702-
throw tatum::Error("IPIN nodes should only drive OPIN or SINK nodes");
705+
throw tatum::Error("IPIN nodes should only drive OPIN or SINK nodes", src_node, out_edge);
703706
}
704707

705708
if(out_edge_type != EdgeType::PRIMITIVE_COMBINATIONAL) {
706-
throw tatum::Error("IPIN to OPIN/SINK edges should always be PRIMITIVE_COMBINATIONAL type edges");
709+
throw tatum::Error("IPIN to OPIN/SINK edges should always be PRIMITIVE_COMBINATIONAL type edges", src_node, out_edge);
707710
}
708711

709712
} else if (src_type == NodeType::OPIN) {
710713
if( sink_type != NodeType::IPIN
711714
&& sink_type != NodeType::CPIN
712715
&& sink_type != NodeType::SINK) {
713-
throw tatum::Error("OPIN nodes should only drive IPIN, CPIN or SINK nodes");
716+
throw tatum::Error("OPIN nodes should only drive IPIN, CPIN or SINK nodes", src_node, out_edge);
714717
}
715718

716719
if(out_edge_type != EdgeType::INTERCONNECT) {
717-
throw tatum::Error("OPIN out edges should always be INTERCONNECT type edges");
720+
throw tatum::Error("OPIN out edges should always be INTERCONNECT type edges", src_node, out_edge);
718721
}
719722

720723
} else if (src_type == NodeType::CPIN) {
721724
if( sink_type != NodeType::SOURCE
722725
&& sink_type != NodeType::SINK) {
723-
throw tatum::Error("CPIN nodes should only drive SOURCE or SINK nodes");
726+
throw tatum::Error("CPIN nodes should only drive SOURCE or SINK nodes", src_node, out_edge);
724727
}
725728

726729
if(sink_type == NodeType::SOURCE && out_edge_type != EdgeType::PRIMITIVE_CLOCK_LAUNCH) {
727-
throw tatum::Error("CPIN to SOURCE edges should always be PRIMITIVE_CLOCK_LAUNCH type edges");
730+
throw tatum::Error("CPIN to SOURCE edges should always be PRIMITIVE_CLOCK_LAUNCH type edges", src_node, out_edge);
728731
} else if (sink_type == NodeType::SINK && out_edge_type != EdgeType::PRIMITIVE_CLOCK_CAPTURE) {
729-
throw tatum::Error("CPIN to SINK edges should always be PRIMITIVE_CLOCK_CAPTURE type edges");
732+
throw tatum::Error("CPIN to SINK edges should always be PRIMITIVE_CLOCK_CAPTURE type edges", src_node, out_edge);
730733
}
731734
} else {
732-
throw tatum::Error("Unrecognized node type");
735+
throw tatum::Error("Unrecognized node type", src_node, out_edge);
733736
}
734737
}
735738
}
@@ -757,27 +760,27 @@ bool TimingGraph::validate_structure() const {
757760
for(EdgeId edge : edge_ids) {
758761
ss << edge << " ";
759762
}
760-
throw tatum::Error(ss.str());
763+
throw tatum::Error(ss.str(), src_node);
761764
}
762765
}
763766

764767
for(NodeId node : primary_inputs()) {
765768
if(!node_in_edges(node).empty()) {
766-
throw tatum::Error("Primary input nodes should have no incoming edges");
769+
throw tatum::Error("Primary input nodes should have no incoming edges", node);
767770
}
768771

769772
if(node_type(node) != NodeType::SOURCE) {
770-
throw tatum::Error("Primary inputs should be only SOURCE nodes");
773+
throw tatum::Error("Primary inputs should be only SOURCE nodes", node);
771774
}
772775
}
773776

774777
for(NodeId node : logical_outputs()) {
775778
if(!node_out_edges(node).empty()) {
776-
throw tatum::Error("Logical output node should have no outgoing edges");
779+
throw tatum::Error("Logical output node should have no outgoing edges", node);
777780
}
778781

779782
if(node_type(node) != NodeType::SINK) {
780-
throw tatum::Error("Logical outputs should be only SINK nodes");
783+
throw tatum::Error("Logical outputs should be only SINK nodes", node);
781784
}
782785
}
783786

@@ -912,10 +915,10 @@ EdgeType infer_edge_type(const TimingGraph& tg, EdgeId edge) {
912915
} else if(sink_node_type == NodeType::SINK) {
913916
return EdgeType::PRIMITIVE_CLOCK_CAPTURE;
914917
} else {
915-
throw tatum::Error("Invalid edge sink node (CPIN source node must connect to SOURCE or SINK sink node)");
918+
throw tatum::Error("Invalid edge sink node (CPIN source node must connect to SOURCE or SINK sink node)", sink_node, edge);
916919
}
917920
} else {
918-
throw tatum::Error("Invalid edge sink/source nodes");
921+
throw tatum::Error("Invalid edge sink/source nodes", edge);
919922
}
920923
}
921924

libtatum/tatum/base/validate_timing_graph_constraints.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ bool validate_timing_graph_constraints(const TimingGraph& timing_graph, const Ti
1919
msg = "Clock Domain " + std::to_string(size_t(domain)) + " (" + timing_constraints.clock_domain_name(domain) + ")"
2020
" source node " + std::to_string(size_t(source_node)) + " is not a node of type SOURCE.";
2121

22-
throw tatum::Error(msg);
22+
throw tatum::Error(msg, source_node);
2323
}
2424
}
2525
}
@@ -32,7 +32,7 @@ bool validate_timing_graph_constraints(const TimingGraph& timing_graph, const Ti
3232

3333
msg = "Timing Graph node " + std::to_string(size_t(node)) + " is an OPIN with no incoming edges, but is not marked as a constant generator";
3434

35-
throw tatum::Error(msg);
35+
throw tatum::Error(msg, node);
3636
}
3737
}
3838
}

libtatum/tatum/error.hpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,34 @@
22
#define TATUM_ERROR_HPP
33
#include <stdexcept>
44

5+
#include "tatum/TimingGraphFwd.hpp"
6+
57
namespace tatum {
68
class Error : public std::runtime_error {
79

810
public:
9-
template<typename ...Args>
10-
explicit Error(Args&&... args)
11-
: std::runtime_error(std::forward<Args>(args)...) {}
11+
//String only
12+
explicit Error(const std::string& what_str)
13+
: std::runtime_error(what_str) {}
14+
15+
//String and node
16+
explicit Error(const std::string& what_str, const NodeId n)
17+
: std::runtime_error(what_str)
18+
, node(n) {}
19+
20+
//String and edge
21+
explicit Error(const std::string& what_str, const EdgeId e)
22+
: std::runtime_error(what_str)
23+
, edge(e) {}
24+
25+
//String, node and edge
26+
explicit Error(const std::string& what_str, const NodeId n, const EdgeId e)
27+
: std::runtime_error(what_str)
28+
, node(n)
29+
, edge(e) {}
1230

31+
NodeId node; //The related node, may be invalid if unspecified
32+
EdgeId edge; //The related edge, may be invalid if unspecified
1333
};
1434

1535
}

tatum_test/main.cpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ struct Args {
8080
//Verify results match reference
8181
size_t verify = 0;
8282

83+
//Print reports
84+
size_t report = 1;
85+
8386
//Timing graph node whose transitive fanout is included in the
8487
//dumped .dot file (useful for debugging). Values < 0 dump the
8588
//entire graph.
@@ -113,23 +116,27 @@ void usage(std::string prog) {
113116
cout << " 0 uses delay model from input.\n";
114117
cout << " (default " << default_args.unit_delay << ")\n";
115118
cout << " --write_echo WRITE_ECHO: Write an echo file of restuls.\n";
116-
cout << " 0 implies no, non-zero implies yes.\n";
119+
cout << " empty implies no, non-empty implies write to specified file.\n";
117120
cout << " (default " << default_args.write_echo << ")\n";
118121
cout << " --opt_graph_layout OPT_LAYOUT: Optimize graph layout.\n";
119122
cout << " 0 implies no, non-zero implies yes.\n";
120123
cout << " (default " << default_args.opt_graph_layout << ")\n";
121124
cout << " --print_sizes PRINT_SIZES: Print various data structure sizes.\n";
122125
cout << " 0 implies no, non-zero implies yes.\n";
123126
cout << " (default " << default_args.print_sizes << ")\n";
127+
cout << " --report REPORT: Generate various reports.\n";
128+
cout << " 0 implies no, non-zero implies yes.\n";
129+
cout << " (default " << default_args.report << ")\n";
124130
cout << " --verify VERIFY: Verify calculated results match reference.\n";
125131
cout << " 0 implies no, non-zero implies yes.\n";
126132
cout << " (default " << default_args.verify << ")\n";
127133
cout << " --debug_dot_node NODEID: Specifies the timing graph node node whose transitive\n";
128134
cout << " connections are dumped to the .dot file (useful for debugging).\n";
129-
cout << " Values < 0 dump the entire graph,\n";
135+
cout << " Values < -1 dump the entire graph,\n";
136+
cout << " Values == -1 do not dump dot file,\n";
130137
cout << " Values >= 0 dump the transitive connections of\n";
131138
cout << " the matching node.\n";
132-
cout << " (default " << default_args.verify << ")\n";
139+
cout << " (default " << default_args.debug_dot_node << ")\n";
133140
}
134141

135142
void cmd_error(std::string prog, std::string msg) {
@@ -181,6 +188,8 @@ Args parse_args(int argc, char** argv) {
181188
args.opt_graph_layout = arg_val;
182189
} else if (argv[i] == std::string("--verify")) {
183190
args.verify = arg_val;
191+
} else if (argv[i] == std::string("--report")) {
192+
args.report = arg_val;
184193
} else if (argv[i] == std::string("--debug_dot_node")) {
185194
args.debug_dot_node = arg_val;
186195
} else {
@@ -216,8 +225,8 @@ int main(int argc, char** argv) {
216225

217226
int exit_code = 0;
218227

219-
struct timespec prog_start, load_start, verify_start;
220-
struct timespec prog_end, load_end, verify_end;
228+
struct timespec prog_start, load_start, opt_start, verify_start;
229+
struct timespec prog_end, load_end, opt_end, verify_end;
221230

222231
clock_gettime(CLOCK_MONOTONIC, &prog_start);
223232

@@ -316,7 +325,10 @@ int main(int argc, char** argv) {
316325

317326
if (args.opt_graph_layout) {
318327

328+
clock_gettime(CLOCK_MONOTONIC, &opt_start);
319329
auto id_maps = timing_graph->optimize_layout();
330+
clock_gettime(CLOCK_MONOTONIC, &opt_end);
331+
cout << "Optimizing graph took: " << tatum::time_sec(opt_start, opt_end) << " sec" << endl;
320332

321333
remap_delay_calculator(*timing_graph, *delay_calculator, id_maps.edge_id_map);
322334
timing_constraints->remap_nodes(id_maps.node_id_map);
@@ -391,13 +403,18 @@ int main(int argc, char** argv) {
391403
auto dot_writer = make_graphviz_dot_writer(*timing_graph, *delay_calculator);
392404

393405
std::vector<NodeId> nodes;
394-
if (args.debug_dot_node >= 0) {
406+
if (args.debug_dot_node == -1) {
407+
//Pass
408+
} else if (args.debug_dot_node < -1) {
409+
auto tg_nodes = timing_graph->nodes();
410+
nodes = std::vector<NodeId>(tg_nodes.begin(), tg_nodes.end());
411+
} else if (args.debug_dot_node >= 0) {
395412
nodes = find_transitively_connected_nodes(*timing_graph, {NodeId(args.debug_dot_node)});
396-
dot_writer.set_nodes_to_dump(nodes);
397413
}
414+
dot_writer.set_nodes_to_dump(nodes);
398415

399416
std::shared_ptr<tatum::SetupTimingAnalyzer> echo_setup_analyzer = std::dynamic_pointer_cast<tatum::SetupTimingAnalyzer>(serial_analyzer);
400-
if(echo_setup_analyzer) {
417+
if(args.report && echo_setup_analyzer) {
401418
//write_dot_file_setup("tg_setup_annotated.dot", *timing_graph, *delay_calculator, *echo_setup_analyzer, nodes);
402419
dot_writer.write_dot_file("tg_setup_annotated.dot", *echo_setup_analyzer);
403420
timing_reporter.report_timing_setup("report_timing.setup.rpt", *echo_setup_analyzer);
@@ -409,7 +426,7 @@ int main(int argc, char** argv) {
409426
detailed_timing_reporter.report_unconstrained_setup("report_unconstrained_timing_detailed.setup.rpt", *echo_setup_analyzer);
410427
}
411428
std::shared_ptr<tatum::HoldTimingAnalyzer> echo_hold_analyzer = std::dynamic_pointer_cast<tatum::HoldTimingAnalyzer>(serial_analyzer);
412-
if(echo_hold_analyzer) {
429+
if(args.report && echo_hold_analyzer) {
413430
//write_dot_file_hold("tg_hold_annotated.dot", *timing_graph, *delay_calculator, *echo_hold_analyzer, nodes);
414431
dot_writer.write_dot_file("tg_hold_annotated.dot", *echo_hold_analyzer);
415432
timing_reporter.report_timing_hold("report_timing.hold.rpt", *echo_hold_analyzer);

0 commit comments

Comments
 (0)