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:
Michael Davidsaver
2011-01-30 18:04:52 -05:00
parent 302d3fe5d2
commit d8fe325dc0
2 changed files with 116 additions and 252 deletions

View File

@@ -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");
}
}}

View File

@@ -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()
}}