bug 118061 Enabling nsRecyclingAllocator r=dveditz sr=sfraser

This commit is contained in:
dp%netscape.com 2002-01-24 07:00:07 +00:00
parent d70f788fac
commit 63fff83ae2
4 changed files with 37 additions and 283 deletions

View File

@ -36,10 +36,10 @@
#include "nsCOMPtr.h"
#include "nsIModule.h"
#include "nsIGenericFactory.h"
#include "nsJAR.h"
#include "nsIJARFactory.h"
#include "nsZlibAllocator.h"
#include "nsRecyclingAllocator.h"
extern nsRecyclingAllocator *gZlibAllocator;
// The list of components we register
static nsModuleComponentInfo components[] =

View File

@ -44,14 +44,16 @@
#define READTYPE PRInt32
#include "zlib.h"
#include "nsISupportsUtils.h"
#include "nsZlibAllocator.h"
#include "nsRecyclingAllocator.h"
/**
* Globals
*
* Global allocator used with zlib. Destroyed in module shutdown.
*/
nsZlibAllocator *gZlibAllocator = NULL;
#define NBUCKETS 6
#define BY4ALLOC_ITEMS 320
nsRecyclingAllocator *gZlibAllocator = NULL;
#else /* STANDALONE */
@ -382,148 +384,17 @@ void ProcessWindowsMessages()
// we startup and disabled after we startup if memory is a concern.
//***********************************************************
void * nsZlibAllocator::zAlloc(PRUint32 items, PRUint32 bytes)
{
PRUint32 totalsize = items * bytes;
PRInt32 freeAllocatedBucketIndex = -1;
PRUint32 i;
PRUint32 size;
void *ptr;
for (i = 0; i < NBUCKETS; i++)
{
size = mMemBucket[i].size;
ptr = mMemBucket[i].ptr;
// Dont look at buckets with no memory allocated or less memory than
// what we need.
// Can we do this check without claiming the bucket? I think we can
// because the next thing we do is try claim this bucket.
if (!ptr || size < totalsize)
continue;
// Try Claim a bucket. If we cant, skip it.
if (!Claim(i))
continue;
if (size == totalsize)
{
// Let go of any freeAllocatedBucket that we claimed
if (freeAllocatedBucketIndex >= 0)
Unclaim(freeAllocatedBucketIndex);
// zero out memory and return it
memset(ptr, 0, totalsize);
return ptr;
}
// Meanwhile, remember a free allocated bucket.
// At this point we know the bucket is not in use and it has more
// than what we need
if (freeAllocatedBucketIndex < 0)
freeAllocatedBucketIndex = i;
else
{
// See if this bucket is closer to what we need
if (size < mMemBucket[freeAllocatedBucketIndex].size)
{
Unclaim(freeAllocatedBucketIndex);
freeAllocatedBucketIndex = i;
}
else
// Undo our claim as freeAllocatedBucketIndex does better than this one
Unclaim(i);
}
}
// See if we have an allocated bucket
if (freeAllocatedBucketIndex >= 0)
{
ptr = mMemBucket[freeAllocatedBucketIndex].ptr;
// Clear it, Mark it used and return ptr
// We need to clear only the size that was requested although
// the bucket may be larger
memset(ptr, 0, totalsize);
return ptr;
}
// We dont have that memory already
// Allocate. Make sure we bump up our allocations of x4 allocations
int realitems = items;
if (bytes == 4 && items < BY4ALLOC_ITEMS)
realitems = BY4ALLOC_ITEMS;
ptr = calloc(realitems, bytes);
// Take care of no memory situation
if (!ptr)
return ptr;
// Find a free unallocated bucket and store allocation
for (i = 0; i < NBUCKETS; i++)
{
// If bucket cannot be calimed, continue search.
if (!Claim(i))
continue;
if (!mMemBucket[i].ptr)
{
// Found free slot. Store it
mMemBucket[i].ptr = ptr;
mMemBucket[i].size = realitems * bytes;
return ptr;
}
// This is an already allocated bucket. Cant use this one.
Unclaim(i);
}
#ifdef DEBUG_dp
// Warn if we are failing over to calloc and not storing it
// This says we have a misdesigned memory pool. The intent was
// once the pool was full, we would never fail over to calloc.
printf("zalloc %d [%dx%d] - FAILOVER 0x%p Memory pool has sizes: ",
items*bytes, items, bytes, ptr);
for (i = 0; i < NBUCKETS; i++)
{
printf("%d ", mMemBucket[i].size);
}
printf("\n");
#endif
return ptr;
}
void nsZlibAllocator::zFree(void *ptr)
{
PRUint32 i;
for (i = 0; i < NBUCKETS; i++)
{
if (mMemBucket[i].ptr == ptr)
{
// Ah ha. One of the slots we allocated.
// Nothing to do. Mark it unused.
Unclaim(i);
return;
}
}
#ifdef DEBUG_dp
// Warn if we are failing over to free.
// This says we have a misdesigned memory pool. The intent was
// once the pool was full, we would never fail over to free.
printf("DEBUG: zlib memory pool freeing 0x%p\n", ptr);
#endif
// Failover to free
free(ptr);
return;
}
PR_STATIC_CALLBACK(void *)
zlibAlloc(void *opaque, uInt items, uInt size)
{
nsZlibAllocator *zallocator = (nsZlibAllocator *)opaque;
if (zallocator)
return zallocator->zAlloc(items, size);
nsRecyclingAllocator *zallocator = (nsRecyclingAllocator *)opaque;
if (zallocator) {
// Bump up x4 allocations
PRUint32 realitems = items;
if (size == 4 && items < BY4ALLOC_ITEMS)
realitems = BY4ALLOC_ITEMS;
return zallocator->Calloc(realitems, size);
}
else
return calloc(items, size);
}
@ -531,9 +402,9 @@ zlibAlloc(void *opaque, uInt items, uInt size)
PR_STATIC_CALLBACK(void)
zlibFree(void *opaque, void *ptr)
{
nsZlibAllocator *zallocator = (nsZlibAllocator *)opaque;
nsRecyclingAllocator *zallocator = (nsRecyclingAllocator *)opaque;
if (zallocator)
zallocator->zFree(ptr);
zallocator->Free(ptr);
else
free(ptr);
return;
@ -1063,7 +934,7 @@ PRInt32 nsZipArchive::BuildFileList()
//-- we think we found the central directory, read in the first chunk
pos = 0;
bufsize = PR_Read( mFd, &buf, sizeof(buf) );
if (bufsize < sizeof(ZipCentral) + sizeof(ZipEnd))
if (bufsize < (PRInt32)(sizeof(ZipCentral) + sizeof(ZipEnd)))
{
// We know we read the end sig and got pointed at the central
// directory--there should be at least this much
@ -1404,7 +1275,7 @@ PRInt32 nsZipArchive::InflateItem( const nsZipItem* aItem, PRFileDesc* fOut,
#ifndef STANDALONE
//-- ensure we have our zlib allocator for better performance
if (!gZlibAllocator) {
gZlibAllocator = new nsZlibAllocator();
gZlibAllocator = new nsRecyclingAllocator(NBUCKETS);
}
zs.zalloc = zlibAlloc;

View File

@ -76,11 +76,23 @@ mailing address.
#include "prlog.h"
#include "GIF2.h"
#include "nsCRT.h"
#include "nsGifAllocator.h"
#include "nsRecyclingAllocator.h"
#include "nsAutoLock.h"
// Global gif allocator
nsGifAllocator *gGifAllocator = nsnull;
/*******************************************************************************
* Gif decoder allocator
*
* For every image that gets loaded, we allocate
* 4097 x 2 : gs->prefix
* 4097 x 1 : gs->suffix
* 4097 x 1 : gs->stack
* for lzw to operate on the data. These are held for a very short interval
* and freed. This allocator tries to keep one set of these around
* and reuses them; automatically fails over to use calloc/free when all
* buckets are full.
*/
const int kGifAllocatorNBucket = 6;
nsRecyclingAllocator *gGifAllocator = nsnull;
#define HOWMANY(x, r) (((x) + ((r) - 1)) / (r))
#define ROUNDUP(x, r) (HOWMANY(x, r) * (r))
@ -452,142 +464,11 @@ PRBool gif_create(gif_struct **gs)
return PR_TRUE;
}
/*******************************************************************************
* Gif decoder allocator
*
* For every image that gets loaded, we allocate
* 4097 x 2 : gs->prefix
* 4097 x 1 : gs->suffix
* 4097 x 1 : gs->stack
* for lzw to operate on the data. These are held for a very short interval
* and freed. This allocator tries to keep one set of these around
* and reuses them; automatically fails over to use calloc/free when all
* buckets are full.
*/
void
nsGifAllocator::ClearBuckets()
{
nsAutoLock autolock(mLock);
for (PRUint32 i = 0; i < kNumBuckets; i++)
{
if (mMemBucket[i])
{
// If the bucket is in use, then we will leak that memory.
PR_ASSERT(!IsUsed(i));
if (!IsUsed(i))
{
free(mMemBucket[i]);
}
mMemBucket[i] = nsnull;
mSize[i] = 0;
}
}
// Clear the in use flag of all buckets
mFlag = 0;
}
void *
nsGifAllocator::Calloc(PRUint32 items, PRUint32 size)
{
PRUint32 totalsize = items * size;
PRInt32 freeAllocatedBucket = -1;
nsAutoLock autolock(mLock);
PRUint32 i;
for (i = 0; i < kNumBuckets; i++) {
// if bucket is in use or has no memory, dont touch it.
if (IsUsed(i) || !mMemBucket[i])
continue;
// See if we have the memory already allocated. This is the
// most common case.
if (mSize[i] == totalsize) {
// Exact match. zero out memory, increase refcnt and return it
memset(mMemBucket[i], 0, totalsize);
MarkUsed(i);
return mMemBucket[i];
}
// Meanwhile, remember a free bucket that has enough memory
if (mSize[i] >= totalsize)
freeAllocatedBucket = i;
}
// See if we have an allocated bucket
if (freeAllocatedBucket >= 0) {
// Clear it, Mark it used and return ptr
// We need to clear only the size that was requested although
// the bucket may be larger
memset(mMemBucket[freeAllocatedBucket], 0, totalsize);
MarkUsed(freeAllocatedBucket);
return mMemBucket[freeAllocatedBucket];
}
// Make sure we are not holding on to a lock
autolock.unlock();
void *ptr = calloc(items, size);
// Reaquire the lock
autolock.lock();
// Find a free bucket and store allocation
for (i = 0; i < kNumBuckets; i++)
if (!mMemBucket[i]) {
// Found free slot. Store it
PR_ASSERT(!IsUsed(i));
mMemBucket[i] = ptr;
mSize[i] = totalsize;
MarkUsed(i);
return ptr;
}
#ifdef DEBUG_dp
// Warn if we are failing over to calloc and not storing it
// This says we have a misdesigned memory pool. The intent was
// once the pool was full, we would never fail over to calloc.
printf("0x%p - Calloc %d [%dx%d] - FAILOVER 0x%p Memory pool has sizes: ",
this, items*size, items, size, ptr);
for (i = 0; i < kNumBuckets; i++)
{
printf("%d ", mSize[i]);
}
printf("\n");
#endif
return ptr;
}
void nsGifAllocator::Free(void *ptr)
{
nsAutoLock autolock(mLock);
for (PRUint32 i = 0; i < kNumBuckets; i++)
{
if (mMemBucket[i] == ptr)
{
// Ah ha. One of the slots we allocated.
// Nothing to do. Mark it unused.
ClearUsed(i);
return;
}
}
// Release lock before calling free
autolock.unlock();
// Failover to free
free(ptr);
return;
}
static inline void *
gif_calloc(size_t n, size_t s)
{
if (!gGifAllocator)
gGifAllocator = new nsGifAllocator;
gGifAllocator = new nsRecyclingAllocator(kGifAllocatorNBucket);
if (gGifAllocator)
return gGifAllocator->Calloc(n, s);
else

View File

@ -41,7 +41,9 @@
#include "nsIGenericFactory.h"
#include "nsISupports.h"
#include "nsCOMPtr.h"
#include "nsGifAllocator.h"
#include "nsRecyclingAllocator.h"
extern nsRecyclingAllocator *gGifAllocator;
NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIFDecoder2)