Added more measures to sync monitor statistics
authorkhizmax <libcds.dev@gmail.com>
Sun, 8 Mar 2015 15:41:41 +0000 (18:41 +0300)
committerkhizmax <libcds.dev@gmail.com>
Sun, 8 Mar 2015 15:41:41 +0000 (18:41 +0300)
cds/sync/monitor.h
cds/sync/pool_monitor.h
tests/unit/map2/map_defs.h
tests/unit/print_sync_monitor_stat.h

index 60d3afcd6eaabb3af3109ef1790fd5196f1517e0..09eb1970a185dac768d29882916f4e216749df41 100644 (file)
@@ -1,18 +1,12 @@
 //$$CDS-header$$
-
 #ifndef CDSLIB_SYNC_MONITOR_H
 #define CDSLIB_SYNC_MONITOR_H
-
 #include <cds/details/defs.h>
-
 namespace cds { namespace sync {
-
     /**
         @page cds_sync_monitor Synchronization monitor
-
         A <a href="http://en.wikipedia.org/wiki/Monitor_%28synchronization%29">monitor</a> is synchronization construct
         that allows threads to have both mutual exclusion and the ability to wait (block) for a certain condition to become true.
-
         Some blocking data structure algoritms like the trees require per-node locking.
         For huge trees containing millions of nodes it can be very inefficient to inject
         the lock object into each node. Moreover, some operating systems may not support
@@ -22,9 +16,7 @@ namespace cds { namespace sync {
         lock object for the node if needed, and to lock the node.
         The monitor strategy can significantly reduce the number of system objects
         required for data structure.
-
         <b>Implemetations</b>
-
         \p libcds contains several monitor implementations:
         - \p sync::injecting_monitor injects the lock object into each node.
             That mock monitor is designed for user-space locking primitive like
@@ -33,15 +25,12 @@ namespace cds { namespace sync {
             for a node from the pool when needed. When the node is unlocked
             the lock assigned to it is given back to the pool if no thread
             references to that node.
-
         <b>How to use</b>
-
         If you use a container from \p libcds that requires a monitor, you should just
-        specify required monitor type in container's traits. Usually, the monitor 
+        specify required monitor type in container's traits. Usually, the monitor
         is specified by \p traits::sync_monitor typedef, or by \p cds::opt::sync_monitor
         option for container's \p make_traits metafunction.
-
-        If you're developing a new container algorithm, you should know internal monitor 
+        If you're developing a new container algorithm, you should know internal monitor
         interface:
         \code
         class Monitor {
@@ -51,23 +40,19 @@ namespace cds { namespace sync {
             struct node_injection: public Node
             {
                 // Monitor data to inject into container's node
-                // ... 
+                // ...
             };
-
-            // Locks the node 
+            // Locks the node
             template <typename Node>
             void lock( Node& node );
-
             // Unlocks the node
             template <typename Node>
             void unlock( Node& node );
-
             // Scoped lock applyes RAII to Monitor
             template <typename Node>
             using scoped_lock = monitor_scoped_lock< pool_monitor, Node >;
         };
         \endcode
-
         Monitor's data must be inject into container's node as \p m_SyncMonitorInjection data member:
         \code
         template <typename SyncMonitor>
@@ -77,7 +62,6 @@ namespace cds { namespace sync {
             typename SyncMonitor::node_injection m_SyncMonitorInjection;
         };
         \endcode
-
         The monitor must be a member of your container:
         \code
         template <typename GC, typename T, typename Traits>
@@ -90,7 +74,6 @@ namespace cds { namespace sync {
         };
         \endcode
     */
-
     /// Monitor scoped lock (RAII)
     /**
         Template arguments:
@@ -103,13 +86,11 @@ namespace cds { namespace sync {
     public:
         typedef Monitor monitor_type;   ///< Monitor type
         typedef Node    node_type;      ///< Node type
-
     private:
         //@cond
         monitor_type&    m_Monitor; ///< Monitor
         node_type const& m_Node;    ///< Our locked node
         //@endcond
-
     public:
         /// Makes exclusive access to the node \p p by \p monitor
         monitor_scoped_lock( monitor_type& monitor, node_type const& p )
@@ -118,15 +99,12 @@ namespace cds { namespace sync {
         {
             monitor.lock( p );
         }
-
         /// Unlocks the node
         ~monitor_scoped_lock()
         {
             m_Monitor.unlock( m_Node );
         }
     };
-
 }} // namespace cds::sync
-
 #endif // #ifndef CDSLIB_SYNC_MONITOR_H
 
index 404c35d270d16a6b9a911c3d1e24bd777f820f0a..8045a59b4e789f73e7081e65d17281b77558895b 100644 (file)
@@ -34,17 +34,31 @@ namespace cds { namespace sync {
 
             event_counter m_nLockCount;         ///< Number of monitor \p lock() call
             event_counter m_nUnlockCount;       ///< Number of monitor \p unlock call
+            event_counter m_nMaxLocked;         ///< Max number of simuntaneously locked mutexes
             event_counter m_nLockContention;    ///< Number of \p lock() contenton
             event_counter m_nUnlockContention;  ///< Number of \p unlock() contention
             event_counter m_nLockAllocation;    ///< Number of the lock allocation from the pool
             event_counter m_nLockDeallocation;  ///< Number of the lock deallocation
+            event_counter m_nMaxAllocated;      ///< Max number of sumultanouusly allocated mutexes
 
             //@cond
-            void onLock()               { ++m_nLockCount;       }
+            void onLock()
+            { 
+                ++m_nLockCount;
+                int nDiff = static_cast<int>( m_nLockCount.get() - m_nUnlockCount.get());
+                if ( nDiff > 0 && m_nMaxLocked.get() < static_cast<typename event_counter::value_type>( nDiff ))
+                    m_nMaxLocked = static_cast<typename event_counter::value_type>( nDiff );
+            }
             void onUnlock()             { ++m_nUnlockCount;     }
             void onLockContention()     { ++m_nLockContention;  }
             void onUnlockContention()   { ++m_nUnlockContention;}
-            void onLockAllocation()     { ++m_nLockAllocation;  }
+            void onLockAllocation()
+            { 
+                ++m_nLockAllocation;  
+                int nDiff = static_cast<int>( m_nLockAllocation.get() - m_nLockDeallocation.get());
+                if ( nDiff > 0 && m_nMaxAllocated.get() < static_cast<typename event_counter::value_type>( nDiff ) )
+                    m_nMaxAllocated = static_cast<typename event_counter::value_type>( nDiff );
+            }
             void onLockDeallocation()   { ++m_nLockDeallocation;}
             //@endcond
         };
@@ -65,7 +79,7 @@ namespace cds { namespace sync {
         Template arguments:
         - \p LockPool - the @ref cds_memory_pool "pool type". The pool must maintain
             the objects of type \p std::mutex or similar. The access to the pool is not synchronized.
-        - \p BackOff - back-off strategy for spinning, default is \p cds::backoff::LockDefault
+        - \p BackOff - back-off strategy for spinning, default is \p cds::backoff::yield
         - \p Stat - enable (\p true) or disable (\p false, the default) monitor's internal statistics.
 
         <b>How to use</b>
@@ -74,7 +88,7 @@ namespace cds { namespace sync {
         typedef cds::sync::pool_monitor< pool_type > sync_monitor;
         \endcode
     */
-    template <class LockPool, typename BackOff = cds::backoff::LockDefault, bool Stat = false >
+    template <class LockPool, typename BackOff = cds::backoff::yield, bool Stat = false >
     class pool_monitor
     {
     public:
@@ -82,7 +96,7 @@ namespace cds { namespace sync {
         typedef typename pool_type::value_type lock_type; ///< node lock type
         typedef typename std::conditional< 
             std::is_same< BackOff, cds::opt::none >::value, 
-            cds::backoff::LockDefault,
+            cds::backoff::yield,
             BackOff
         >::type  back_off;  ///< back-off strategy for spinning
         typedef uint32_t refspin_type;  ///< Reference counter + spin-lock bit
index 99e3003af70aef5d7411e8f21d0d8b914b8b5f6a..089a64d45d763b1792b5b149633e8dfc814b911c 100644 (file)
@@ -458,16 +458,16 @@ TEST_MAP_EXTRACT(SplitList_Lazy_RCU_SHT_st_less_stat)
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_shb_cmp_stat) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_cmp_stat) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_shb_less_pool_simple) \
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_simple) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_shb_less_pool_simple_stat) \
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_simple) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_simple_stat) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_shb_less_pool_lazy) \
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_lazy) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_shb_less_pool_lazy_stat) \
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_lazy) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_lazy_stat) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_shb_less_pool_bounded) \
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_bounded) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_shb_less_pool_bounded_stat) \
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_bounded) \
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_sht_less_pool_bounded_stat) \
 
 #else
@@ -507,25 +507,23 @@ TEST_MAP_EXTRACT(SplitList_Lazy_RCU_SHT_st_less_stat)
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpi_cmp_stat)\
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_cmp_stat)\
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_cmp_stat)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpi_less_pool_simple)\
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_cmp_stat)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less_pool_simple)\
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_cmp_stat)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less_pool_simple)\
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpi_less_pool_simple_stat)\
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less_pool_simple_stat)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less_pool_simple_stat)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpi_less_pool_lazy)\
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less_pool_lazy)\
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less_pool_lazy)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpi_less_pool_lazy_stat)\
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less_pool_lazy)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less_pool_lazy_stat)\
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less_pool_lazy)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less_pool_lazy_stat)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpi_less_pool_bounded)\
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less_pool_bounded)\
-    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less_pool_bounded)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpi_less_pool_bounded_stat)\
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less_pool_bounded)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpb_less_pool_bounded_stat)\
+    CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less_pool_bounded)\
     CPPUNIT_TEST(BronsonAVLTreeMap_rcu_gpt_less_pool_bounded_stat)\
     CDSUNIT_TEST_BronsonAVLTreeMap_RCU_signal
 
index 721ddcda6e26c624d7bf6acd3a7852a5d0ea682d..aa56cecfc526131d75ebf73495fa2feac310514c 100644 (file)
@@ -25,10 +25,12 @@ namespace std {
         return o << "cds::sync::pool_monitor statistics:\n"
             << "\t\t        m_nLockCount: " << s.m_nLockCount.get()        << "\n"
             << "\t\t      m_nUnlockCount: " << s.m_nUnlockCount.get()      << "\n"
+            << "\t\t        m_nMaxLocked: " << s.m_nMaxLocked.get()        << "\n"
             << "\t\t   m_nLockContention: " << s.m_nLockContention.get()   << "\n"
             << "\t\t m_nUnlockContention: " << s.m_nUnlockContention.get() << "\n"
             << "\t\t   m_nLockAllocation: " << s.m_nLockAllocation.get()   << "\n"
-            << "\t\t m_nLockDeallocation: " << s.m_nLockDeallocation.get() << "\n";
+            << "\t\t m_nLockDeallocation: " << s.m_nLockDeallocation.get() << "\n"
+            << "\t\t     m_nMaxAllocated: " << s.m_nMaxAllocated.get()     << "\n";
     }
 }
 #endif