mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
292 lines
8.2 KiB
C++
292 lines
8.2 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the NPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the NPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
#include "nscore.h"
|
|
#include "nsISizeOfHandler.h"
|
|
#include "nsIAtom.h"
|
|
#include "plhash.h"
|
|
|
|
class nsSizeOfHandler : public nsISizeOfHandler {
|
|
public:
|
|
nsSizeOfHandler();
|
|
virtual ~nsSizeOfHandler();
|
|
|
|
// nsISupports
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsISizeOfHandler
|
|
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;
|
|
PRUint32 mTotalCount;
|
|
PLHashTable* mSizeTable;
|
|
PLHashTable* mObjectTable;
|
|
|
|
static PRIntn PR_CALLBACK RemoveObjectEntry(PLHashEntry* he, PRIntn i, void* arg);
|
|
static PRIntn PR_CALLBACK RemoveSizeEntry(PLHashEntry* he, PRIntn i, void* arg);
|
|
static PRIntn PR_CALLBACK ReportEntry(PLHashEntry* he, PRIntn i, void* arg);
|
|
};
|
|
|
|
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
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
MOZ_DECL_CTOR_COUNTER(SizeOfDataStats)
|
|
|
|
SizeOfDataStats::SizeOfDataStats(nsIAtom* aType, PRUint32 aSize)
|
|
: mType(aType),
|
|
mCount(1),
|
|
mTotalSize(aSize),
|
|
mMinSize(aSize),
|
|
mMaxSize(aSize)
|
|
{
|
|
MOZ_COUNT_CTOR(SizeOfDataStats);
|
|
NS_IF_ADDREF(mType);
|
|
}
|
|
|
|
SizeOfDataStats::~SizeOfDataStats()
|
|
{
|
|
MOZ_COUNT_DTOR(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) NS_PTR_TO_INT32(_atom)
|
|
|
|
static PLHashNumber
|
|
PointerHashKey(nsIAtom* key)
|
|
{
|
|
return POINTER_HASH_KEY(key);
|
|
}
|
|
|
|
static PRIntn
|
|
PointerCompareKeys(void* key1, void* key2)
|
|
{
|
|
return key1 == key2;
|
|
}
|
|
|
|
nsSizeOfHandler::nsSizeOfHandler()
|
|
: mTotalSize(0),
|
|
mTotalCount(0)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mTotalSize = 0;
|
|
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 != 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::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;
|
|
}
|
|
|
|
struct ReportArgs {
|
|
nsISizeOfHandler* mHandler;
|
|
nsISizeofReportFunc mFunc;
|
|
void* mArg;
|
|
};
|
|
|
|
PRIntn
|
|
nsSizeOfHandler::ReportEntry(PLHashEntry* he, PRIntn i, void* arg)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
return HT_ENUMERATE_NEXT;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSizeOfHandler::Report(nsISizeofReportFunc aFunc, void* aArg)
|
|
{
|
|
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;
|
|
}
|
|
return it->QueryInterface(NS_GET_IID(nsISizeOfHandler), (void **) aInstancePtrResult);
|
|
}
|