Implemented #500 (limit number of shapes in net tracer)

This commit is contained in:
Matthias Koefferlein 2020-02-23 11:02:15 +01:00
parent e790ec661e
commit d01759aa60
12 changed files with 348 additions and 177 deletions

View File

@ -53,6 +53,20 @@
the "Trace Net" button again.
</p>
<p>
Sometimes you encounter large nets (e.g. power nets). When you click on such a net, the tracer will start running and
the extraction will take a long time. If you're not interested in the details of such nets, you can limit the depth
of the net tracing. This means, after a specified number of shapes is encountered, the tracer will stop and report
the shapes collected so far as an incomplete net.
</p>
<p>
To configure the depth, enter the desired number of shapes in the
"Trace depth" box at the bottom of the trace dialog. NOTE: the actual number of shapes in the net may be a litte
less than the specified depth due to internal marker shapes which are taken into account, but are not delivered
as parts of the net.
</p>
<p>
The "Trace Path" function works similar but allows specification of two points and let the algorithm find the shortest connection
(in terms of shape count, not geometrical length) between those points. If the points are not connected, a message is given

View File

@ -840,7 +840,7 @@ NetTracerLayerExpression::make_l2n_region (db::LayoutToNetlist &l2n, std::map <u
// NetTracer implementation
NetTracer::NetTracer ()
: mp_layout (0), mp_cell (0), mp_progress (0), m_name_hier_depth (-1), m_incomplete (false)
: mp_layout (0), mp_cell (0), mp_progress (0), m_name_hier_depth (-1), m_incomplete (false), m_trace_depth (0)
{
// .. nothing yet ..
}
@ -1187,6 +1187,17 @@ NetTracer::trace (const db::Layout &layout, const db::Cell &cell, const NetTrace
m_incomplete = false;
mp_progress = 0;
} catch (tl::BreakException &) {
m_shapes_graph.clear ();
m_hit_test_queue.clear ();
m_incomplete = true;
mp_progress = 0;
// on user break or depth exhausted just keep the shapes
return;
} catch (...) {
m_shapes_graph.clear ();
@ -1311,6 +1322,10 @@ NetTracer::deliver_shape (const NetTracerShape &net_shape, const NetTracerShape
if (! m_stop_shape.is_valid ()) {
if (m_trace_depth > 0 && m_shapes_found.size () >= m_trace_depth) {
throw tl::BreakException ();
}
std::pair<std::set <NetTracerShape>::iterator, bool> f = m_shapes_found.insert (net_shape);
if (f.second) {
if (mp_progress) {
@ -1326,6 +1341,10 @@ NetTracer::deliver_shape (const NetTracerShape &net_shape, const NetTracerShape
std::map <NetTracerShape, std::vector<const NetTracerShape *> >::iterator n = m_shapes_graph.find (net_shape);
if (n == m_shapes_graph.end ()) {
if (m_trace_depth > 0 && m_shapes_graph.size () >= m_trace_depth) {
throw tl::BreakException ();
}
n = m_shapes_graph.insert (std::make_pair (net_shape, std::vector<const NetTracerShape *> ())).first;
if (mp_progress) {

View File

@ -695,6 +695,24 @@ public:
return m_shapes_found.end ();
}
/**
* @brief Sets the maximum number of shapes to trace
*
* Setting the trace depth to 0 is equivalent to "unlimited".
*/
void set_trace_depth (size_t n)
{
m_trace_depth = n;
}
/**
* @brief Gets the maximum number of shapes to trace
*/
size_t trace_depth () const
{
return m_trace_depth;
}
/**
* @brief Returns the number of shapes found
*/
@ -707,7 +725,7 @@ public:
* @brief Returns true, if the net is incomplete
*
* This flag is true if the extractor was aborted
* for example by the user.
* for example by the user or the trace depth was exhausted.
* The shapes do not fully cover the net.
*/
bool incomplete () const
@ -759,6 +777,7 @@ private:
std::string m_name;
int m_name_hier_depth;
bool m_incomplete;
size_t m_trace_depth;
NetTracerShape m_stop_shape;
NetTracerShape m_start_shape;
db::EdgeProcessor m_ep;

View File

@ -227,6 +227,22 @@ gsi::Class<db::NetTracer> decl_NetTracer ("db", "NetTracer",
"The net name is extracted from labels found during the extraction. "
"This attribute is useful only after the extraction has been performed."
) +
gsi::method ("trace_depth=", &db::NetTracer::set_trace_depth, gsi::arg ("n"),
"@brief Sets the trace depth (shape limit)\n"
"Set this value to limit the maximum number of shapes delivered. Upon reaching this count, "
"the tracer will stop and report the net as 'incomplete' (see \\incomplete?).\n"
"Setting a trace depth if 0 is equivalent to 'unlimited'.\n"
"The actual number of shapes delivered may be a little less than the depth because of "
"internal marker shapes which are taken into account, but are not delivered.\n"
"\n"
"This method has been introduced in version 0.26.4.\n"
) +
gsi::method ("trace_depth", &db::NetTracer::trace_depth,
"@brief gets the trace depth\n"
"See \\trace_depth= for a description of this property.\n"
"\n"
"This method has been introduced in version 0.26.4.\n"
) +
gsi::method ("incomplete?", &db::NetTracer::incomplete,
"@brief Returns a value indicating whether the net is incomplete\n"
"A net may be incomplete if the extraction has been stopped by the user for example. "

View File

@ -29,7 +29,24 @@
<property name="spacing">
<number>6</number>
</property>
<item row="1" column="0" colspan="4">
<item row="3" column="0" rowspan="2" colspan="8">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0" rowspan="2">
<widget class="QPushButton" name="configure_pb">
<property name="text">
<string>Configure</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="8">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
@ -50,41 +67,175 @@ Select one or multiple nets and choose &quot;Export&quot; to export the selected
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="2" column="7">
<widget class="QFrame" name="frame">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
</font>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="text">
<string>Net Tracer</string>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="add_pb">
<property name="text">
<string>Trace Net</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="sticky_cbx">
<property name="text">
<string>Lock</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="add2_pb">
<property name="text">
<string>Trace Path</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="del_pb">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clear_all_pb">
<property name="text">
<string>Clear All</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>261</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="redo_pb">
<property name="text">
<string>Redo</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" rowspan="2" colspan="4">
<widget class="Line" name="line">
<item row="5" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="3" rowspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Trace depth:</string>
</property>
</widget>
</item>
<item row="5" column="0" rowspan="2">
<widget class="QPushButton" name="configure_pb">
<item row="5" column="7" rowspan="2">
<widget class="QPushButton" name="close_pb">
<property name="text">
<string>Configure</string>
<string>Close</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</widget>
</item>
<item row="5" column="6" rowspan="2">
<widget class="QLabel" name="tech_info_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
@ -98,7 +249,7 @@ Select one or multiple nets and choose &quot;Export&quot; to export the selected
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<item row="2" column="0" colspan="7">
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
@ -326,152 +477,47 @@ p, li { white-space: pre-wrap; }
</widget>
</widget>
</item>
<item row="2" column="3">
<widget class="QFrame" name="frame">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="add_pb">
<property name="text">
<string>Trace Net</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="sticky_cbx">
<property name="text">
<string>Lock</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="add2_pb">
<property name="text">
<string>Trace Path</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="del_pb">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clear_all_pb">
<property name="text">
<string>Clear All</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>261</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="redo_pb">
<property name="text">
<string>Redo</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="2" rowspan="2">
<widget class="QLabel" name="tech_info_label">
<item row="0" column="0" colspan="8">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
<string>Net Tracer</string>
</property>
</widget>
</item>
<item row="5" column="3" rowspan="2">
<widget class="QPushButton" name="close_pb">
<item row="5" column="5" rowspan="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Close</string>
<string>shapes</string>
</property>
</widget>
</item>
<item row="5" column="4" rowspan="2">
<widget class="QLineEdit" name="depth_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>

View File

@ -41,6 +41,7 @@ extern const std::string cfg_nt_marker_intensity ("nt-marker-intensity");
extern const std::string cfg_nt_window_mode ("nt-window-mode");
extern const std::string cfg_nt_window_dim ("nt-window-dim");
extern const std::string cfg_nt_max_shapes_highlighted ("nt-max-shapes-highlighted");
extern const std::string cfg_nt_trace_depth ("nt-trace_depth");
// ------------------------------------------------------------

View File

@ -44,6 +44,7 @@ extern const std::string cfg_nt_marker_intensity;
extern const std::string cfg_nt_window_mode;
extern const std::string cfg_nt_window_dim;
extern const std::string cfg_nt_max_shapes_highlighted;
extern const std::string cfg_nt_trace_depth;
enum nt_window_type { NTDontChange = 0, NTFitNet, NTCenter, NTCenterSize };

View File

@ -394,16 +394,13 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
}
db::NetTracer net_tracer;
net_tracer.set_trace_depth (get_trace_depth ());
// and trace
try {
if (trace_path) {
net_tracer.trace (cv->layout (), *cv.cell (), start_point, start_layer, stop_point, stop_layer, tracer_data);
} else {
net_tracer.trace (cv->layout (), *cv.cell (), start_point, start_layer, tracer_data);
}
} catch (tl::BreakException &) {
// just keep the found shapes on break (user abort)
if (trace_path) {
net_tracer.trace (cv->layout (), *cv.cell (), start_point, start_layer, stop_point, stop_layer, tracer_data);
} else {
net_tracer.trace (cv->layout (), *cv.cell (), start_point, start_layer, tracer_data);
}
if (net_tracer.begin () == net_tracer.end ()) {
@ -433,8 +430,18 @@ NetTracerDialog::configure (const std::string &name, const std::string &value)
need_update = true;
} else if (name == cfg_nt_marker_cycle_colors) {
} else if (name == cfg_nt_trace_depth) {
unsigned int n = 0;
tl::from_string (value, n);
if (n > 0) {
depth_le->setText (tl::to_qstring (tl::to_string (n)));
} else {
depth_le->setText (QString ());
}
} else if (name == cfg_nt_marker_cycle_colors) {
m_auto_colors.from_string (value, true);
} else if (name == cfg_nt_marker_cycle_colors_enabled) {
@ -1113,6 +1120,7 @@ void
NetTracerDialog::trace_path_button_clicked ()
{
BEGIN_PROTECTED
commit ();
net_list->setCurrentItem (0);
m_mouse_state = 2;
view ()->message (tl::to_string (QObject::tr ("Click on the first point in the net")));
@ -1124,6 +1132,7 @@ void
NetTracerDialog::trace_net_button_clicked ()
{
BEGIN_PROTECTED
commit ();
net_list->setCurrentItem (0);
m_mouse_state = 1;
view ()->message (tl::to_string (QObject::tr ("Click on a point in the net")));
@ -1411,9 +1420,35 @@ BEGIN_PROTECTED
END_PROTECTED
}
size_t
NetTracerDialog::get_trace_depth()
{
double n = 0.0;
try {
QString depth = depth_le->text ().trimmed ();
if (! depth.isEmpty ()) {
tl::from_string (tl::to_string (depth), n);
if (n < 0 || n > std::numeric_limits<size_t>::max ()) {
n = 0.0;
}
}
} catch (...) {
// .. nothing yet ..
}
return (size_t) n;
}
void
NetTracerDialog::commit ()
{
root ()->config_set (cfg_nt_trace_depth, tl::to_string (get_trace_depth ()));
}
void
NetTracerDialog::deactivated ()
{
commit ();
clear_markers ();
release_mouse ();
}

View File

@ -108,6 +108,8 @@ private:
lay::FileDialog *mp_export_file_dialog;
std::string m_export_file_name;
void commit ();
size_t get_trace_depth ();
void update_highlights ();
void adjust_view ();
void clear_markers ();

View File

@ -90,7 +90,7 @@ static db::NetTracerNet trace (db::NetTracer &tracer, const db::Layout &layout,
return db::NetTracerNet (tracer, db::ICplxTrans (), layout, cell.cell_index (), std::string (), std::string (), tracer_data);
}
void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracerTechnologyComponent &tc, const db::LayerProperties &lp_start, const db::Point &p_start, const std::string &file_au, const char *net_name = 0)
void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracerTechnologyComponent &tc, const db::LayerProperties &lp_start, const db::Point &p_start, const std::string &file_au, const char *net_name = 0, size_t depth = 0)
{
db::Manager m;
@ -107,12 +107,18 @@ void run_test (tl::TestBase *_this, const std::string &file, const db::NetTracer
const db::Cell &cell = layout_org.cell (*layout_org.begin_top_down ());
db::NetTracer tracer;
tracer.set_trace_depth (depth);
db::NetTracerNet net = trace (tracer, layout_org, cell, tc, layer_for (layout_org, lp_start), p_start);
if (net_name) {
EXPECT_EQ (net.name (), std::string (net_name));
}
EXPECT_EQ (net.incomplete (), depth != 0);
if (depth > 0) {
EXPECT_EQ (net.size () <= depth, true);
}
db::Layout layout_net;
net.export_net (layout_net, layout_net.cell (layout_net.add_cell ("NET")));
@ -337,7 +343,19 @@ TEST(6)
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (-2250, -900), file_au, "IN_B");
}
TEST(7)
TEST(6b)
{
std::string file = "t6.oas.gz";
std::string file_au = "t6b_net.oas.gz";
db::NetTracerTechnologyComponent tc;
tc.add (connection ("1-10", "2", "3"));
tc.add (connection ("3", "4", "5"));
run_test (_this, file, tc, db::LayerProperties (1, 0), db::Point (-2250, -900), file_au, "IN_B", 10);
}
TEST(7)
{
std::string file = "t7.oas.gz";
std::string file_au = "t7_net.oas.gz";

View File

@ -6,8 +6,8 @@ TARGET = net_tracer_tests
include($$PWD/../../../../lib_ut.pri)
SOURCES = \
dbNetTracer.cc \
dbTraceAllNets.cc
dbTraceAllNets.cc \
dbNetTracerTests.cc
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common

BIN
testdata/net_tracer/t6b_net.oas.gz vendored Normal file

Binary file not shown.