From aef69c9f25b98ef705b6ea814b85a6764bbf1a8f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 6 May 2023 10:15:26 -0700 Subject: [PATCH] redo INST_COUNTER Allow for use by pvxsIoc --- src/client.cpp | 5 +++++ src/clientget.cpp | 1 + src/clientintrospect.cpp | 1 + src/clientmon.cpp | 1 + src/data.cpp | 2 ++ src/evhelper.cpp | 12 +++++++++++- src/instcounters.h | 38 ------------------------------------ src/serverconn.cpp | 9 +++++++++ src/serverget.cpp | 3 +++ src/serverintrospect.cpp | 2 ++ src/servermon.cpp | 3 +++ src/sharedpv.cpp | 1 + src/udp_collector.cpp | 2 ++ src/util.cpp | 42 ++++++++++++++++++++++++++++++++++------ src/utilpvt.h | 29 +++++++++++++++++---------- 15 files changed, 96 insertions(+), 55 deletions(-) delete mode 100644 src/instcounters.h diff --git a/src/client.cpp b/src/client.cpp index 677953f..7f6d050 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -27,6 +27,11 @@ typedef epicsGuardRelease UnGuard; namespace pvxs { namespace client { +DEFINE_INST_COUNTER(Connection); +DEFINE_INST_COUNTER(Channel); +DEFINE_INST_COUNTER2(ContextImpl, ClientContextImpl); +DEFINE_INST_COUNTER2(Context::Pvt, ClientPvt); + namespace { /* "normal" tick interval for the search bucket ring, and "fast" interval * used for one revolution after a successful poke(). diff --git a/src/clientget.cpp b/src/clientget.cpp index 85e1d3e..6f742b2 100644 --- a/src/clientget.cpp +++ b/src/clientget.cpp @@ -383,6 +383,7 @@ struct GPROp : public OperationBase } } }; +DEFINE_INST_COUNTER(GPROp); } // namespace diff --git a/src/clientintrospect.cpp b/src/clientintrospect.cpp index bab7e27..f6927a7 100644 --- a/src/clientintrospect.cpp +++ b/src/clientintrospect.cpp @@ -108,6 +108,7 @@ struct InfoOp : public OperationBase } } }; +DEFINE_INST_COUNTER(InfoOp); } // namespace diff --git a/src/clientmon.cpp b/src/clientmon.cpp index 3bff444..2759cc3 100644 --- a/src/clientmon.cpp +++ b/src/clientmon.cpp @@ -463,6 +463,7 @@ struct SubscriptionImpl final : public OperationBase, public Subscription } } }; +DEFINE_INST_COUNTER(SubscriptionImpl); void Connection::handle_MONITOR() { diff --git a/src/data.cpp b/src/data.cpp index 019e8d5..d9b49ca 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -12,6 +12,8 @@ namespace pvxs { +DEFINE_INST_COUNTER(StructTop); + NoField::NoField() :std::runtime_error ("No such field") {} diff --git a/src/evhelper.cpp b/src/evhelper.cpp index b47843f..cf1f6f8 100644 --- a/src/evhelper.cpp +++ b/src/evhelper.cpp @@ -107,6 +107,13 @@ struct ThreadEvent inline epicsEvent* operator->() { return get(); } }; +namespace { +struct evbaseRunning { + INST_COUNTER(evbaseRunning); +}; +DEFINE_INST_COUNTER(evbaseRunning); +} + struct evbase::Pvt final : public epicsThreadRunable { SockAttach attach; @@ -165,7 +172,7 @@ struct evbase::Pvt final : public epicsThreadRunable virtual void run() override final { - INST_COUNTER(evbaseRunning); + evbaseRunning track; try { evconfig conf(__FILE__, __LINE__, event_config_new()); #ifdef __rtems__ @@ -253,6 +260,7 @@ struct evbase::Pvt final : public epicsThreadRunable } }; +DEFINE_INST_COUNTER2(evbase::Pvt, evbase); evbase::evbase(const std::string &name, unsigned prio) { @@ -1024,6 +1032,8 @@ void to_evbuf(evbuffer *buf, const Header& H, bool be) } // namespace impl +std::atomic Timer::Pvt::cnt_Timer {0u}; + Timer::~Timer() {} bool Timer::cancel() diff --git a/src/instcounters.h b/src/instcounters.h deleted file mode 100644 index 80956de..0000000 --- a/src/instcounters.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Names of internal object instance counters. - * Included in three places in utilpvt.h and util.cpp - */ -#ifndef CASE -// for IDEs -# define CASE(NAME) -# error Must define CASE -#endif -CASE(StructTop); - -CASE(UDPListener); -CASE(evbase); -CASE(evbaseRunning); -CASE(Timer); - -CASE(GPROp); -CASE(Connection); -CASE(Channel); -CASE(ClientPvt); -CASE(ClientContextImpl); -CASE(InfoOp); -CASE(SubScriptionImpl); - -CASE(ServerChannelControl); -CASE(ServerChan); -CASE(ServerConn); -CASE(ServerSource); -CASE(ServerPvt); -CASE(ServerIntrospect); -CASE(ServerIntrospectControl); -CASE(ServerGPR); -CASE(ServerGPRConnect); -CASE(ServerGPRExec); -CASE(MonitorOp); -CASE(ServerMonitorControl); -CASE(ServerMonitorSetup); -CASE(SharedPVImpl); -CASE(SubscriptionImpl); diff --git a/src/serverconn.cpp b/src/serverconn.cpp index f0ce884..fee0bfe 100644 --- a/src/serverconn.cpp +++ b/src/serverconn.cpp @@ -20,7 +20,16 @@ static constexpr size_t tcp_tx_limit_mult = 2u; namespace pvxs { +namespace impl { +DEFINE_INST_COUNTER(ServerChannelControl); +DEFINE_INST_COUNTER(ServerChan); +DEFINE_INST_COUNTER(ServerConn); +DEFINE_INST_COUNTER(ServerSource); +} namespace server { + +DEFINE_INST_COUNTER2(Server::Pvt, ServerPvt); + std::set ClientCredentials::roles() const { std::set ret; diff --git a/src/serverget.cpp b/src/serverget.cpp index ab63bdf..336e194 100644 --- a/src/serverget.cpp +++ b/src/serverget.cpp @@ -152,6 +152,7 @@ struct ServerGPR : public ServerOp INST_COUNTER(ServerGPR); }; +DEFINE_INST_COUNTER(ServerGPR); struct ServerGPRConnect : public server::ConnectOp @@ -246,6 +247,7 @@ struct ServerGPRConnect : public server::ConnectOp INST_COUNTER(ServerGPRConnect); }; +DEFINE_INST_COUNTER(ServerGPRConnect); struct ServerGPRExec : public server::ExecOp { @@ -317,6 +319,7 @@ struct ServerGPRExec : public server::ExecOp INST_COUNTER(ServerGPRExec); }; +DEFINE_INST_COUNTER(ServerGPRExec); } // namespace diff --git a/src/serverintrospect.cpp b/src/serverintrospect.cpp index f599468..6379552 100644 --- a/src/serverintrospect.cpp +++ b/src/serverintrospect.cpp @@ -56,6 +56,7 @@ struct ServerIntrospect : public ServerOp INST_COUNTER(ServerIntrospect); }; +DEFINE_INST_COUNTER(ServerIntrospect); struct ServerIntrospectControl : public server::ConnectOp { @@ -117,6 +118,7 @@ struct ServerIntrospectControl : public server::ConnectOp INST_COUNTER(ServerIntrospectControl); }; +DEFINE_INST_COUNTER(ServerIntrospectControl); } // namespace void ServerConn::handle_GET_FIELD() diff --git a/src/servermon.cpp b/src/servermon.cpp index 59a3ee1..da83007 100644 --- a/src/servermon.cpp +++ b/src/servermon.cpp @@ -200,6 +200,7 @@ struct MonitorOp : public ServerOp, strm<<"MONITOR\n"; } }; +DEFINE_INST_COUNTER(MonitorOp); struct ServerMonitorSetup; @@ -326,6 +327,7 @@ struct ServerMonitorControl : public server::MonitorControlOp INST_COUNTER(ServerMonitorControl); }; +DEFINE_INST_COUNTER(ServerMonitorControl); struct ServerMonitorSetup : public server::MonitorSetupOp { @@ -401,6 +403,7 @@ struct ServerMonitorSetup : public server::MonitorSetupOp INST_COUNTER(ServerMonitorSetup); }; +DEFINE_INST_COUNTER(ServerMonitorSetup); ServerMonitorControl::ServerMonitorControl(ServerMonitorSetup* setup, diff --git a/src/sharedpv.cpp b/src/sharedpv.cpp index e55179d..b49dd34 100644 --- a/src/sharedpv.cpp +++ b/src/sharedpv.cpp @@ -101,6 +101,7 @@ struct SharedPV::Impl : public std::enable_shared_from_this } } }; +DEFINE_INST_COUNTER2(SharedPV::Impl, SharedPVImpl); SharedPV SharedPV::buildMailbox() { diff --git a/src/udp_collector.cpp b/src/udp_collector.cpp index f0fb331..f27a9ff 100644 --- a/src/udp_collector.cpp +++ b/src/udp_collector.cpp @@ -31,6 +31,8 @@ namespace pvxs {namespace impl { DEFINE_LOGGER(logio, "pvxs.udp.io"); DEFINE_LOGGER(logsetup, "pvxs.udp.setup"); +DEFINE_INST_COUNTER(UDPListener); + struct UDPCollector final : public UDPManager::Search, public std::enable_shared_from_this { diff --git a/src/util.cpp b/src/util.cpp index f6cc330..b39a2a3 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -78,18 +78,48 @@ unsigned long version_abi_int() return PVXS_ABI_VERSION; } +namespace { +epicsThreadOnceId ICountOnce = EPICS_THREAD_ONCE_INIT; +struct ICountGbl_t { + RWLock lock; + std::map*> counters; +} *ICountGbl; -#define CASE(KLASS) std::atomic cnt_ ## KLASS{} -#include "instcounters.h" -#undef CASE +void ICountInit(void*) +{ + ICountGbl = new ICountGbl_t; +} + +} // namespace + +void registerICount(const char *name, std::atomic& Cnt) +{ + epicsThreadOnce(&ICountOnce, &ICountInit, nullptr); + auto& gbl = *ICountGbl; + try { + auto L(gbl.lock.lockWriter()); + if(!gbl.counters.emplace(name, &Cnt).second) { // duplicate name + return; + } + } catch(std::exception& e) { // bad_alloc + return; + } + Cnt++; // bias by +1 to indicate initialization +} std::map instanceSnapshot() { std::map ret; -#define CASE(KLASS) ret[#KLASS] = cnt_ ## KLASS .load(std::memory_order_relaxed) -#include "instcounters.h" -#undef CASE + { + epicsThreadOnce(&ICountOnce, &ICountInit, nullptr); + auto& gbl = *ICountGbl; + auto L(gbl.lock.lockReader()); + for(auto& pair : gbl.counters) { + // remove -1 bias for initialized counter + ret.emplace(pair.first, pair.second->load(std::memory_order_relaxed)-1u); + } + } return ret; } diff --git a/src/utilpvt.h b/src/utilpvt.h index 7c84a77..bc23323 100644 --- a/src/utilpvt.h +++ b/src/utilpvt.h @@ -267,18 +267,27 @@ struct Restore { } }; -template* Cnt> -struct InstCounter -{ - InstCounter() {(*Cnt).fetch_add(1, std::memory_order_relaxed);} - ~InstCounter() {(*Cnt).fetch_sub(1, std::memory_order_relaxed);} +PVXS_API +void registerICount(const char* name, std::atomic& Cnt); + +// Name and Cnt must have global lifetime +template& Cnt> +struct InstCounter { + explicit InstCounter(const char* Name) { + if(0u==Cnt.fetch_add(1u, std::memory_order_relaxed)) { // first + registerICount(Name, Cnt); + } + } + ~InstCounter() { + Cnt.fetch_sub(1u, std::memory_order_relaxed); + } }; -#define INST_COUNTER(KLASS) InstCounter<&cnt_ ## KLASS> instances - -#define CASE(KLASS) PVXS_API extern std::atomic cnt_ ## KLASS -#include "instcounters.h" -#undef CASE +#define INST_COUNTER(KLASS) \ + static std::atomic cnt_ ## KLASS; \ + InstCounter instances{#KLASS} +#define DEFINE_INST_COUNTER2(KLASS, NAME) std::atomic KLASS::cnt_ ## NAME {0u} +#define DEFINE_INST_COUNTER(KLASS) DEFINE_INST_COUNTER2(KLASS, KLASS) } // namespace pvxs