Skip to content

Commit 5ffb601

Browse files
committed
Squashed 'libs/EXTERNAL/libtatum/' changes from 751112a2c..d68a6b3ec
d68a6b3ec Fix typo causing compilation error cd5497e43 Improve comments in TimingAnalyzer 286b4cb0c Clean-up and improve commenting of incremental analyzers aeb7a90d0 Ensure only SINK nodes are placed in the logical outputs 8142eb60a Avoid sorting by pre-emptively skipping duplicates during incremental update 84d945ba6 Move node tag invalidation from enqueue to node traversal 41c60027d Produce separate callgrind profiles for each incremental update 377507b08 Wrap edge slack calculation in TATUM_CALCULATE_EDGE_SLACKS define ba0837132 Fix callgrind profiling configuration 72602d145 Add support for querying nodes modified by analzyer updates f54d05349 Disable debug prints 3339f82d0 Ensure stale node slacks are invalidated during incremental update e2ac16a42 Only dump dot for valid analyzers 1bd9e0447 Add support for checking only setup/hold/setuphold analysis from command line cbb0ffbf7 Add missing slack verification checks 9925563de Fix TimingGraph::logical_outputs() a4ce72ad5 Include missing header 1868b9470 Add missing incremental setup/hold analyzers 45cd38140 Add support for skipping clock edge invalidation during profiling (disabled) 54df64b18 Cleanup 1af66cd74 Fix processed level count f95f26ee2 Reduce invalidation pessimism for clock network delay changes 6a21936a6 Further clean-up to profiling and measurement code for incremental analysis 1ee01d939 Add --edge_change_prob option to tatum_test a9084fd3b Clean-up randomized profiling test 44907b473 Disable some debug code cecbedf7e Ensure that SOURCE node's driven by clocks correctly have their tags invalidated d8d44b6ff Fix handling of incremental updates to sinks 5bd072aaf Ignore generated files 4e785724f Include tag type in verification error messages c31fc923d Add support for running with sanitizers (disabled) bca158971 Fix uninitialized level range 9ddbc0d80 Fix verification of inf values 1a66299e5 Clean up compilation warnings 2c0622130 Add improved dominant edge-based incremental node invalidation 54b8ad8d8 Move incremental tag invalidation into separate enqueue functions 7d2f9c717 Remove commented code ea7732497 Fix incremental analysis when dominant timing edge changes 8d4f374c7 Add support for modifying edge delays and verifying correctness of incremental analysis 133e98c40 Add missing file 119279170 Add missing comparison operator d2d73e4bd Improve assertion handling of unused args 2dcedda50 Add support for profiling with randomly modified delays 7b371ab55 Initial implementation of level-based incremental update 03876efa6 Add reverse node-to-level lookup to TimingGraph 533771bc7 Add edge invalidation interface to TimingAnalyzer's and feed invalidations to GraphWalkers 08f21e3c2 Do not duplicate clocks tags during incremental analysis e6dc3f204 Add support for TimingTags::set_tag() which adds or updates a tag unconditionally 38c5deae3 Fix incremental required time update 605ab74b3 Various fixes to main tester 6a5836171 Do not repeatedly add data tags during incremental update 11533d523 Move sinks to last level of levelization (easier for incremental required time update) 6ee5a8833 Avoid creating duplicate required times on sink nodes during incremental updates a8bd7abd8 Initial incremental timing update support 0c320a75d Add initial SerialIncrWalker implementation and infrastructure 0657b5fdd Fix typo 78e9e9e2e Add failure message at end of executable e3a946df8 Update node traversal functions to return whether they caused modifications a997b7b90 Turn on test verification by default bb3bd3142 Remove unused code git-subtree-dir: libs/EXTERNAL/libtatum git-subtree-split: d68a6b3ec5a66fae97136e6e3135d7b34520660e
1 parent f7bc161 commit 5ffb601

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2087
-240
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,8 @@ callgrind*
4747
# Python temp files
4848
#
4949
*.pyc
50+
51+
#Generated Tatum files
52+
*.rpt
53+
*.dot
54+
*.echo

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,14 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
2020
#Only set compiler flags if not a sub-project
2121
set(WARN_FLAGS -Wall -Wextra -Wpedantic -Wcast-qual -Wcast-align -Wshadow -Wformat=2 -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wredundant-decls -Wswitch-default -Wundef -Wunused-variable -Wdisabled-optimization -Wnoexcept -Woverloaded-virtual -Wctor-dtor-privacy -Wnon-virtual-dtor)
2222

23+
set(SANITIZE_FLAGS -fsanitize=address -fsanitize=leak -fsanitize=undefined)
24+
2325
add_compile_options(${WARN_FLAGS})
2426
add_compile_options(-std=c++14)
2527

28+
#add_compile_options(${SANITIZE_FLAGS})
29+
#link_libraries(${SANITIZE_FLAGS})
30+
2631
set(FLEX_BISON_WARN_SUPPRESS_FLAGS -Wno-switch-default -Wno-unused-parameter -Wno-sign-compare -Wno-missing-declarations)
2732
endif()
2833

libtatum/tatum/HoldAnalysis.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ class HoldAnalysis : public detail::CommonAnalysisVisitor<detail::HoldAnalysisOp
6565

6666
TimingTags::tag_range hold_tags(const NodeId node) const { return ops_.get_tags(node); }
6767
TimingTags::tag_range hold_tags(const NodeId node, TagType type) const { return ops_.get_tags(node, type); }
68+
#ifdef TATUM_CALCULATE_EDGE_SLACKS
6869
TimingTags::tag_range hold_edge_slacks(const EdgeId edge) const { return ops_.get_edge_slacks(edge); }
70+
#endif
6971
TimingTags::tag_range hold_node_slacks(const NodeId node) const { return ops_.get_node_slacks(node); }
7072
};
7173

libtatum/tatum/SetupAnalysis.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ class SetupAnalysis : public detail::CommonAnalysisVisitor<detail::SetupAnalysis
132132

133133
TimingTags::tag_range setup_tags(const NodeId node) const { return ops_.get_tags(node); }
134134
TimingTags::tag_range setup_tags(const NodeId node, TagType type) const { return ops_.get_tags(node, type); }
135+
#ifdef TATUM_CALCULATE_EDGE_SLACKS
135136
TimingTags::tag_range setup_edge_slacks(const EdgeId edge) const { return ops_.get_edge_slacks(edge); }
137+
#endif
136138
TimingTags::tag_range setup_node_slacks(const NodeId node) const { return ops_.get_node_slacks(node); }
137139
};
138140

libtatum/tatum/SetupHoldAnalysis.hpp

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,38 @@ class SetupHoldAnalysis : public GraphVisitor {
2828
setup_visitor_.do_reset_node(node_id);
2929
hold_visitor_.do_reset_node(node_id);
3030
}
31+
32+
#ifdef TATUM_CALCULATE_EDGE_SLACKS
3133
void do_reset_edge(const EdgeId edge_id) override {
3234
setup_visitor_.do_reset_edge(edge_id);
3335
hold_visitor_.do_reset_edge(edge_id);
3436
}
37+
#endif
38+
39+
void do_reset_node_arrival_tags(const NodeId node_id) override {
40+
setup_visitor_.do_reset_node_arrival_tags(node_id);
41+
hold_visitor_.do_reset_node_arrival_tags(node_id);
42+
}
43+
44+
void do_reset_node_required_tags(const NodeId node_id) override {
45+
setup_visitor_.do_reset_node_required_tags(node_id);
46+
hold_visitor_.do_reset_node_required_tags(node_id);
47+
}
48+
49+
void do_reset_node_slack_tags(const NodeId node_id) override {
50+
setup_visitor_.do_reset_node_slack_tags(node_id);
51+
hold_visitor_.do_reset_node_slack_tags(node_id);
52+
}
53+
54+
void do_reset_node_arrival_tags_from_origin(const NodeId node_id, const NodeId origin) override {
55+
setup_visitor_.do_reset_node_arrival_tags_from_origin(node_id, origin);
56+
hold_visitor_.do_reset_node_arrival_tags_from_origin(node_id, origin);
57+
}
58+
59+
void do_reset_node_required_tags_from_origin(const NodeId node_id, const NodeId origin) override {
60+
setup_visitor_.do_reset_node_required_tags_from_origin(node_id, origin);
61+
hold_visitor_.do_reset_node_required_tags_from_origin(node_id, origin);
62+
}
3563

3664
bool do_arrival_pre_traverse_node(const TimingGraph& tg, const TimingConstraints& tc, const NodeId node_id) override {
3765
bool setup_unconstrained = setup_visitor_.do_arrival_pre_traverse_node(tg, tc, node_id);
@@ -47,29 +75,39 @@ class SetupHoldAnalysis : public GraphVisitor {
4775
return setup_unconstrained || hold_unconstrained;
4876
}
4977

50-
void do_arrival_traverse_node(const TimingGraph& tg, const TimingConstraints& tc, const DelayCalculator& dc, const NodeId node_id) override {
51-
setup_visitor_.do_arrival_traverse_node(tg, tc, dc, node_id);
52-
hold_visitor_.do_arrival_traverse_node(tg, tc, dc, node_id);
78+
bool do_arrival_traverse_node(const TimingGraph& tg, const TimingConstraints& tc, const DelayCalculator& dc, const NodeId node_id) override {
79+
bool setup_modified = setup_visitor_.do_arrival_traverse_node(tg, tc, dc, node_id);
80+
bool hold_modified = hold_visitor_.do_arrival_traverse_node(tg, tc, dc, node_id);
81+
82+
return setup_modified || hold_modified;
5383
}
5484

55-
void do_required_traverse_node(const TimingGraph& tg, const TimingConstraints& tc, const DelayCalculator& dc, const NodeId node_id) override {
56-
setup_visitor_.do_required_traverse_node(tg, tc, dc, node_id);
57-
hold_visitor_.do_required_traverse_node(tg, tc, dc, node_id);
85+
bool do_required_traverse_node(const TimingGraph& tg, const TimingConstraints& tc, const DelayCalculator& dc, const NodeId node_id) override {
86+
bool setup_modified = setup_visitor_.do_required_traverse_node(tg, tc, dc, node_id);
87+
bool hold_modified = hold_visitor_.do_required_traverse_node(tg, tc, dc, node_id);
88+
89+
return setup_modified || hold_modified;
5890
}
5991

60-
void do_slack_traverse_node(const TimingGraph& tg, const DelayCalculator& dc, const NodeId node) override {
61-
setup_visitor_.do_slack_traverse_node(tg, dc, node);
62-
hold_visitor_.do_slack_traverse_node(tg, dc, node);
92+
bool do_slack_traverse_node(const TimingGraph& tg, const DelayCalculator& dc, const NodeId node) override {
93+
bool setup_modified = setup_visitor_.do_slack_traverse_node(tg, dc, node);
94+
bool hold_modified = hold_visitor_.do_slack_traverse_node(tg, dc, node);
95+
96+
return setup_modified || hold_modified;
6397
}
6498

6599
TimingTags::tag_range setup_tags(const NodeId node_id) const { return setup_visitor_.setup_tags(node_id); }
66100
TimingTags::tag_range setup_tags(const NodeId node_id, TagType type) const { return setup_visitor_.setup_tags(node_id, type); }
101+
#ifdef TATUM_CALCULATE_EDGE_SLACKS
67102
TimingTags::tag_range setup_edge_slacks(const EdgeId edge_id) const { return setup_visitor_.setup_edge_slacks(edge_id); }
103+
#endif
68104
TimingTags::tag_range setup_node_slacks(const NodeId node_id) const { return setup_visitor_.setup_node_slacks(node_id); }
69105

70106
TimingTags::tag_range hold_tags(const NodeId node_id) const { return hold_visitor_.hold_tags(node_id); }
71107
TimingTags::tag_range hold_tags(const NodeId node_id, TagType type) const { return hold_visitor_.hold_tags(node_id, type); }
108+
#ifdef TATUM_CALCULATE_EDGE_SLACKS
72109
TimingTags::tag_range hold_edge_slacks(const EdgeId edge_id) const { return hold_visitor_.hold_edge_slacks(edge_id); }
110+
#endif
73111
TimingTags::tag_range hold_node_slacks(const NodeId node_id) const { return hold_visitor_.hold_node_slacks(node_id); }
74112

75113
SetupAnalysis& setup_visitor() { return setup_visitor_; }

libtatum/tatum/TimingGraph.cpp

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@ EdgeId TimingGraph::node_clock_launch_edge(const NodeId node) const {
167167
return EdgeId::INVALID();
168168
}
169169

170+
LevelId TimingGraph::node_level(const NodeId node) const {
171+
if (!is_levelized_) {
172+
return LevelId::INVALID();
173+
}
174+
return node_levels_[node];
175+
}
176+
170177

171178
NodeId TimingGraph::add_node(const NodeType type) {
172179
//Invalidate the levelization
@@ -329,6 +336,7 @@ void TimingGraph::force_levelize() {
329336
//Clear any previous levelization
330337
level_nodes_.clear();
331338
level_ids_.clear();
339+
node_levels_.clear();
332340
primary_inputs_.clear();
333341
logical_outputs_.clear();
334342

@@ -356,7 +364,7 @@ void TimingGraph::force_levelize() {
356364
if (node_type(node_id) == NodeType::SOURCE) {
357365
//We require that all primary inputs (i.e. top-level circuit inputs) to
358366
//be SOURCEs. Due to disconnected nodes we may have non-SOURCEs which
359-
//appear in the first level.
367+
//otherwise appear in the first level.
360368
primary_inputs_.push_back(node_id);
361369
}
362370
}
@@ -371,6 +379,8 @@ void TimingGraph::force_levelize() {
371379
int level_idx = 0;
372380
level_ids_.emplace_back(level_idx);
373381

382+
std::vector<NodeId> last_level;
383+
374384
bool inserted_node_in_level = true;
375385
while(inserted_node_in_level) { //If nothing was inserted we are finished
376386
inserted_node_in_level = false;
@@ -388,26 +398,29 @@ void TimingGraph::force_levelize() {
388398

389399
//Add to the next level if all fanin has been seen
390400
if(node_fanin_remaining[size_t(sink_node)] == 0) {
391-
//Ensure there is space by allocating the next level if required
392-
level_nodes_.resize(level_idx+2);
393401

394-
//Add the node
395-
level_nodes_[LevelId(level_idx+1)].push_back(sink_node);
396-
397-
inserted_node_in_level = true;
402+
if (node_out_edges(sink_node).size() != 0) {
403+
//Place into next level
404+
405+
//Ensure there is space by allocating the next level if required
406+
level_nodes_.resize(level_idx+2);
407+
408+
//Add the node
409+
level_nodes_[LevelId(level_idx+1)].push_back(sink_node);
410+
411+
inserted_node_in_level = true;
412+
} else {
413+
//No fan-out
414+
//
415+
//We choose to put these nodes into the *last* level,
416+
//since it makes it easier to walk back from them in the
417+
//required time traversal
418+
TATUM_ASSERT(node_out_edges(sink_node).size() == 0);
419+
420+
last_level.push_back(sink_node);
421+
}
398422
}
399423
}
400-
401-
//Also track the primary outputs (those with fan-in AND no fan-out)
402-
//
403-
// There may be some node with neither any fan-in or fan-out.
404-
// We will treat them as primary inputs, so they should not be to
405-
// the primary outputs
406-
if( node_out_edges(node_id).size() == 0
407-
&& node_in_edges(node_id).size() != 0
408-
&& node_type(node_id) == NodeType::SINK) {
409-
logical_outputs_.push_back(node_id);
410-
}
411424
}
412425

413426
if(inserted_node_in_level) {
@@ -416,6 +429,27 @@ void TimingGraph::force_levelize() {
416429
}
417430
}
418431

432+
//Add the last level to the end of the levelization
433+
level_nodes_.emplace_back(last_level);
434+
level_idx++;
435+
level_ids_.emplace_back(level_idx);
436+
437+
//Add SINK type nodes in the last level to logical outputs
438+
//Note that we only do this for sinks, since non-sink nodes may end up
439+
//in the last level (e.g. due to breaking combinational loops)
440+
auto is_sink = [this](NodeId id) {
441+
return this->node_type(id) == NodeType::SINK;
442+
};
443+
std::copy_if(last_level.begin(), last_level.end(), std::back_inserter(logical_outputs_), is_sink);
444+
445+
//Build the reverse node-to-level look-up
446+
node_levels_.resize(nodes().size());
447+
for (LevelId level : level_ids_) {
448+
for(NodeId node : level_nodes_[level]) {
449+
node_levels_[node] = level;
450+
}
451+
}
452+
419453
//Mark the levelization as valid
420454
is_levelized_ = true;
421455
}
@@ -562,7 +596,8 @@ bool TimingGraph::valid_level_id(const LevelId level_id) const {
562596
bool TimingGraph::validate_sizes() const {
563597
if ( node_ids_.size() != node_types_.size()
564598
|| node_ids_.size() != node_in_edges_.size()
565-
|| node_ids_.size() != node_out_edges_.size()) {
599+
|| node_ids_.size() != node_out_edges_.size()
600+
|| node_ids_.size() != node_levels_.size()) {
566601
throw tatum::Error("Inconsistent node attribute sizes");
567602
}
568603

@@ -794,6 +829,15 @@ bool TimingGraph::validate_structure() const {
794829
}
795830
}
796831

832+
//Check levelization look-up is consistent with levelization
833+
for (LevelId level : levels()) {
834+
for(NodeId node : level_nodes(level)) {
835+
if (node_level(node) != level) {
836+
throw tatum::Error("Node level look-up does not match levelization", node);
837+
}
838+
}
839+
}
840+
797841
auto sccs = identify_combinational_loops(*this);
798842
if(!sccs.empty()) {
799843
throw Error("Timing graph contains active combinational loops. "

libtatum/tatum/TimingGraph.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ class TimingGraph {
104104
///\returns The edge id corresponding to the incoming clock launch edge, or EdgeId::INVALID() if none
105105
EdgeId node_clock_launch_edge(const NodeId id) const;
106106

107+
///\param id The node id
108+
///\returns The level id corresponding to specified node
109+
LevelId node_level(const NodeId id) const;
110+
107111
/*
108112
* Edge accessors
109113
*/
@@ -280,6 +284,7 @@ class TimingGraph {
280284
tatum::util::linear_map<NodeId,NodeType> node_types_; //Type of node
281285
tatum::util::linear_map<NodeId,std::vector<EdgeId>> node_in_edges_; //Incomiing edge IDs for node
282286
tatum::util::linear_map<NodeId,std::vector<EdgeId>> node_out_edges_; //Out going edge IDs for node
287+
tatum::util::linear_map<NodeId,LevelId> node_levels_; //Out going edge IDs for node
283288

284289
//Edge data
285290
tatum::util::linear_map<EdgeId,EdgeId> edge_ids_; //The edge IDs in the graph

libtatum/tatum/analyzer_factory.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "tatum/graph_walkers.hpp"
1111
#include "tatum/timing_analyzers.hpp"
1212
#include "tatum/analyzers/full_timing_analyzers.hpp"
13+
#include "tatum/analyzers/incr_timing_analyzers.hpp"
1314

1415
namespace tatum {
1516

@@ -129,6 +130,52 @@ struct AnalyzerFactory<SetupHoldAnalysis,GraphWalker> {
129130
}
130131
};
131132

133+
134+
//Specialize for incremental setup
135+
template<>
136+
struct AnalyzerFactory<SetupAnalysis,SerialIncrWalker> {
137+
138+
static std::unique_ptr<SetupTimingAnalyzer> make(const TimingGraph& timing_graph,
139+
const TimingConstraints& timing_constraints,
140+
const DelayCalculator& delay_calc) {
141+
return std::unique_ptr<SetupTimingAnalyzer>(
142+
new detail::IncrSetupTimingAnalyzer<SerialIncrWalker>(timing_graph,
143+
timing_constraints,
144+
delay_calc)
145+
);
146+
}
147+
};
148+
149+
//Specialize for incremental hold
150+
template<>
151+
struct AnalyzerFactory<HoldAnalysis,SerialIncrWalker> {
152+
153+
static std::unique_ptr<HoldTimingAnalyzer> make(const TimingGraph& timing_graph,
154+
const TimingConstraints& timing_constraints,
155+
const DelayCalculator& delay_calc) {
156+
return std::unique_ptr<HoldTimingAnalyzer>(
157+
new detail::IncrHoldTimingAnalyzer<SerialIncrWalker>(timing_graph,
158+
timing_constraints,
159+
delay_calc)
160+
);
161+
}
162+
};
163+
164+
//Specialize for combined incremental setup and hold
165+
template<>
166+
struct AnalyzerFactory<SetupHoldAnalysis,SerialIncrWalker> {
167+
168+
static std::unique_ptr<SetupHoldTimingAnalyzer> make(const TimingGraph& timing_graph,
169+
const TimingConstraints& timing_constraints,
170+
const DelayCalculator& delay_calc) {
171+
return std::unique_ptr<SetupHoldTimingAnalyzer>(
172+
new detail::IncrSetupHoldTimingAnalyzer<SerialIncrWalker>(timing_graph,
173+
timing_constraints,
174+
delay_calc)
175+
);
176+
}
177+
};
178+
132179
} //namepsace
133180

134181
#endif

libtatum/tatum/analyzers/FullHoldTimingAnalyzer.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,23 @@ class FullHoldTimingAnalyzer : public HoldTimingAnalyzer {
5757
graph_walker_.set_profiling_data("num_full_updates", graph_walker_.get_profiling_data("num_full_updates") + 1);
5858
}
5959

60+
virtual void invalidate_edge_impl(const EdgeId edge) override {
61+
graph_walker_.invalidate_edge(edge);
62+
}
63+
64+
virtual node_range modified_nodes_impl() const override {
65+
return graph_walker_.modified_nodes();
66+
}
67+
6068
double get_profiling_data_impl(std::string key) const override { return graph_walker_.get_profiling_data(key); }
6169
size_t num_unconstrained_startpoints_impl() const override { return graph_walker_.num_unconstrained_startpoints(); }
6270
size_t num_unconstrained_endpoints_impl() const override { return graph_walker_.num_unconstrained_endpoints(); }
6371

6472
TimingTags::tag_range hold_tags_impl(NodeId node_id) const override { return hold_visitor_.hold_tags(node_id); }
6573
TimingTags::tag_range hold_tags_impl(NodeId node_id, TagType type) const override { return hold_visitor_.hold_tags(node_id, type); }
74+
#ifdef TATUM_CALCULATE_EDGE_SLACKS
6675
TimingTags::tag_range hold_edge_slacks_impl(EdgeId edge_id) const override { return hold_visitor_.hold_edge_slacks(edge_id); }
76+
#endif
6777
TimingTags::tag_range hold_node_slacks_impl(NodeId node_id) const override { return hold_visitor_.hold_node_slacks(node_id); }
6878

6979
private:

0 commit comments

Comments
 (0)