mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-24 05:44:10 +00:00
bug 118061 Enabling nsRecyclingAllocator r=dveditz sr=sfraser
This commit is contained in:
parent
d70f788fac
commit
63fff83ae2
@ -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[] =
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user