replace ShowConstructDestruct with simpler CDRMonitor
Hold counters internally instead of exposing (and duplicating) counting code in other compile units Remove deleteFunc list. This should be handled by another mechanism. CDRMonitor is debugging code. Use internal singly linked list to avoid special handling of LinkedList.
This commit is contained in:
@@ -11,201 +11,80 @@
|
||||
#include <stdio.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include "noDefaultMethods.h"
|
||||
#include "lock.h"
|
||||
#include "pvType.h"
|
||||
#include "linkedList.h"
|
||||
#include "showConstructDestruct.h"
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
static ShowConstructDestruct *pShowConstructDestruct = 0;
|
||||
static Mutex globalMutex;
|
||||
static bool notInited = true;
|
||||
typedef LinkedListNode<ConstructDestructCallback> ListNode;
|
||||
typedef LinkedList<ConstructDestructCallback> List;
|
||||
static List *list;
|
||||
static
|
||||
epicsThreadOnceId monitorInit = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
/* list callbacks are special because showConstructDestruct creates a list
|
||||
Thus list can be null when list calls registerCallback
|
||||
The list callbacks are not put on the list but handled separately
|
||||
*/
|
||||
static ConstructDestructCallback *listCallback = 0;
|
||||
static ConstructDestructCallback *listNodeCallback = 0;
|
||||
// Must use a pointer w/ lazy init due to lack of
|
||||
// initialization order guarantees
|
||||
CDRMonitor* CDRMonitor::theone = 0;
|
||||
|
||||
ConstructDestructCallback::ConstructDestructCallback(
|
||||
String name,
|
||||
getTotalFunc construct,
|
||||
getTotalFunc destruct,
|
||||
getTotalFunc reference,
|
||||
deleteStaticFunc deleteFunc)
|
||||
: name(name), construct(construct), destruct(destruct) ,reference(reference),
|
||||
deleteFunc(deleteFunc)
|
||||
{ }
|
||||
|
||||
ConstructDestructCallback::~ConstructDestructCallback() {}
|
||||
|
||||
String ConstructDestructCallback::getConstructName()
|
||||
CDRMonitor&
|
||||
CDRMonitor::get()
|
||||
{
|
||||
return name;
|
||||
epicsThreadOnce(&monitorInit, &CDRMonitor::init, 0);
|
||||
assert(theone);
|
||||
return *theone;
|
||||
}
|
||||
|
||||
int64 ConstructDestructCallback::getTotalConstruct()
|
||||
void
|
||||
CDRMonitor::init(void *)
|
||||
{
|
||||
if(construct==0) return 0;
|
||||
return construct();
|
||||
//BUG: No idea how to handle allocation failure at this stage.
|
||||
theone=new CDRMonitor;
|
||||
}
|
||||
|
||||
int64 ConstructDestructCallback:: getTotalDestruct()
|
||||
{
|
||||
if(destruct==0) return 0;
|
||||
return destruct();
|
||||
}
|
||||
CDRMonitor::CDRMonitor()
|
||||
:firstNode(0)
|
||||
{}
|
||||
|
||||
int64 ConstructDestructCallback::getTotalReferenceCount()
|
||||
CDRCount
|
||||
CDRMonitor::current()
|
||||
{
|
||||
if(reference==0) return 0;
|
||||
return reference();
|
||||
}
|
||||
|
||||
void ConstructDestructCallback::deleteStatic()
|
||||
{
|
||||
if(deleteFunc==0) return;
|
||||
deleteFunc();
|
||||
}
|
||||
|
||||
ShowConstructDestruct::ShowConstructDestruct() {}
|
||||
|
||||
ShowConstructDestruct::~ShowConstructDestruct() {
|
||||
delete listCallback;
|
||||
delete listNodeCallback;
|
||||
listCallback = 0;
|
||||
listNodeCallback = 0;
|
||||
}
|
||||
|
||||
void ShowConstructDestruct::registerCallback(
|
||||
String name,
|
||||
getTotalFunc construct,
|
||||
getTotalFunc destruct,
|
||||
getTotalFunc reference,
|
||||
deleteStaticFunc deleteFunc)
|
||||
{
|
||||
getShowConstructDestruct(); // make it initialize
|
||||
Lock xx(&globalMutex);
|
||||
if(name.compare("linkedList")==0) {
|
||||
listCallback = new ConstructDestructCallback(
|
||||
name,construct,destruct,reference,deleteFunc);
|
||||
return;
|
||||
} else if(name.compare("linkedListNode")==0) {
|
||||
listNodeCallback = new ConstructDestructCallback(
|
||||
name,construct,destruct,reference,deleteFunc);
|
||||
return;
|
||||
}
|
||||
if(list==0) {
|
||||
throw std::logic_error(String(
|
||||
"ShowConstructDestruct::registerCallback"));
|
||||
}
|
||||
ConstructDestructCallback *callback = new ConstructDestructCallback(
|
||||
name,construct,destruct,reference,deleteFunc);
|
||||
ListNode *listNode = new ListNode(callback);
|
||||
list->addTail(listNode);
|
||||
}
|
||||
static void showOne(ConstructDestructCallback *callback,FILE *fd)
|
||||
{
|
||||
String name = callback->getConstructName();
|
||||
int64 reference = callback->getTotalReferenceCount();
|
||||
int64 construct = callback->getTotalConstruct();
|
||||
int64 destruct = callback->getTotalDestruct();
|
||||
if(reference==0&&construct==0&&destruct==0) return;
|
||||
fprintf(fd,"%s: ", name.c_str());
|
||||
if(construct>0 || destruct>0) {
|
||||
fprintf(fd," totalConstruct %lli totalDestruct %lli",
|
||||
construct,destruct);
|
||||
}
|
||||
if(reference>0) fprintf(fd," totalReference %lli",reference);
|
||||
int64 diff = construct - destruct;
|
||||
if(diff!=0) fprintf(fd," ACTIVE %lli",diff);
|
||||
fprintf(fd,"\n");
|
||||
}
|
||||
|
||||
ConstructDestructCallback* ShowConstructDestruct::getConstructDestructCallback(
|
||||
String name)
|
||||
{
|
||||
if(name.compare(listNodeCallback->getConstructName())==0) {
|
||||
return listNodeCallback;
|
||||
}
|
||||
if(name.compare(listCallback->getConstructName())==0) {
|
||||
return listCallback;
|
||||
}
|
||||
Lock xx(&globalMutex);
|
||||
ListNode *node = list->getHead();
|
||||
while(node!=0) {
|
||||
ConstructDestructCallback *callback = node->getObject();
|
||||
if(name.compare(callback->getConstructName())==0) {
|
||||
return callback;
|
||||
}
|
||||
node = list->getNext(node);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ShowConstructDestruct::constuctDestructTotals(FILE *fd)
|
||||
{
|
||||
getShowConstructDestruct(); // make it initialize
|
||||
Lock xx(&globalMutex);
|
||||
ListNode *node = list->getHead();
|
||||
while(node!=0) {
|
||||
ConstructDestructCallback *callback = node->getObject();
|
||||
showOne(callback,fd);
|
||||
node = list->getNext(node);
|
||||
}
|
||||
showOne(listNodeCallback,fd);
|
||||
showOne(listCallback,fd);
|
||||
}
|
||||
|
||||
void ShowConstructDestruct::showDeleteStaticExit(FILE *fd)
|
||||
{
|
||||
getShowConstructDestruct(); // make it initialize
|
||||
CDRCount total;
|
||||
for(CDRNode *cur=first(); !!cur; cur=cur->next())
|
||||
{
|
||||
Lock xx(&globalMutex);
|
||||
ListNode *node = list->getHead();
|
||||
while(node!=0) {
|
||||
ConstructDestructCallback *callback = node->getObject();
|
||||
if(callback->deleteFunc!=0) callback->deleteFunc();
|
||||
node = list->getNext(node);
|
||||
}
|
||||
node = list->getHead();
|
||||
while(node!=0) {
|
||||
ConstructDestructCallback *callback = node->getObject();
|
||||
showOne(callback,fd);
|
||||
list->removeHead();
|
||||
delete callback;
|
||||
delete node;
|
||||
node = list->getHead();
|
||||
}
|
||||
delete list;
|
||||
if(listNodeCallback->deleteFunc!=0) listNodeCallback->deleteFunc();
|
||||
if(listCallback->deleteFunc!=0) listCallback->deleteFunc();
|
||||
showOne(listNodeCallback,fd);
|
||||
showOne(listCallback,fd);
|
||||
delete pShowConstructDestruct;
|
||||
pShowConstructDestruct = 0;
|
||||
total+=cur->get();
|
||||
}
|
||||
exit( 0);
|
||||
return total;
|
||||
}
|
||||
|
||||
ShowConstructDestruct * getShowConstructDestruct()
|
||||
void
|
||||
CDRMonitor::show(FILE *fd)
|
||||
{
|
||||
static Mutex mutex;
|
||||
Lock xx(&mutex);
|
||||
if(notInited) {
|
||||
notInited = false;
|
||||
pShowConstructDestruct = new ShowConstructDestruct();
|
||||
List *listTemp;
|
||||
listTemp = new List();
|
||||
list = listTemp;
|
||||
}
|
||||
return pShowConstructDestruct;
|
||||
for(CDRNode *cur=first(); !!cur; cur=cur->next())
|
||||
{
|
||||
cur->show(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDRNode::show(FILE *fd)
|
||||
{
|
||||
Lock x(&guard);
|
||||
if(!current.cons && !current.dtys && !current.refs)
|
||||
return;
|
||||
fprintf(fd,"%s: totalConstruct %lu totalDestruct %lu",
|
||||
nodeName.c_str(), (unsigned long)current.cons,
|
||||
(unsigned long)current.dtys);
|
||||
ssize_t alive=current.cons;
|
||||
alive-=current.dtys;
|
||||
if(current.refs)
|
||||
fprintf(fd," totalReference %ld", current.refs);
|
||||
if(alive)
|
||||
fprintf(fd," ACTIVE %ld\n", (long)alive);
|
||||
else
|
||||
fprintf(fd,"\n");
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -13,96 +13,81 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "noDefaultMethods.h"
|
||||
#include "lock.h"
|
||||
#include "pvType.h"
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
typedef int64 (*getTotalFunc)();
|
||||
typedef void (*deleteStaticFunc)();
|
||||
|
||||
class ConstructDestructCallback : private NoDefaultMethods {
|
||||
public:
|
||||
String getConstructName();
|
||||
int64 getTotalConstruct();
|
||||
int64 getTotalDestruct();
|
||||
int64 getTotalReferenceCount();
|
||||
private:
|
||||
ConstructDestructCallback(
|
||||
String name,
|
||||
getTotalFunc construct,
|
||||
getTotalFunc destruct,
|
||||
getTotalFunc reference,
|
||||
deleteStaticFunc deleteFunc);
|
||||
~ConstructDestructCallback();
|
||||
void deleteStatic();
|
||||
String name;
|
||||
getTotalFunc construct;
|
||||
getTotalFunc destruct;
|
||||
getTotalFunc reference;
|
||||
deleteStaticFunc deleteFunc;
|
||||
friend class ShowConstructDestruct;
|
||||
//! Used to pass around snapshots
|
||||
struct CDRCount { // default copy and assignment are ok
|
||||
size_t cons, dtys;
|
||||
long refs;
|
||||
CDRCount():cons(0),dtys(0),refs(0){}
|
||||
CDRCount& operator+=(const CDRCount& o)
|
||||
{cons+=o.cons; dtys+=o.dtys; refs+=o.refs; return *this;}
|
||||
CDRCount& operator=(size_t count) // reset counters
|
||||
{cons=count; dtys=count; refs=count; return *this;}
|
||||
};
|
||||
|
||||
class ShowConstructDestruct : private NoDefaultMethods {
|
||||
class CDRNode;
|
||||
|
||||
//! @brief Global registrar for CDRNodes
|
||||
class CDRMonitor : private NoDefaultMethods {
|
||||
public:
|
||||
static void registerCallback(
|
||||
String name,
|
||||
getTotalFunc construct,
|
||||
getTotalFunc destruct,
|
||||
getTotalFunc reference,
|
||||
deleteStaticFunc deleteFunc);
|
||||
ConstructDestructCallback* getConstructDestructCallback(String name);
|
||||
void constuctDestructTotals(FILE *fd);
|
||||
static void showDeleteStaticExit(FILE *fd);
|
||||
private:
|
||||
ShowConstructDestruct();
|
||||
~ShowConstructDestruct();
|
||||
friend ShowConstructDestruct* getShowConstructDestruct();
|
||||
};
|
||||
static CDRMonitor& get();
|
||||
|
||||
extern ShowConstructDestruct* getShowConstructDestruct();
|
||||
|
||||
|
||||
|
||||
/* convenience macros - no getTotalReferenceCount() support */
|
||||
|
||||
#define PVDATA_REFCOUNT_MONITOR_DEFINE(NAME) \
|
||||
static volatile int64 NAME ## _totalConstruct = 0; \
|
||||
static volatile int64 NAME ## _totalDestruct = 0; \
|
||||
static Mutex NAME ## _globalMutex; \
|
||||
\
|
||||
static bool NAME ## _notInited = true; \
|
||||
static int64 NAME ## _processTotalConstruct() \
|
||||
{ \
|
||||
Lock xx(&NAME ## _globalMutex); \
|
||||
return NAME ## _totalConstruct; \
|
||||
} \
|
||||
\
|
||||
static int64 NAME ## _processTotalDestruct() \
|
||||
{ \
|
||||
Lock xx(&NAME ## _globalMutex); \
|
||||
return NAME ## _totalDestruct; \
|
||||
} \
|
||||
\
|
||||
static void NAME ## _init() \
|
||||
{ \
|
||||
Lock xx(&NAME ## _globalMutex); \
|
||||
if(NAME ## _notInited) { \
|
||||
NAME ## _notInited = false; \
|
||||
ShowConstructDestruct::registerCallback( \
|
||||
String(#NAME), \
|
||||
NAME ## _processTotalConstruct,NAME ## _processTotalDestruct,0,0); \
|
||||
} \
|
||||
CDRNode* addNode(CDRNode& next)
|
||||
{
|
||||
CDRNode *ret=firstNode;
|
||||
firstNode=&next;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PVDATA_REFCOUNT_MONITOR_DESTRUCT(NAME) \
|
||||
Lock xx(&NAME ## _globalMutex); \
|
||||
NAME ## _totalDestruct++;
|
||||
CDRCount current(); //!< current global count
|
||||
|
||||
#define PVDATA_REFCOUNT_MONITOR_CONSTRUCT(NAME) \
|
||||
NAME ## _init(); \
|
||||
Lock xx(&NAME ## _globalMutex); \
|
||||
NAME ## _totalConstruct++;
|
||||
CDRNode* first(){return firstNode;}
|
||||
|
||||
void show(FILE*);
|
||||
private:
|
||||
// Private ctor for singleton
|
||||
CDRMonitor();
|
||||
CDRNode *firstNode;
|
||||
|
||||
static CDRMonitor *theone;
|
||||
static void init(void*);
|
||||
};
|
||||
|
||||
//! Counters for Construction, Destruction, and References of one class
|
||||
class CDRNode : private NoDefaultMethods {
|
||||
public:
|
||||
CDRNode(const String& name)
|
||||
:nodeName(name)
|
||||
,current()
|
||||
,guard()
|
||||
,nextNode(CDRMonitor::get().addNode(*this))
|
||||
{}
|
||||
void construct(){Lock x(&guard); current.cons++;}
|
||||
void destruct(){Lock x(&guard); current.dtys++;}
|
||||
void incRef(){Lock x(&guard); current.refs++;}
|
||||
void decRef(){Lock x(&guard); current.refs--;}
|
||||
|
||||
CDRNode* next() const{return nextNode;}
|
||||
|
||||
CDRCount get() const{Lock x(&guard); return current;}
|
||||
|
||||
void show(FILE*);
|
||||
private:
|
||||
const String nodeName;
|
||||
CDRCount current;
|
||||
mutable Mutex guard;
|
||||
CDRNode * const nextNode;
|
||||
};
|
||||
|
||||
#define PVDATA_REFCOUNT_MONITOR_DEFINE(NAME) static CDRNode NAME ## _node(#NAME)
|
||||
|
||||
#define PVDATA_REFCOUNT_MONITOR_DESTRUCT(NAME) NAME ## _node.destruct()
|
||||
|
||||
#define PVDATA_REFCOUNT_MONITOR_CONSTRUCT(NAME) NAME ## _node.construct()
|
||||
|
||||
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user