--- a/webengine/osswebengine/MemoryManager/Src/heap.cpp Fri Jul 03 15:54:40 2009 +0100
+++ b/webengine/osswebengine/MemoryManager/Src/heap.cpp Thu Aug 27 07:44:59 2009 +0300
@@ -29,6 +29,7 @@
#ifdef __NEW_ALLOCATOR__
+#include "MemoryLogger.h"
#include "SymbianDLHeap.h"
_LIT(KDLHeapPanicCategory, "DL Heap");
@@ -46,6 +47,205 @@
#undef UEXPORT_C
#define UEXPORT_C
+
+/* Purpose: Map chunk memory pages from system RAM
+ * Arguments: tp - tchunkptr in which memmory should be mapped
+ * psize - incoming tchunk size
+ * Return: KErrNone if successful, else KErrNoMemory
+ * Note:
+ */
+TInt RSymbianDLHeap::map_chunk_pages(tchunkptr tp, size_t psize)
+{
+ if(page_not_in_memory(tp, psize)) {
+ char *a_addr = tchunk_page_align(tp);
+ size_t npages = tp->npages;
+
+#ifdef OOM_LOGGING
+ // check that npages matches the psize
+ size_t offset = address_offset(a_addr,tp);
+ if(offset < psize && (psize - offset) >= mparams.page_size )
+ {
+ size_t tpages = ( psize - offset) >> pageshift;
+ if(tpages != tp->npages) //assert condition
+ MEM_LOG("CHUNK_PAGE_ERROR:map_chunk_pages, error in npages");
+ }
+ else
+ MEM_LOG("CHUNK_PAGE_ERROR::map_chunk_pages: - Incorrect page-in-memmory flag");
+#endif
+
+ if(map(a_addr, npages*mparams.page_size)) {
+ TRACE_DL_CHUNK_MAP(tp, psize, a_addr, npages*mparams.page_size);
+ ASSERT_RCHUNK_SIZE();
+ TRACE_UNMAPPED_CHUNK(-1*npages*mparams.page_size);
+ return KErrNone;
+ }
+ else {
+ MEM_LOGF(_L8("CHUNK_PAGE_ERROR:: map_chunk_pages - Failed to Commit RAM, page_addr=%x, npages=%d, chunk_size=%d"), a_addr, npages, psize);
+ MEM_DUMP_OOM_LOGS(psize, "RSymbianDLHeap::map_chunk_pages - Failed to Commit RAM");
+ return KErrNoMemory;
+ }
+ }
+ return KErrNone;
+}
+
+/* Purpose: Map partial chunk memory pages from system RAM
+ * Arguments: tp - tchunkptr in which memmory should be mapped
+ * psize - incoming tchunk size
+ * r - remainder chunk pointer
+ * rsize - remainder chunk size
+ * Return: Number of unmapped pages from remainder chunk if successful (0 or more), else KErrNoMemory
+ * Note: Remainder chunk should be large enough to be mapped out (checked before invoking this function)
+ * pageout headers will be set from insert_large_chunk(), not here.
+ */
+TInt RSymbianDLHeap::map_chunk_pages_partial(tchunkptr tp, size_t psize, tchunkptr r, size_t rsize)
+{
+ if(page_not_in_memory(tp, psize)) {
+ size_t npages = tp->npages; // total no of pages unmapped in this chunk
+ char *page_addr_map = tchunk_page_align(tp); // address to begin page map
+ char *page_addr_rem = tchunk_page_align(r); // address in remainder chunk to remain unmapped
+ assert(address_offset(page_addr_rem, r) < rsize);
+ size_t npages_map = address_offset(page_addr_rem, page_addr_map) >> pageshift; // no of pages to be mapped
+ if(npages_map > 0) {
+ if(map(page_addr_map, npages_map*mparams.page_size)) {
+ TRACE_DL_CHUNK_MAP(tp, psize, page_addr_map, npages_map*mparams.page_size);
+ ASSERT_RCHUNK_SIZE();
+ TRACE_UNMAPPED_CHUNK(-1*npages_map*mparams.page_size);
+ return (npages - npages_map);
+ }
+ else {
+ MEM_LOGF(_L8("CHUNK_PAGE_ERROR:: map_chunk_pages_partial - Failed to Commit RAM, page_addr=%x, npages=%d, chunk_size=%d"), page_addr_map, npages_map, psize);
+ MEM_DUMP_OOM_LOGS(psize, "RSymbianDLHeap::map_chunk_pages_partial - Failed to Commit RAM");
+ return KErrNoMemory;
+ }
+ }
+ else {
+ // map not needed, first page is already mapped
+ return npages;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Purpose: Release (unmap) chunk memory pages to system RAM
+ * Arguments: tp - tchunkptr from which memmory may be released
+ * psize - incoming tchunk size
+ * prev_npages - number of pages that has been already unmapped from this chunk
+ * Return: total number of pages that has been unmapped from this chunk (new unmapped pages + prev_npages)
+ * Note: pageout headers will be set from insert_large_chunk(), not here.
+ */
+TInt RSymbianDLHeap::unmap_chunk_pages(tchunkptr tp, size_t psize, size_t prev_npages)
+{
+ size_t npages = 0;
+ char *a_addr = tchunk_page_align(tp);
+ size_t offset = address_offset(a_addr,tp);
+ if(offset < psize && (psize - offset) >= mparams.page_size)
+ { /* check for new pages to decommit */
+ npages = ( psize - offset) >> pageshift;
+ if(npages > prev_npages) {
+ unmap(a_addr, npages*mparams.page_size); // assuming kernel takes care of already unmapped pages
+ TRACE_DL_CHUNK_UNMAP(tp, psize, a_addr, npages*mparams.page_size);
+ iChunkSize += prev_npages*mparams.page_size; //adjust actual chunk size
+ ASSERT_RCHUNK_SIZE();
+ TRACE_UNMAPPED_CHUNK((npages-prev_npages)*mparams.page_size);
+ assert((a_addr + npages*mparams.page_size - 1) < (char*)next_chunk(tp));
+ }
+ }
+
+#ifdef OOM_LOGGING
+ if(npages && (npages < prev_npages))
+ MEM_LOG("CHUNK_PAGE_ERROR:unmap_chunk_pages, error in npages");
+ if(npages > prev_npages) {
+ /* check that end of decommited address lie within this chunk */
+ if((a_addr + npages*mparams.page_size - 1) >= (char*)next_chunk(tp))
+ MEM_LOG("CHUNK_PAGE_ERROR:unmap_chunk_pages, error chunk boundary");
+ }
+#endif
+#ifdef DL_CHUNK_MEM_DEBUG
+ mchunkptr next = next_chunk(tp);
+ do_check_any_chunk_access(next, chunksize(next));
+ if(!npages) do_check_any_chunk_access((mchunkptr)tp, psize);
+#endif
+
+ return (npages);
+}
+
+/* Purpose: Unmap all pages between previously unmapped and end of top chunk
+ and reset top to beginning of prev chunk
+ * Arguments: fm - global malloc state
+ * prev - previous chunk which has unmapped pages
+ * psize - size of previous chunk
+ * prev_npages - number of unmapped pages from previous chunk
+ * Return: nonzero if sucessful, else 0
+ * Note:
+ */
+TInt RSymbianDLHeap::sys_trim_partial(mstate m, mchunkptr prev, size_t psize, size_t prev_npages)
+{
+ size_t released = 0;
+ size_t extra = 0;
+ if (is_initialized(m)) {
+ psize += m->topsize;
+ char *a_addr = tchunk_page_align(prev); // includes space for TOP footer
+ size_t addr_offset = address_offset(a_addr, prev);
+ assert(addr_offset > TOP_FOOT_SIZE); //always assert?
+ assert((char*)iTop >= a_addr); //always assert?
+ if((char*)iTop > a_addr)
+ extra = address_offset(iTop, a_addr);
+
+#ifdef OOM_LOGGING
+ if ((char*)iTop < a_addr)
+ MEM_LOGF(_L8("RSymbianDLHeap::sys_trim_partial - incorrect iTop value, top=%x, iTop=%x"), m->top, iTop);
+#endif
+ msegmentptr sp = segment_holding(m, (TUint8*)prev);
+ if (!is_extern_segment(sp)) {
+ if (is_mmapped_segment(sp)) {
+ if (HAVE_MMAP && sp->size >= extra && !has_segment_link(m, sp)) { /* can't shrink if pinned */
+ size_t newsize = sp->size - extra;
+ /* Prefer mremap, fall back to munmap */
+ if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
+ (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
+ released = extra;
+ }
+ }
+ }
+ else if (HAVE_MORECORE) {
+ if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
+ extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - mparams.granularity;
+ ACQUIRE_MORECORE_LOCK(m);
+ {
+ /* Make sure end of memory is where we last set it. */
+ TUint8* old_br = (TUint8*)(CALL_MORECORE(0));
+ if (old_br == sp->base + sp->size) {
+ TUint8* rel_br = (TUint8*)(CALL_MORECORE(-extra));
+ TUint8* new_br = (TUint8*)(CALL_MORECORE(0));
+ if (rel_br != CMFAIL && new_br < old_br)
+ released = old_br - new_br;
+ }
+ }
+ RELEASE_MORECORE_LOCK(m);
+ }
+ }
+
+ if (released != 0) {
+ TRACE_DL_CHUNK_UNMAP(prev, psize, a_addr, released);
+ iChunkSize += prev_npages*mparams.page_size; // prev_unmapped was already unmapped
+ TRACE_UNMAPPED_CHUNK(-1*prev_npages*mparams.page_size);
+ ASSERT_RCHUNK_SIZE();
+ sp->size -= released;
+ m->footprint -= released;
+ }
+
+ /* reset top to prev chunk */
+ init_top(m, prev, addr_offset - TOP_FOOT_SIZE);
+ check_top_chunk(m, m->top);
+ }
+
+ // DL region not initalized, do not reset top here
+ return (released != 0)? 1 : 0;
+}
+
+
UEXPORT_C RSymbianDLHeap::RSymbianDLHeap(TInt aMaxLength, TInt aAlign, TBool aSingleThread)
// constructor for a fixed heap. Just use DL allocator
:iMinLength(aMaxLength), iMaxLength(aMaxLength), iOffset(0), iGrowBy(0), iChunkHandle(0),
@@ -84,7 +284,7 @@
if (aMinLength == aMaxLength)
Init(0, 0, 0);
else
- Init(0x3fff, 16, 0x10000); // all slabs, page {64KB}, trim {64KB}
+ Init(0x3fff, 15, 0x10000); // all slabs, page {32KB}, trim {64KB}
// Init(0xabe, 16, iPageSize*4); // slabs {48, 40, 32, 24, 20, 16, 12}, page {64KB}, trim {16KB}
}
@@ -112,6 +312,10 @@
/*10-1K,11-2K,12-4k,13-8K,14-16K,15-32K,16-64K*/
paged_init(aPagePower);
+
+#ifdef OOM_LOGGING
+ iUnmappedChunkSize = 0;
+#endif
}
UEXPORT_C RSymbianDLHeap::SCell* RSymbianDLHeap::GetAddress(const TAny* aCell) const
@@ -163,6 +367,9 @@
else
{
addr = paged_allocate(aSize);
+ if(!addr) { // paged_allocator failed, try in dlmalloc
+ addr = dlmalloc(aSize);
+ }
}
Unlock();
@@ -417,18 +624,35 @@
t = leftmost_child(t);
}
/* If dv is a better fit, return 0 so malloc will use it */
- if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
+ if (v != 0) {
if (RTCHECK(ok_address(m, v))) { /* split */
mchunkptr r = chunk_plus_offset(v, nb);
assert(chunksize(v) == rsize + nb);
+
+ /* check for chunk memory page-in */
+ size_t npages_out = 0;
+ if(page_not_in_memory(v, chunksize(v))) {
+ if(!is_small(rsize) && rsize>=CHUNK_PAGEOUT_THESHOLD) {
+ // partial chunk page mapping
+ TInt result = map_chunk_pages_partial(v, chunksize(v), (tchunkptr)r, rsize);
+ if (result < 0) return 0; // Failed to Commit RAM
+ else npages_out = (size_t)result;
+ }
+ else {
+ // full chunk page map needed
+ TInt err = map_chunk_pages(v, chunksize(v));
+ if(err != KErrNone) return 0; // Failed to Commit RAM
+ }
+ }
+
if (RTCHECK(ok_next(v, r))) {
unlink_large_chunk(m, v);
- if (rsize < MIN_CHUNK_SIZE)
+ if (rsize < free_chunk_threshold) // exaust if less than slab threshold
set_inuse_and_pinuse(m, v, (rsize + nb));
else {
set_size_and_pinuse_of_inuse_chunk(m, v, nb);
set_size_and_pinuse_of_free_chunk(r, rsize);
- insert_chunk(m, r, rsize);
+ insert_chunk(m, r, rsize, npages_out);
}
return chunk2mem(v);
}
@@ -460,14 +684,21 @@
if (RTCHECK(ok_address(m, v))) {
mchunkptr r = chunk_plus_offset(v, nb);
assert(chunksize(v) == rsize + nb);
+
+ /* check for chunk memory page-in */
+ if(page_not_in_memory(v, chunksize(v))) {
+ TInt err = map_chunk_pages(v, chunksize(v));
+ if(err != KErrNone) return 0; // Failed to Commit RAM
+ }
+
if (RTCHECK(ok_next(v, r))) {
unlink_large_chunk(m, v);
- if (rsize < MIN_CHUNK_SIZE)
+ if (rsize < free_chunk_threshold) // exaust if less than slab threshold
set_inuse_and_pinuse(m, v, (rsize + nb));
else {
set_size_and_pinuse_of_inuse_chunk(m, v, nb);
set_size_and_pinuse_of_free_chunk(r, rsize);
- replace_dv(m, r, rsize);
+ insert_chunk(m, r, rsize, 0);
}
return chunk2mem(v);
}
@@ -515,7 +746,7 @@
if (oldsize >= nb) { /* already big enough */
size_t rsize = oldsize - nb;
newp = oldp;
- if (rsize >= MIN_CHUNK_SIZE) {
+ if (rsize >= free_chunk_threshold) {
mchunkptr remainder = chunk_plus_offset(newp, nb);
set_inuse(m, newp, nb);
set_inuse(m, remainder, rsize);
@@ -833,6 +1064,8 @@
}
}
/*need to check this*/
+ MEM_DUMP_OOM_LOGS(nb, "sys_alloc:: FAILED to get more memory");
+
//errno = -1;
return 0;
}
@@ -883,12 +1116,12 @@
}
-inline void RSymbianDLHeap::insert_chunk(mstate M,mchunkptr P,size_t S)
+inline void RSymbianDLHeap::insert_chunk(mstate M,mchunkptr P,size_t S,size_t NPAGES)
{
if (is_small(S))
insert_small_chunk(M, P, S);
else{
- tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S);
+ tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S, NPAGES);
}
}
@@ -896,6 +1129,7 @@
{
tchunkptr XP = X->parent;
tchunkptr R;
+ reset_tchunk_mem_pageout(X); // clear chunk pageout flag
if (X->bk != X) {
tchunkptr F = X->fd;
R = X->bk;
@@ -1016,7 +1250,7 @@
/* ------------------------- Operations on trees ------------------------- */
/* Insert chunk into tree */
-inline void RSymbianDLHeap::insert_large_chunk(mstate M,tchunkptr X,size_t S)
+inline void RSymbianDLHeap::insert_large_chunk(mstate M,tchunkptr X,size_t S,size_t NPAGES)
{
tbinptr* H;
bindex_t I;
@@ -1024,6 +1258,10 @@
H = treebin_at(M, I);
X->index = I;
X->child[0] = X->child[1] = 0;
+
+ if(NPAGES) { set_tchunk_mem_pageout(X, NPAGES) }
+ else { reset_tchunk_mem_pageout(X) }
+
if (!treemap_is_marked(M, I)) {
mark_treemap(M, I);
*H = X;
@@ -1157,7 +1395,7 @@
size_t psize = csp - old_top;
mchunkptr tn = chunk_plus_offset(q, psize);
set_free_with_pinuse(q, psize, tn);
- insert_chunk(m, q, psize);
+ insert_chunk(m, q, psize, 0);
}
check_top_chunk(m, m->top);
@@ -1184,20 +1422,20 @@
q->head = tsize | PINUSE_BIT;
check_top_chunk(m, q);
}
- else if (oldfirst == m->dv) {
- size_t dsize = m->dvsize += qsize;
- m->dv = q;
- set_size_and_pinuse_of_free_chunk(q, dsize);
- }
else {
if (!cinuse(oldfirst)) {
size_t nsize = chunksize(oldfirst);
+
+ /* check for chunk memory page-in */
+ if(page_not_in_memory(oldfirst, nsize))
+ map_chunk_pages((tchunkptr)oldfirst, nsize); //Err Ignored, branch not reachable.
+
unlink_chunk(m, oldfirst, nsize);
oldfirst = chunk_plus_offset(oldfirst, nsize);
qsize += nsize;
}
set_free_with_pinuse(q, qsize, oldfirst);
- insert_chunk(m, q, qsize);
+ insert_chunk(m, q, qsize, 0);
check_free_chunk(m, q);
}
@@ -1321,14 +1559,9 @@
/* Can unmap if first chunk holds entire segment and not pinned */
if (!cinuse(p) && (TUint8*)p + psize >= base + size - TOP_FOOT_SIZE) {
tchunkptr tp = (tchunkptr)p;
+ size_t npages_out = tp->npages;
assert(segment_holds(sp, (TUint8*)sp));
- if (p == m->dv) {
- m->dv = 0;
- m->dvsize = 0;
- }
- else {
- unlink_large_chunk(m, tp);
- }
+ unlink_large_chunk(m, tp);
if (CALL_MUNMAP(base, size) == 0) {
released += size;
m->footprint -= size;
@@ -1337,7 +1570,7 @@
sp->next = next;
}
else { /* back out if cannot unmap */
- insert_large_chunk(m, tp, psize);
+ insert_large_chunk(m, tp, psize, npages_out);
}
}
}
@@ -1404,18 +1637,12 @@
Basic algorithm:
If a small request (< 256 bytes minus per-chunk overhead):
1. If one exists, use a remainderless chunk in associated smallbin.
- (Remainderless means that there are too few excess bytes to
- represent as a chunk.)
- 2. If it is big enough, use the dv chunk, which is normally the
- chunk adjacent to the one used for the most recent small request.
- 3. If one exists, split the smallest available chunk in a bin,
- saving remainder in dv.
+ (Remainderless means that there are too few excess bytes to represent as a chunk.)
+ 2. If one exists, split the smallest available chunk in a bin, saving remainder in bin.
4. If it is big enough, use the top chunk.
5. If available, get memory from system and use it
Otherwise, for a large request:
- 1. Find the smallest available binned chunk that fits, and use it
- if it is better fitting than dv chunk, splitting if necessary.
- 2. If better fitting than any binned chunk, use the dv chunk.
+ 1. Find the smallest available binned chunk that fits, splitting if necessary.
3. If it is big enough, use the top chunk.
4. If request size >= mmap threshold, try to directly mmap this chunk.
5. If available, get memory from system and use it
@@ -1443,9 +1670,7 @@
mem = chunk2mem(p);
check_malloced_chunk(gm, mem, nb);
goto postaction;
- }
-
- else if (nb > gm->dvsize) {
+ } else {
if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
mchunkptr b, p, r;
size_t rsize;
@@ -1459,25 +1684,24 @@
unlink_first_small_chunk(gm, b, p, i);
rsize = small_index2size(i) - nb;
/* Fit here cannot be remainderless if 4byte sizes */
- if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+ if (rsize < free_chunk_threshold)
set_inuse_and_pinuse(gm, p, small_index2size(i));
else {
set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
r = chunk_plus_offset(p, nb);
set_size_and_pinuse_of_free_chunk(r, rsize);
- replace_dv(gm, r, rsize);
+ insert_chunk(gm, r, rsize, 0);
}
mem = chunk2mem(p);
check_malloced_chunk(gm, mem, nb);
goto postaction;
}
-
else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
check_malloced_chunk(gm, mem, nb);
goto postaction;
}
}
- }
+ } /* else - large alloc request */
else if (bytes >= MAX_REQUEST)
nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
else {
@@ -1488,27 +1712,7 @@
}
}
- if (nb <= gm->dvsize) {
- size_t rsize = gm->dvsize - nb;
- mchunkptr p = gm->dv;
- if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
- mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
- gm->dvsize = rsize;
- set_size_and_pinuse_of_free_chunk(r, rsize);
- set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
- }
- else { /* exhaust dv */
- size_t dvs = gm->dvsize;
- gm->dvsize = 0;
- gm->dv = 0;
- set_inuse_and_pinuse(gm, p, dvs);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- else if (nb < gm->topsize) { /* Split top */
+ if (nb < gm->topsize) { /* Split top */
size_t rsize = gm->topsize -= nb;
mchunkptr p = gm->top;
mchunkptr r = gm->top = chunk_plus_offset(p, nb);
@@ -1524,6 +1728,13 @@
postaction:
POSTACTION(gm);
+#ifdef DL_CHUNK_MEM_DEBUG
+ if(mem) {
+ mchunkptr pp = mem2chunk(mem);
+ do_check_any_chunk_access(pp, chunksize(pp));
+ }
+#endif
+
return mem;
}
@@ -1539,6 +1750,8 @@
if (mem != 0)
{
+ size_t unmapped_pages = 0;
+ int prev_chunk_unmapped = 0;
mchunkptr p = mem2chunk(mem);
#if FOOTERS
mstate fm = get_mstate_for(p);
@@ -1565,41 +1778,23 @@
{
prevsize &= ~IS_MMAPPED_BIT;
psize += prevsize + MMAP_FOOT_PAD;
- /*TInt tmp = TOP_FOOT_SIZE;
- TUint8* top = (TUint8*)fm->top + fm->topsize + 40;
- if((top == (TUint8*)p)&& fm->topsize > 4096)
- {
- fm->topsize += psize;
- msegmentptr sp = segment_holding(fm, (TUint8*)fm->top);
- sp->size+=psize;
- if (should_trim(fm, fm->topsize))
- sys_trim(fm, 0);
- goto postaction;
- }
- else*/
- {
if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
fm->footprint -= psize;
goto postaction;
- }
}
else
{
mchunkptr prev = chunk_minus_offset(p, prevsize);
+ if(page_not_in_memory(prev, prevsize)) {
+ prev_chunk_unmapped = 1;
+ unmapped_pages = ((tchunkptr)prev)->npages;
+ }
+
psize += prevsize;
p = prev;
if (RTCHECK(ok_address(fm, prev)))
{ /* consolidate backward */
- if (p != fm->dv)
- {
- unlink_chunk(fm, p, prevsize);
- }
- else if ((next->head & INUSE_BITS) == INUSE_BITS)
- {
- fm->dvsize = psize;
- set_free_with_pinuse(p, psize, next);
- goto postaction;
- }
+ unlink_chunk(fm, p, prevsize);
}
else
goto erroraction;
@@ -1611,43 +1806,49 @@
if (!cinuse(next))
{ /* consolidate forward */
if (next == fm->top)
- {
- size_t tsize = fm->topsize += psize;
- fm->top = p;
- p->head = tsize | PINUSE_BIT;
- if (p == fm->dv)
- {
- fm->dv = 0;
- fm->dvsize = 0;
+ {
+ if(prev_chunk_unmapped) { // previous chunk is unmapped
+ /* unmap all pages between previously unmapped and end of top chunk
+ and reset top to beginning of prev chunk - done in sys_trim_partial() */
+ sys_trim_partial(fm, p, psize, unmapped_pages);
+ do_check_any_chunk_access(fm->top, fm->topsize);
+ goto postaction;
}
- if (should_trim(fm, tsize))
- sys_trim(fm, 0);
- goto postaction;
- }
- else if (next == fm->dv)
- {
- size_t dsize = fm->dvsize += psize;
- fm->dv = p;
- set_size_and_pinuse_of_free_chunk(p, dsize);
- goto postaction;
+ else { // forward merge to top
+ size_t tsize = fm->topsize += psize;
+ fm->top = p;
+ p->head = tsize | PINUSE_BIT;
+ if (should_trim(fm, tsize))
+ sys_trim(fm, 0);
+ do_check_any_chunk_access(fm->top, fm->topsize);
+ goto postaction;
+ }
}
else
{
- size_t nsize = chunksize(next);
+ size_t nsize = chunksize(next);
+ int next_chunk_unmapped = 0;
+ if( page_not_in_memory(next, nsize) ) {
+ next_chunk_unmapped = 1;
+ unmapped_pages += ((tchunkptr)next)->npages;
+ }
+
psize += nsize;
unlink_chunk(fm, next, nsize);
set_size_and_pinuse_of_free_chunk(p, psize);
- if (p == fm->dv)
- {
- fm->dvsize = psize;
- goto postaction;
- }
}
}
else
set_free_with_pinuse(p, psize, next);
- insert_chunk(fm, p, psize);
+
+ /* check if chunk memmory can be released */
+ size_t npages_out = 0;
+ if(!is_small(psize) && psize>=CHUNK_PAGEOUT_THESHOLD)
+ npages_out = unmap_chunk_pages((tchunkptr)p, psize, unmapped_pages);
+
+ insert_chunk(fm, p, psize, npages_out);
check_free_chunk(fm, p);
+ do_chunk_page_release_check(p, psize, fm, npages_out);
goto postaction;
}
}
@@ -1959,6 +2160,8 @@
}
sizemap[sz>>2] = ix;
}
+
+ free_chunk_threshold = pad_request(slab_threshold);
}
void* RSymbianDLHeap::slab_allocate(slabset& ss)
@@ -2109,7 +2312,6 @@
TInt r = chunk.Commit(iOffset + ptrdiff(p, this),sz);
if (r < 0)
return 0;
- ASSERT(p = offset(this, r - iOffset));
iChunkSize += sz;
return p;
}
@@ -2267,4 +2469,162 @@
}
}
+/* Only for debugging purpose - start*/
+#ifdef DL_CHUNK_MEM_DEBUG
+void RSymbianDLHeap::debug_check_small_chunk_access(mchunkptr p, size_t psize)
+{
+ size_t sz = chunksize(p);
+ char ch = *((char*)chunk_plus_offset(p, psize-1));
+}
+
+void RSymbianDLHeap::debug_check_any_chunk_access(mchunkptr p, size_t psize)
+{
+ if(p==0 || psize==0) return;
+
+ mchunkptr next = chunk_plus_offset(p, psize);
+ char* t = (char*)chunk_plus_offset(p, mparams.page_size);
+ char ch = *((char*)p);
+ while((size_t)t<(size_t)next)
+ {
+ ch = *t;
+ t = (char*)chunk_plus_offset(t, mparams.page_size);
+ };
+}
+
+void RSymbianDLHeap::debug_check_large_chunk_access(tchunkptr p, size_t psize)
+{
+ mchunkptr next = chunk_plus_offset(p, psize);
+ char* t = (char*)chunk_plus_offset(p, mparams.page_size);
+ char ch = *((char*)p);
+ while((size_t)t<(size_t)next)
+ {
+ ch = *t;
+ t = (char*)chunk_plus_offset(t, mparams.page_size);
+ };
+}
+
+void RSymbianDLHeap::debug_chunk_page_release_check(mchunkptr p, size_t psize, mstate fm, int mem_released)
+{
+ if(mem_released)
+ {
+ if(!page_not_in_memory(p, psize) )
+ MEM_LOG("CHUNK_PAGE_ERROR::dlfree, error - page_in_mem flag is corrupt");
+ if(chunk_plus_offset(p, psize) > fm->top)
+ MEM_LOG("CHUNK_PAGE_ERROR: error Top chunk address invalid");
+ if(fm->dv >= p && fm->dv < chunk_plus_offset(p, psize))
+ MEM_LOG("CHUNK_PAGE_ERROR: error DV chunk address invalid");
+ }
+}
#endif
+
+#ifdef OOM_LOGGING
+#include <hal.h>
+void RSymbianDLHeap::dump_large_chunk(mstate m, tchunkptr t) {
+ tchunkptr u = t;
+ bindex_t tindex = t->index;
+ size_t tsize = chunksize(t);
+ bindex_t idx;
+ compute_tree_index(tsize, idx);
+
+ size_t free = 0;
+ int nfree = 0;
+ do
+ { /* traverse through chain of same-sized nodes */
+ if (u->child[0] != 0)
+ {
+ dump_large_chunk(m, u->child[0]);
+ }
+
+ if (u->child[1] != 0)
+ {
+ dump_large_chunk(m, u->child[1]);
+ }
+
+ free += chunksize(u);
+ nfree++;
+ u = u->fd;
+ }
+ while (u != t);
+ C_LOGF(_L8("LARGE_BIN,%d,%d,%d"), tsize, free, nfree);
+}
+
+void RSymbianDLHeap::dump_dl_free_chunks()
+{
+ C_LOG("");
+ C_LOG("------------ dump_dl_free_chunks start -------------");
+ C_LOG("BinType,BinSize,FreeSize,FreeCount");
+
+ // dump small bins
+ for (int i = 0; i < NSMALLBINS; ++i)
+ {
+ sbinptr b = smallbin_at(gm, i);
+ unsigned int empty = (gm->smallmap & (1 << i)) == 0;
+ int nfree = 0;
+ if (!empty)
+ {
+ int nfree = 0;
+ size_t free = 0;
+ mchunkptr p = b->bk;
+ size_t size = chunksize(p);
+ for (; p != b; p = p->bk)
+ {
+ free += chunksize(p);
+ nfree++;
+ }
+
+ C_LOGF(_L8("SMALL_BIN,%d,%d,%d"), size, free, nfree);
+ }
+ }
+
+ // dump large bins
+ for (int i = 0; i < NTREEBINS; ++i)
+ {
+ tbinptr* tb = treebin_at(gm, i);
+ tchunkptr t = *tb;
+ int empty = (gm->treemap & (1 << i)) == 0;
+ if (!empty)
+ dump_large_chunk(gm, t);
+ }
+
+ C_LOG("------------ dump_dl_free_chunks end -------------");
+ C_LOG("");
+ }
+
+void RSymbianDLHeap::dump_heap_logs(size_t fail_size)
+{
+ MEM_LOG("");
+ if (fail_size) {
+ MEM_LOG("MEMDEBUG::RSymbianDLHeap OOM Log dump *************** start");
+ MEM_LOGF(_L8("Failing to alloc size: %d"), fail_size);
+ }
+ else
+ MEM_LOG("MEMDEBUG::RSymbianDLHeap Log dump *************** start");
+
+ TInt dl_chunk_size = ptrdiff(iTop,iBase);
+ TInt slabp_chunk_size = iChunkSize + iUnmappedChunkSize - dl_chunk_size;
+ TInt freeMem = 0;
+ HAL::Get(HALData::EMemoryRAMFree, freeMem);
+ MEM_LOGF(_L8("System Free RAM Size: %d"), freeMem);
+ MEM_LOGF(_L8("Allocator Commited Chunk Size: %d"), iChunkSize);
+ MEM_LOGF(_L8("DLHeap Arena Size=%d"), dl_chunk_size);
+ MEM_LOGF(_L8("DLHeap unmapped chunk size: %d"), iUnmappedChunkSize);
+ MEM_LOGF(_L8("Slab-Page Allocator Chunk Size=%d"), slabp_chunk_size);
+
+ mallinfo info = dlmallinfo();
+ TUint heapAlloc = info.uordblks;
+ TUint heapFree = info.fordblks;
+ MEM_LOGF(_L8("DLHeap allocated size: %d"), heapAlloc);
+ MEM_LOGF(_L8("DLHeap free size: %d"), heapFree);
+
+ if (fail_size) {
+ MEM_LOG("MEMDEBUG::RSymbianDLHeap OOM Log dump *************** end");
+ }else {
+ MEM_LOG("MEMDEBUG::RSymbianDLHeap Log dump *************** end");
+ }
+ MEM_LOG("");
+}
+
+#endif
+/* Only for debugging purpose - end*/
+
+#endif