From 54adb84e275b8005b92d31268f55dd35f4534b10 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 29 Dec 2018 01:04:48 +0100 Subject: [PATCH] WIP: locking of netlist for better performance. --- src/db/db/dbNetlist.cc | 34 ++++++++++++++++---- src/db/db/dbNetlist.h | 50 +++++++++++++++++++++++++++++ src/db/unit_tests/dbNetlistTests.cc | 10 ++++++ 3 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 0e954a4e4..0b6631132 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -1129,13 +1129,13 @@ size_t DeviceClass::terminal_id_for_name (const std::string &name) const // Netlist class implementation Netlist::Netlist () - : m_valid_topology (false) + : m_valid_topology (false), m_lock_count (0) { m_circuits.changed ().add (this, &Netlist::invalidate_topology); } Netlist::Netlist (const Netlist &other) - : m_valid_topology (false) + : m_valid_topology (false), m_lock_count (0) { operator= (other); m_circuits.changed ().add (this, &Netlist::invalidate_topology); @@ -1173,11 +1173,16 @@ Netlist &Netlist::operator= (const Netlist &other) void Netlist::invalidate_topology () { if (m_valid_topology) { + m_valid_topology = false; - m_top_circuits = 0; - m_top_down_circuits.clear (); - m_child_circuits.clear (); - m_parent_circuits.clear (); + + if (m_lock_count == 0) { + m_top_circuits = 0; + m_top_down_circuits.clear (); + m_child_circuits.clear (); + m_parent_circuits.clear (); + } + } } @@ -1195,6 +1200,8 @@ void Netlist::validate_topology () { if (m_valid_topology) { return; + } else if (m_lock_count > 0) { + return; } m_child_circuits.clear (); @@ -1295,6 +1302,21 @@ void Netlist::validate_topology () m_valid_topology = true; } +void Netlist::lock () +{ + if (m_lock_count == 0) { + validate_topology (); + } + ++m_lock_count; +} + +void Netlist::unlock () +{ + if (m_lock_count > 0) { + --m_lock_count; + } +} + const tl::vector &Netlist::child_circuits (Circuit *circuit) { if (! m_valid_topology) { diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index cbdedddf8..cf1016e97 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -1806,6 +1806,30 @@ public: */ void clear (); + /** + * @brief Starts a sequence of operations during which topology updates are not desired + * + * If the hierarchy is modified, the topology information (top-down order, children + * and parent information) may be recomputed frequently. This may cause performance issues + * and may not be desired. + * + * Calling this method will bring the netlist into a state in which updates on the + * list will not happen. Using "unlock" will end this state. + * + * "lock" and "unlock" are incremental and can be nested. Use "NetlistLocker" for safe locking + * and unlocking. + * + * Before lock, the state will be validated, so inside the locked operation, the topology + * information will be valid with respect to the initial state. + */ + void lock (); + + /** + * @brief Ends a sequence of operations during which topology updates are not desired + * See "lock" for more details. + */ + void unlock (); + /** * @brief Adds a circuit to this netlist * @@ -1974,6 +1998,7 @@ private: circuit_list m_circuits; device_class_list m_device_classes; bool m_valid_topology; + int m_lock_count; tl::vector m_top_down_circuits; tl::vector > m_child_circuits; tl::vector > m_parent_circuits; @@ -1986,6 +2011,31 @@ private: const tl::vector &parent_circuits (Circuit *circuit); }; +/** + * @brief A helper class using RAII for safe locking/unlocking + */ +class DB_PUBLIC NetlistLocker +{ +public: + NetlistLocker (Netlist *netlist) + : mp_netlist (netlist) + { + if (mp_netlist.get ()) { + mp_netlist->lock (); + } + } + + ~NetlistLocker () + { + if (mp_netlist.get ()) { + mp_netlist->unlock (); + } + } + +private: + tl::weak_ptr mp_netlist; +}; + } #endif diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index 3edfe1503..a25147743 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -902,9 +902,19 @@ TEST(12_NetlistTopology) EXPECT_EQ (td2string (nl.get ()), "c1,c2"); EXPECT_EQ (bu2string (nl.get ()), "c2,c1"); + std::auto_ptr locker (new db::NetlistLocker (nl.get ())); + db::Circuit *c3 = new db::Circuit (); c3->set_name ("c3"); nl->add_circuit (c3); + + // because we locked, it did not get updated: + EXPECT_EQ (nl->top_circuit_count (), size_t (2)); + EXPECT_EQ (td2string (nl.get ()), "c1,c2"); + EXPECT_EQ (bu2string (nl.get ()), "c2,c1"); + locker.reset (0); + + // after removing the lock, it's updated EXPECT_EQ (nl->top_circuit_count (), size_t (3)); EXPECT_EQ (td2string (nl.get ()), "c1,c2,c3"); EXPECT_EQ (bu2string (nl.get ()), "c3,c2,c1");