Reworked sizeof api's to be much more useful; updated implementations to match
git-svn-id: svn://10.0.0.236/trunk@45272 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
* Reserved.
|
||||
*/
|
||||
#include "nsISizeOfHandler.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "plhash.h"
|
||||
|
||||
class nsSizeOfHandler : public nsISizeOfHandler {
|
||||
@@ -27,90 +28,239 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsISizeOfHandler
|
||||
NS_IMETHOD Add(size_t aSize);
|
||||
virtual PRBool HaveSeen(void* anObject);
|
||||
NS_IMETHOD GetSize(PRUint32& aResult);
|
||||
NS_IMETHOD Init();
|
||||
NS_IMETHOD RecordObject(void* aObject, PRBool* aResult);
|
||||
NS_IMETHOD AddSize(nsIAtom* aKey, PRUint32 aSize);
|
||||
NS_IMETHOD Report(nsISizeofReportFunc aFunc, void* aArg);
|
||||
NS_IMETHOD GetTotals(PRUint32* aCountResult, PRUint32* aTotalSizeResult);
|
||||
|
||||
protected:
|
||||
PRUint32 mTotalSize;
|
||||
PLHashTable* mTable;
|
||||
PRUint32 mTotalCount;
|
||||
PLHashTable* mSizeTable;
|
||||
PLHashTable* mObjectTable;
|
||||
|
||||
static PRIntn RemoveObjectEntry(PLHashEntry* he, PRIntn i, void* arg);
|
||||
static PRIntn RemoveSizeEntry(PLHashEntry* he, PRIntn i, void* arg);
|
||||
static PRIntn ReportEntry(PLHashEntry* he, PRIntn i, void* arg);
|
||||
};
|
||||
|
||||
static PLHashNumber
|
||||
HashKey(void* key)
|
||||
class SizeOfDataStats {
|
||||
public:
|
||||
SizeOfDataStats(nsIAtom* aType, PRUint32 aSize);
|
||||
~SizeOfDataStats();
|
||||
|
||||
void Update(PRUint32 aSize);
|
||||
|
||||
nsIAtom* mType; // type
|
||||
PRUint32 mCount; // # of objects of this type
|
||||
PRUint32 mTotalSize; // total size of all objects of this type
|
||||
PRUint32 mMinSize; // smallest size for this type
|
||||
PRUint32 mMaxSize; // largest size for this type
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
SizeOfDataStats::SizeOfDataStats(nsIAtom* aType, PRUint32 aSize)
|
||||
: mType(aType),
|
||||
mCount(1),
|
||||
mTotalSize(aSize),
|
||||
mMinSize(aSize),
|
||||
mMaxSize(aSize)
|
||||
{
|
||||
return (PLHashNumber) key;
|
||||
NS_IF_ADDREF(mType);
|
||||
}
|
||||
|
||||
SizeOfDataStats::~SizeOfDataStats()
|
||||
{
|
||||
NS_IF_RELEASE(mType);
|
||||
}
|
||||
|
||||
void
|
||||
SizeOfDataStats::Update(PRUint32 aSize)
|
||||
{
|
||||
mCount++;
|
||||
if (aSize < mMinSize) mMinSize = aSize;
|
||||
if (aSize > mMaxSize) mMaxSize = aSize;
|
||||
mTotalSize += aSize;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define POINTER_HASH_KEY(_atom) ((PLHashNumber) _atom)
|
||||
|
||||
static PLHashNumber
|
||||
PointerHashKey(nsIAtom* key)
|
||||
{
|
||||
return POINTER_HASH_KEY(key);
|
||||
}
|
||||
|
||||
static PRIntn
|
||||
CompareKeys(void* key1, void* key2)
|
||||
PointerCompareKeys(void* key1, void* key2)
|
||||
{
|
||||
return key1 == key2;
|
||||
}
|
||||
|
||||
nsSizeOfHandler::nsSizeOfHandler()
|
||||
: mTotalSize(0),
|
||||
mTotalCount(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mTotalSize = 0;
|
||||
mTable = PL_NewHashTable(8, (PLHashFunction) HashKey,
|
||||
(PLHashComparator) CompareKeys,
|
||||
(PLHashComparator) nsnull,
|
||||
nsnull, nsnull);
|
||||
mSizeTable = PL_NewHashTable(32, (PLHashFunction) PointerHashKey,
|
||||
(PLHashComparator) PointerCompareKeys,
|
||||
(PLHashComparator) nsnull,
|
||||
nsnull, nsnull);
|
||||
mObjectTable = PL_NewHashTable(32, (PLHashFunction) PointerHashKey,
|
||||
(PLHashComparator) PointerCompareKeys,
|
||||
(PLHashComparator) nsnull,
|
||||
nsnull, nsnull);
|
||||
}
|
||||
|
||||
PRIntn
|
||||
nsSizeOfHandler::RemoveObjectEntry(PLHashEntry* he, PRIntn i, void* arg)
|
||||
{
|
||||
// Remove and free this entry and continue enumerating
|
||||
return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
PRIntn
|
||||
nsSizeOfHandler::RemoveSizeEntry(PLHashEntry* he, PRIntn i, void* arg)
|
||||
{
|
||||
if (he->value) {
|
||||
SizeOfDataStats* stats = (SizeOfDataStats*) he->value;
|
||||
he->value = nsnull;
|
||||
delete stats;
|
||||
}
|
||||
|
||||
// Remove and free this entry and continue enumerating
|
||||
return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
nsSizeOfHandler::~nsSizeOfHandler()
|
||||
{
|
||||
if (nsnull != mTable) {
|
||||
PL_HashTableDestroy(mTable);
|
||||
if (nsnull != mObjectTable) {
|
||||
PL_HashTableEnumerateEntries(mObjectTable, RemoveObjectEntry, 0);
|
||||
PL_HashTableDestroy(mObjectTable);
|
||||
}
|
||||
if (nsnull != mSizeTable) {
|
||||
PL_HashTableEnumerateEntries(mSizeTable, RemoveSizeEntry, 0);
|
||||
PL_HashTableDestroy(mSizeTable);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsSizeOfHandler, nsISizeOfHandler)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSizeOfHandler::Add(size_t aSize)
|
||||
nsSizeOfHandler::Init()
|
||||
{
|
||||
if (mObjectTable) {
|
||||
PL_HashTableEnumerateEntries(mObjectTable, RemoveObjectEntry, 0);
|
||||
}
|
||||
if (mSizeTable) {
|
||||
PL_HashTableEnumerateEntries(mSizeTable, RemoveSizeEntry, 0);
|
||||
}
|
||||
mTotalCount = 0;
|
||||
mTotalSize = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSizeOfHandler::RecordObject(void* aAddr, PRBool* aResult)
|
||||
{
|
||||
if (!aResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
PRBool result = PR_TRUE;
|
||||
if (mObjectTable && aAddr) {
|
||||
PLHashNumber hashCode = POINTER_HASH_KEY(aAddr);
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mObjectTable, hashCode, aAddr);
|
||||
PLHashEntry* he = *hep;
|
||||
if (!he) {
|
||||
// We've never seen it before. Add it to the table
|
||||
(void) PL_HashTableRawAdd(mObjectTable, hep, hashCode, aAddr, aAddr);
|
||||
result = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
*aResult = result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSizeOfHandler::AddSize(nsIAtom* aType, PRUint32 aSize)
|
||||
{
|
||||
PLHashNumber hashCode = POINTER_HASH_KEY(aType);
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mSizeTable, hashCode, aType);
|
||||
PLHashEntry* he = *hep;
|
||||
if (he) {
|
||||
// Stats already exist
|
||||
SizeOfDataStats* stats = (SizeOfDataStats*) he->value;
|
||||
stats->Update(aSize);
|
||||
}
|
||||
else {
|
||||
// Make new stats for the new frame type
|
||||
SizeOfDataStats* newStats = new SizeOfDataStats(aType, aSize);
|
||||
PL_HashTableRawAdd(mSizeTable, hep, hashCode, aType, newStats);
|
||||
}
|
||||
mTotalCount++;
|
||||
mTotalSize += aSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSizeOfHandler::HaveSeen(void* anObject)
|
||||
struct ReportArgs {
|
||||
nsISizeOfHandler* mHandler;
|
||||
nsISizeofReportFunc mFunc;
|
||||
void* mArg;
|
||||
};
|
||||
|
||||
PRIntn
|
||||
nsSizeOfHandler::ReportEntry(PLHashEntry* he, PRIntn i, void* arg)
|
||||
{
|
||||
if (nsnull == mTable) {
|
||||
// When we run out of memory, HaveSeen returns PR_TRUE to stop
|
||||
// wasting time.
|
||||
return PR_TRUE;
|
||||
ReportArgs* ra = (ReportArgs*) arg;
|
||||
if (he && ra && ra->mFunc) {
|
||||
SizeOfDataStats* stats = (SizeOfDataStats*) he->value;
|
||||
if (stats) {
|
||||
(*ra->mFunc)(ra->mHandler, stats->mType, stats->mCount,
|
||||
stats->mTotalSize, stats->mMinSize, stats->mMaxSize,
|
||||
ra->mArg);
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull != anObject) {
|
||||
PRInt32 hashCode = (PRInt32) anObject;
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, anObject);
|
||||
PLHashEntry* he = *hep;
|
||||
if (nsnull != he) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
he = PL_HashTableRawAdd(mTable, hep, hashCode, anObject, anObject);
|
||||
if (nsnull == he) {
|
||||
// When we run out of memory, HaveSeen returns PR_TRUE to stop
|
||||
// wasting time.
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
// Remove and free this entry and continue enumerating
|
||||
return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSizeOfHandler::GetSize(PRUint32& aResult)
|
||||
nsSizeOfHandler::Report(nsISizeofReportFunc aFunc, void* aArg)
|
||||
{
|
||||
aResult = mTotalSize;
|
||||
ReportArgs ra;
|
||||
ra.mHandler = this;
|
||||
ra.mFunc = aFunc;
|
||||
ra.mArg = aArg;
|
||||
PL_HashTableEnumerateEntries(mSizeTable, ReportEntry, (void*) &ra);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSizeOfHandler::GetTotals(PRUint32* aTotalCountResult,
|
||||
PRUint32* aTotalSizeResult)
|
||||
{
|
||||
if (!aTotalCountResult || !aTotalSizeResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
*aTotalCountResult = mTotalCount;
|
||||
*aTotalSizeResult = mTotalSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewSizeOfHandler(nsISizeOfHandler** aInstancePtrResult)
|
||||
{
|
||||
if (!aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
nsISizeOfHandler *it = new nsSizeOfHandler();
|
||||
if (it == nsnull) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
Reference in New Issue
Block a user