From 557a7d9d33be3992a9f9473595773a363d80229a Mon Sep 17 00:00:00 2001 From: khizmax Date: Sun, 8 Mar 2015 10:53:36 +0300 Subject: [PATCH] Added sync monitor statistics --- .gitignore | 1 + cds/container/bronson_avltree_map_rcu.h | 12 +++ cds/container/impl/bronson_avltree_map_rcu.h | 12 +++ cds/sync/injecting_monitor.h | 14 +++ cds/sync/monitor.h | 4 +- cds/sync/pool_monitor.h | 87 +++++++++++++++++-- projects/Win/vc12/cds.sln | 1 + tests/test-hdr/tree/hdr_bronson_avltree_map.h | 33 ------- ...onson_avltree_map_rcu_gpb_pool_monitor.cpp | 12 +-- ...onson_avltree_map_rcu_gpi_pool_monitor.cpp | 2 + ...onson_avltree_map_rcu_gpt_pool_monitor.cpp | 3 + ...onson_avltree_map_rcu_shb_pool_monitor.cpp | 2 + ...onson_avltree_map_rcu_sht_pool_monitor.cpp | 2 + tests/unit/map2/map_types.h | 13 ++- tests/unit/print_sync_monitor_stat.h | 34 ++++++++ 15 files changed, 184 insertions(+), 48 deletions(-) create mode 100644 tests/unit/print_sync_monitor_stat.h diff --git a/.gitignore b/.gitignore index 069a979e..a7a359fc 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ obj /projects/Win/vc14/.vs/cds/v14 /build/build-mingw-amd64.bat /build/build-mingw-amd64.log +/todo-2.1.txt diff --git a/cds/container/bronson_avltree_map_rcu.h b/cds/container/bronson_avltree_map_rcu.h index eac4bf23..c25a1620 100644 --- a/cds/container/bronson_avltree_map_rcu.h +++ b/cds/container/bronson_avltree_map_rcu.h @@ -652,6 +652,18 @@ namespace cds { namespace container { return base_class::statistics(); } + /// Returns reference to \p sync_monitor object + sync_monitor& monitor() + { + return base_class::monitor(); + } + //@cond + sync_monitor const& monitor() const + { + return base_class::monitor(); + } + //@endcond + /// Checks internal consistency (not atomic, not thread-safe) /** The debugging function to check internal consistency of the tree. diff --git a/cds/container/impl/bronson_avltree_map_rcu.h b/cds/container/impl/bronson_avltree_map_rcu.h index a24ebcb6..0387befc 100644 --- a/cds/container/impl/bronson_avltree_map_rcu.h +++ b/cds/container/impl/bronson_avltree_map_rcu.h @@ -704,6 +704,18 @@ namespace cds { namespace container { return m_stat; } + /// Returns reference to \p sync_monitor object + sync_monitor& monitor() + { + return m_Monitor; + } + //@cond + sync_monitor const& monitor() const + { + return m_Monitor; + } + //@endcond + /// Checks internal consistency (not atomic, not thread-safe) /** The debugging function to check internal consistency of the tree. diff --git a/cds/sync/injecting_monitor.h b/cds/sync/injecting_monitor.h index e1cf5637..1588b204 100644 --- a/cds/sync/injecting_monitor.h +++ b/cds/sync/injecting_monitor.h @@ -10,6 +10,13 @@ namespace cds { namespace sync { + //@cond + struct injecting_monitor_traits { + struct empty_stat + {}; + }; + //@endcond + /// @ref cds_sync_monitor "Monitor" that injects the lock into each node /** This simple monitor injects the lock object of type \p Lock into each node. @@ -43,6 +50,13 @@ namespace cds { namespace sync { p.m_SyncMonitorInjection.m_Lock.unlock(); } + //@cond + injecting_monitor_traits::empty_stat statistics() const + { + return injecting_monitor_traits::empty_stat(); + } + //@endcond + /// Scoped lock template using scoped_lock = monitor_scoped_lock< injecting_monitor, Node > ; diff --git a/cds/sync/monitor.h b/cds/sync/monitor.h index 7d421672..60d3afcd 100644 --- a/cds/sync/monitor.h +++ b/cds/sync/monitor.h @@ -29,8 +29,8 @@ namespace cds { namespace sync { - \p sync::injecting_monitor injects the lock object into each node. That mock monitor is designed for user-space locking primitive like \ref sync::spin_lock "spin-lock". - - \p sync::pool_monitor is the monitor that allocates the lock object - for the node from the pool when needed. When the node is unlocked + - \p sync::pool_monitor is the monitor that allocates a lock object + 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. diff --git a/cds/sync/pool_monitor.h b/cds/sync/pool_monitor.h index 6fe88fe9..f922954d 100644 --- a/cds/sync/pool_monitor.h +++ b/cds/sync/pool_monitor.h @@ -6,9 +6,51 @@ #include #include #include +#include // opt::none namespace cds { namespace sync { + /// \p pool_monitor traits + struct pool_monitor_traits { + + /// Dummy internal statistics if \p Stat template parameter is \p false + struct empty_stat + { + //@cond + void onLock() const {} + void onUnlock() const {} + void onLockContention() const {} + void onUnlockContention() const {} + void onLockAllocation() const {} + void onLockDeallocation() const {} + //@endcond + }; + + /// Monitor's internal statistics, used if \p Stat template parameter is \p true + template + struct stat + { + typedef Counter event_counter; ///< measure type + + event_counter m_nLockCount; ///< Number of monitor \p lock() call + event_counter m_nUnlockCount; ///< Number of monitor \p unlock call + 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 + + //@cond + void onLock() { ++m_nLockCount; } + void onUnlock() { ++m_nUnlockCount; } + void onLockContention() { ++m_nLockContention; } + void onUnlockContention() { ++m_nUnlockContention;} + void onLockAllocation() { ++m_nLockAllocation; } + void onLockDeallocation() { ++m_nLockDeallocation;} + //@endcond + }; + }; + + /// @ref cds_sync_monitor "Monitor" that allocates node's lock when needed /** The monitor is intended for reducing the number of system mutexes for @@ -24,6 +66,7 @@ namespace cds { namespace sync { - \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 Stat - enable (\p true) or disable (\p false, the default) monitor's internal statistics. How to use \code @@ -31,20 +74,32 @@ namespace cds { namespace sync { typedef cds::sync::pool_monitor< pool_type > sync_monitor; \endcode */ - template + template class pool_monitor { public: typedef LockPool pool_type; ///< Pool type typedef typename pool_type::value_type lock_type; ///< node lock type - typedef BackOff back_off; ///< back-off strategy for spinning + typedef typename std::conditional< + std::is_same< BackOff, cds::opt::none >::value, + cds::backoff::LockDefault, + BackOff + >::type back_off; ///< back-off strategy for spinning typedef uint32_t refspin_type; ///< Reference counter + spin-lock bit + /// Internal statistics + typedef typename std::conditional< + Stat, + typename pool_monitor_traits::stat<>, + typename pool_monitor_traits::empty_stat + >::type internal_stat; + private: //@cond static CDS_CONSTEXPR refspin_type const c_nSpinBit = 1; static CDS_CONSTEXPR refspin_type const c_nRefIncrement = 2; - mutable pool_type m_Pool; + mutable pool_type m_Pool; + mutable internal_stat m_Stat; //@endcond public: @@ -83,6 +138,8 @@ namespace cds { namespace sync { { lock_type * pLock; + m_Stat.onLock(); + // try lock spin and increment reference counter refspin_type cur = p.m_SyncMonitorInjection.m_RefSpin.load( atomics::memory_order_relaxed ) & ~c_nSpinBit; if ( !p.m_SyncMonitorInjection.m_RefSpin.compare_exchange_weak( cur, cur + c_nRefIncrement + c_nSpinBit, @@ -90,6 +147,7 @@ namespace cds { namespace sync { { back_off bkoff; do { + m_Stat.onLockContention(); bkoff(); cur &= ~c_nSpinBit; } while ( !p.m_SyncMonitorInjection.m_RefSpin.compare_exchange_weak( cur, cur + c_nRefIncrement + c_nSpinBit, @@ -99,8 +157,10 @@ namespace cds { namespace sync { // spin locked // If the node has no lock, allocate it from pool pLock = p.m_SyncMonitorInjection.m_pLock; - if ( !pLock ) + if ( !pLock ) { pLock = p.m_SyncMonitorInjection.m_pLock = m_Pool.allocate( 1 ); + m_Stat.onLockAllocation(); + } // unlock spin p.m_SyncMonitorInjection.m_RefSpin.store( cur + c_nRefIncrement, atomics::memory_order_release ); @@ -115,6 +175,8 @@ namespace cds { namespace sync { { lock_type * pLock = nullptr; + m_Stat.onUnlock(); + assert( p.m_SyncMonitorInjection.m_pLock != nullptr ); p.m_SyncMonitorInjection.m_pLock->unlock(); @@ -125,6 +187,7 @@ namespace cds { namespace sync { { back_off bkoff; do { + m_Stat.onUnlockContention(); bkoff(); cur &= ~c_nSpinBit; } while ( !p.m_SyncMonitorInjection.m_RefSpin.compare_exchange_weak( cur, cur + c_nSpinBit, @@ -143,13 +206,27 @@ namespace cds { namespace sync { p.m_SyncMonitorInjection.m_RefSpin.store( cur - c_nRefIncrement, atomics::memory_order_release ); // free pLock - if ( pLock ) + if ( pLock ) { m_Pool.deallocate( pLock, 1 ); + m_Stat.onLockDeallocation(); + } } /// Scoped lock template using scoped_lock = monitor_scoped_lock< pool_monitor, Node >; + + /// Returns the reference to internal statistics + /** + If class' template argument \p Stat is \p false, + the function returns \ref empty_stat "dummy statistics". + Otherwise, it returns the reference to monitor's internal statistics + of type \ref stat. + */ + internal_stat const& statistics() const + { + return m_Stat; + } }; }} // namespace cds::sync diff --git a/projects/Win/vc12/cds.sln b/projects/Win/vc12/cds.sln index 8f42ac09..f378a1b4 100644 --- a/projects/Win/vc12/cds.sln +++ b/projects/Win/vc12/cds.sln @@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit-test", "unit-test", "{ ..\..\..\tests\unit\print_segmentedqueue_stat.h = ..\..\..\tests\unit\print_segmentedqueue_stat.h ..\..\..\tests\unit\print_skip_list_stat.h = ..\..\..\tests\unit\print_skip_list_stat.h ..\..\..\tests\unit\print_split_list_stat.h = ..\..\..\tests\unit\print_split_list_stat.h + ..\..\..\tests\unit\print_sync_monitor_stat.h = ..\..\..\tests\unit\print_sync_monitor_stat.h EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit-prerequisites", "unit-prerequisites.vcxproj", "{61179F2F-07E1-490D-B64D-D85A90B6EF81}" diff --git a/tests/test-hdr/tree/hdr_bronson_avltree_map.h b/tests/test-hdr/tree/hdr_bronson_avltree_map.h index f33e56af..b6ffe24b 100644 --- a/tests/test-hdr/tree/hdr_bronson_avltree_map.h +++ b/tests/test-hdr/tree/hdr_bronson_avltree_map.h @@ -85,37 +85,6 @@ namespace tree { protected: static const size_t c_nItemCount = 10000; - /* - class data_array - { - int * pFirst; - int * pLast; - - public: - data_array() - : pFirst( new int[c_nItemCount] ) - , pLast( pFirst + c_nItemCount ) - { - int i = 0; - for ( int * p = pFirst; p != pLast; ++p, ++i ) - *p = i; - - std::random_shuffle( pFirst, pLast ); - } - - ~data_array() - { - delete[] pFirst; - } - - int operator[]( size_t i ) const - { - assert( i < size_t( pLast - pFirst ) ); - return pFirst[i]; - } - }; - */ - struct find_functor { void operator()( key_type, value_type& v ) const @@ -518,8 +487,6 @@ namespace tree { CPPUNIT_ASSERT( s.empty() ); CPPUNIT_ASSERT( check_size( s, 0 ) ); - - PrintStat()(s); } diff --git a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpb_pool_monitor.cpp b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpb_pool_monitor.cpp index 57e0029a..d4a806a8 100644 --- a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpb_pool_monitor.cpp +++ b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpb_pool_monitor.cpp @@ -7,6 +7,7 @@ #include #include "unit/print_bronsonavltree_stat.h" +#include "unit/print_sync_monitor_stat.h" namespace tree { namespace cc = cds::container; @@ -16,9 +17,10 @@ namespace tree { struct print_stat { template - void operator()( Tree const& t ) + void operator()( Tree const& t ) const { std::cout << t.statistics(); + std::cout << t.monitor().statistics(); } }; @@ -45,7 +47,7 @@ namespace tree { cc::bronson_avltree::make_traits< co::less< std::less > ,co::stat< cc::bronson_avltree::stat<> > - ,co::sync_monitor< cds::sync::pool_monitor > + ,co::sync_monitor< cds::sync::pool_monitor> ,cc::bronson_avltree::relaxed_insert< false > >::type {}; @@ -60,7 +62,7 @@ namespace tree { co::compare< compare > ,co::item_counter< cds::atomicity::item_counter > ,co::stat< cc::bronson_avltree::stat<> > - ,co::sync_monitor< cds::sync::pool_monitor > + ,co::sync_monitor< cds::sync::pool_monitor> >::type {}; typedef cc::BronsonAVLTreeMap< rcu_type, key_type, value_type, traits > map_type; @@ -75,7 +77,7 @@ namespace tree { ,co::item_counter< cds::atomicity::item_counter > ,co::stat< cc::bronson_avltree::stat<> > ,co::back_off< cds::backoff::yield > - ,co::sync_monitor< cds::sync::pool_monitor > + ,co::sync_monitor< cds::sync::pool_monitor> >::type {}; typedef cc::BronsonAVLTreeMap< rcu_type, key_type, value_type, traits > map_type; @@ -102,7 +104,7 @@ namespace tree { co::less< std::less > ,co::stat< cc::bronson_avltree::stat<> > ,cc::bronson_avltree::relaxed_insert< true > - ,co::sync_monitor< cds::sync::pool_monitor > + ,co::sync_monitor< cds::sync::pool_monitor> >::type {}; typedef cc::BronsonAVLTreeMap< rcu_type, key_type, value_type, traits > map_type; diff --git a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpi_pool_monitor.cpp b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpi_pool_monitor.cpp index fb505c23..73bfa58b 100644 --- a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpi_pool_monitor.cpp +++ b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpi_pool_monitor.cpp @@ -7,6 +7,7 @@ #include #include "unit/print_bronsonavltree_stat.h" +#include "unit/print_sync_monitor_stat.h" namespace tree { namespace cc = cds::container; @@ -19,6 +20,7 @@ namespace tree { void operator()( Tree const& t ) { std::cout << t.statistics(); + std::cout << t.monitor().statistics(); } }; diff --git a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpt_pool_monitor.cpp b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpt_pool_monitor.cpp index 9701349f..839a1c68 100644 --- a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpt_pool_monitor.cpp +++ b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpt_pool_monitor.cpp @@ -7,6 +7,8 @@ #include #include "unit/print_bronsonavltree_stat.h" +#include "unit/print_sync_monitor_stat.h" + namespace tree { namespace cc = cds::container; @@ -19,6 +21,7 @@ namespace tree { void operator()( Tree const& t ) { std::cout << t.statistics(); + std::cout << t.monitor().statistics(); } }; diff --git a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_shb_pool_monitor.cpp b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_shb_pool_monitor.cpp index 3e5d6d69..ac9b4b7b 100644 --- a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_shb_pool_monitor.cpp +++ b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_shb_pool_monitor.cpp @@ -7,6 +7,7 @@ #include #include "unit/print_bronsonavltree_stat.h" +#include "unit/print_sync_monitor_stat.h" namespace tree { #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED @@ -20,6 +21,7 @@ namespace tree { void operator()( Tree const& t ) { std::cout << t.statistics(); + std::cout << t.monitor().statistics(); } }; diff --git a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_sht_pool_monitor.cpp b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_sht_pool_monitor.cpp index d21d0ce0..6a3570e7 100644 --- a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_sht_pool_monitor.cpp +++ b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_sht_pool_monitor.cpp @@ -7,6 +7,7 @@ #include #include "unit/print_bronsonavltree_stat.h" +#include "unit/print_sync_monitor_stat.h" namespace tree { #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED @@ -20,6 +21,7 @@ namespace tree { void operator()( Tree const& t ) { std::cout << t.statistics(); + std::cout << t.monitor().statistics(); } }; diff --git a/tests/unit/map2/map_types.h b/tests/unit/map2/map_types.h index d246c42a..4417b028 100644 --- a/tests/unit/map2/map_types.h +++ b/tests/unit/map2/map_types.h @@ -66,6 +66,7 @@ #include "print_skip_list_stat.h" #include "print_ellenbintree_stat.h" #include "print_bronsonavltree_stat.h" +#include "print_sync_monitor_stat.h" #include "ellen_bintree_update_desc_pool.h" namespace map2 { @@ -1765,9 +1766,10 @@ namespace map2 { typedef cc::BronsonAVLTreeMap< rcu_shb, Key, Value, BronsonAVLTreeMap_less_pool_simple > BronsonAVLTreeMap_rcu_shb_less_pool_simple; typedef cc::BronsonAVLTreeMap< rcu_sht, Key, Value, BronsonAVLTreeMap_less_pool_simple > BronsonAVLTreeMap_rcu_sht_less_pool_simple; #endif - struct BronsonAVLTreeMap_less_pool_simple_stat : public BronsonAVLTreeMap_less_pool_simple + struct BronsonAVLTreeMap_less_pool_simple_stat : public BronsonAVLTreeMap_less { typedef cc::bronson_avltree::stat<> stat; + typedef cds::sync::pool_monitor sync_monitor; }; typedef cc::BronsonAVLTreeMap< rcu_gpi, Key, Value, BronsonAVLTreeMap_less_pool_simple_stat > BronsonAVLTreeMap_rcu_gpi_less_pool_simple_stat; typedef cc::BronsonAVLTreeMap< rcu_gpb, Key, Value, BronsonAVLTreeMap_less_pool_simple_stat > BronsonAVLTreeMap_rcu_gpb_less_pool_simple_stat; @@ -1788,9 +1790,11 @@ namespace map2 { typedef cc::BronsonAVLTreeMap< rcu_shb, Key, Value, BronsonAVLTreeMap_less_pool_lazy > BronsonAVLTreeMap_rcu_shb_less_pool_lazy; typedef cc::BronsonAVLTreeMap< rcu_sht, Key, Value, BronsonAVLTreeMap_less_pool_lazy > BronsonAVLTreeMap_rcu_sht_less_pool_lazy; #endif - struct BronsonAVLTreeMap_less_pool_lazy_stat : public BronsonAVLTreeMap_less_pool_lazy + struct BronsonAVLTreeMap_less_pool_lazy_stat : public BronsonAVLTreeMap_less { typedef cc::bronson_avltree::stat<> stat; + typedef cds::sync::pool_monitor sync_monitor; + static CDS_CONSTEXPR bool const relaxed_insert = true; }; typedef cc::BronsonAVLTreeMap< rcu_gpi, Key, Value, BronsonAVLTreeMap_less_pool_lazy_stat > BronsonAVLTreeMap_rcu_gpi_less_pool_lazy_stat; typedef cc::BronsonAVLTreeMap< rcu_gpb, Key, Value, BronsonAVLTreeMap_less_pool_lazy_stat > BronsonAVLTreeMap_rcu_gpb_less_pool_lazy_stat; @@ -1811,9 +1815,11 @@ namespace map2 { typedef cc::BronsonAVLTreeMap< rcu_shb, Key, Value, BronsonAVLTreeMap_less_pool_bounded > BronsonAVLTreeMap_rcu_shb_less_pool_bounded; typedef cc::BronsonAVLTreeMap< rcu_sht, Key, Value, BronsonAVLTreeMap_less_pool_bounded > BronsonAVLTreeMap_rcu_sht_less_pool_bounded; #endif - struct BronsonAVLTreeMap_less_pool_bounded_stat : public BronsonAVLTreeMap_less_pool_bounded + struct BronsonAVLTreeMap_less_pool_bounded_stat : public BronsonAVLTreeMap_less { typedef cc::bronson_avltree::stat<> stat; + typedef cds::sync::pool_monitor sync_monitor; + static CDS_CONSTEXPR bool const relaxed_insert = true; }; typedef cc::BronsonAVLTreeMap< rcu_gpi, Key, Value, BronsonAVLTreeMap_less_pool_bounded_stat > BronsonAVLTreeMap_rcu_gpi_less_pool_bounded_stat; typedef cc::BronsonAVLTreeMap< rcu_gpb, Key, Value, BronsonAVLTreeMap_less_pool_bounded_stat > BronsonAVLTreeMap_rcu_gpb_less_pool_bounded_stat; @@ -1925,6 +1931,7 @@ namespace map2 { static inline void print_stat( cc::BronsonAVLTreeMap const& m ) { CPPUNIT_MSG( m.statistics() ); + CPPUNIT_MSG( m.monitor().statistics() ); } template diff --git a/tests/unit/print_sync_monitor_stat.h b/tests/unit/print_sync_monitor_stat.h new file mode 100644 index 00000000..721ddcda --- /dev/null +++ b/tests/unit/print_sync_monitor_stat.h @@ -0,0 +1,34 @@ +//$$CDS-header$$ + +#if defined(CDSLIB_SYNC_INJECTING_MONITOR_H) && !defined(CDSUNIT_PRINT_INJECTING_MONITOR_STAT_H) +#define CDSUNIT_PRINT_INJECTING_MONITOR_STAT_H + +namespace std { + static inline ostream& operator <<( ostream& o, cds::sync::injecting_monitor_traits::empty_stat const& /*s*/ ) + { + return o; + } +} +#endif + +#if defined(CDSLIB_SYNC_POOL_MONITOR_H) && !defined(CDSUNIT_PRINT_POOL_MONITOR_STAT_H) +#define CDSUNIT_PRINT_POOL_MONITOR_STAT_H + +namespace std { + static inline ostream& operator <<( ostream& o, cds::sync::pool_monitor_traits::empty_stat const& /*s*/ ) + { + return o; + } + + static inline ostream& operator <<( ostream& o, cds::sync::pool_monitor_traits::stat<> const& s ) + { + 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_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"; + } +} +#endif -- 2.34.1