mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 10:21:20 +00:00
Currently, each SecMap has an array of linesF, referenced by the linesZ
of the secmap that needs a lineF, via an index stored in dict[1].
When the array is full, its size is doubled.
The linesF array of a secmap is freed when the SecMap is GC-ed.
The above strategy has the following consequences:
A. in average, 25% of the LinesF are unused.
B. if a SecMap has 'temporarily' a need for linesF, but afterwards,
these linesF are converted to normal lineZ representation, the linesF
will not be recuperated unless the SecMap is GC-ed (i.e. fully marked
no access).
The patch replaces the linesF array private per SecMap
by a pool allocator of LinesF shared between all SecMap.
A lineZ that needs a lineF will directly point to its lineF (using a pointer
stored in dict[1]), instead of having in dict[1] the index in the SecMap
linesF array.
When a lineZ needs a lineF, it is allocated from the pool allocator.
When a lineZ does not need anymore a lineF, it is returned back to the
pool allocator.
On a firefox startup, the above strategy reduces the memory for linesF
by about 42Mb. It seems that the more firefox is used (e.g. to visit
a few websites), the bigger the memory gain.
After opening the home page of valgrind, wikipedia and google, the memory
gain is about 94Mb:
trunk:
linesF: 392,181 allocd ( 203,934,120 bytes occupied) ( 173,279 used)
patch:
linesF: 212,966 allocd ( 109,038,592 bytes occupied) ( 170,252 used)
There is also less alloc/free operations in core arena with the patch:
trunk:
core : 810,680,320/ 802,291,712 max/curr mmap'd, 17/19 unsplit/split sb unmmap'd, 759,441,224/ 703,191,896 max/curr, 40631760/16376828248 totalloc-blocks/bytes, 188015696 searches 8 rzB
patch:
core : 701,628,416/ 690,753,536 max/curr mmap'd, 12/29 unsplit/split sb unmmap'd, 643,041,944/ 577,793,712 max/curr, 32050040/14056017712 totalloc-blocks/bytes, 174097728 searches 8 rzB
In terms of performance, no CPU impact detected on Firefox startup.
Note we have no representative reproducible (and preferrably small)
perf test that uses extensively linesF. Firefox is a good heavy lineF
user but is far to be reproducible, and is very far to be small.
Theoretically, in terms of CPU performance, the patch might have some
small benefits here and there for read operations, as the lineF pointer
is directly retrieved from the lineZ, rather than retrieved via an indirection
in the linesF array.
For write operations, the patch might need a little bit more CPU,
as we replace an
assignment to lineF inUse boolean to False (and then probably back to True
when the cacheline is written back)
by
a call to pool allocator VG_(freeEltPA) (and then probably a call to
VG_(allocEltPA) when the cacheline is written back).
These PA functions are small, so cost should be ok.
We might however still maintain in clear_LineF_of_Z the last cleared lineF
and re-use it in alloc_LineF_for_Z. Not sure how many calls to the PA functions
would be avoided by this '1 elt cache' (and the needed 'if elt == NULL'
check in both clear_LineF_of_Z and alloc_LineF_for_Z.
This possible optimisationwill be looked at later.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15253
154 lines
4.6 KiB
C
154 lines
4.6 KiB
C
/*------------------------------------------------------------------------*/
|
|
/*--- A simple pool (memory) allocator implementation. m_poolalloc.c --- */
|
|
/*------------------------------------------------------------------------*/
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2011-2013 OpenWorks LLP info@open-works.co.uk,
|
|
Philippe Waroquiers philippe.waroquiers@skynet.be
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
*/
|
|
|
|
#include "pub_core_basics.h"
|
|
#include "pub_core_libcbase.h"
|
|
#include "pub_core_libcassert.h"
|
|
#include "pub_core_xarray.h"
|
|
#include "pub_core_poolalloc.h" /* self */
|
|
|
|
struct _PoolAlloc {
|
|
UWord nrRef; /* nr reference to this pool allocator */
|
|
UWord elemSzB; /* element size */
|
|
UWord nPerPool; /* # elems per pool */
|
|
void* (*alloc_fn)(const HChar*, SizeT); /* pool allocator */
|
|
const HChar* cc; /* pool allocator's cost centre */
|
|
void (*free_fn)(void*); /* pool allocator's free-er */
|
|
/* XArray of void* (pointers to pools). The pools themselves.
|
|
Each element is a pointer to a block of size (elemSzB *
|
|
nPerPool) bytes. */
|
|
XArray* pools;
|
|
/* next free element. Is a pointer to an element in one of the
|
|
pools pointed to by .pools */
|
|
void* nextFree;
|
|
};
|
|
|
|
PoolAlloc* VG_(newPA) ( UWord elemSzB,
|
|
UWord nPerPool,
|
|
void* (*alloc_fn)(const HChar*, SizeT),
|
|
const HChar* cc,
|
|
void (*free_fn)(void*) )
|
|
{
|
|
PoolAlloc* pa;
|
|
vg_assert(0 == (elemSzB % sizeof(UWord)));
|
|
vg_assert(elemSzB >= sizeof(UWord));
|
|
vg_assert(nPerPool >= 100); /* let's say */
|
|
vg_assert(alloc_fn);
|
|
vg_assert(cc);
|
|
vg_assert(free_fn);
|
|
pa = alloc_fn(cc, sizeof(*pa));
|
|
VG_(memset)(pa, 0, sizeof(*pa));
|
|
pa->nrRef = 0;
|
|
pa->elemSzB = elemSzB;
|
|
pa->nPerPool = nPerPool;
|
|
pa->pools = NULL;
|
|
pa->alloc_fn = alloc_fn;
|
|
pa->cc = cc;
|
|
pa->free_fn = free_fn;
|
|
pa->pools = VG_(newXA)( alloc_fn, cc, free_fn, sizeof(void*) );
|
|
pa->nextFree = NULL;
|
|
|
|
return pa;
|
|
}
|
|
|
|
void VG_(deletePA) ( PoolAlloc* pa)
|
|
{
|
|
Word i;
|
|
vg_assert(pa->nrRef == 0);
|
|
for (i = 0; i < VG_(sizeXA) (pa->pools); i++)
|
|
pa->free_fn (*(UWord **)VG_(indexXA) ( pa->pools, i ));
|
|
VG_(deleteXA) (pa->pools);
|
|
pa->free_fn (pa);
|
|
}
|
|
|
|
/* The freelist is empty. Allocate a new pool and put all the new
|
|
elements in it onto the freelist. */
|
|
__attribute__((noinline))
|
|
static void pal_add_new_pool ( PoolAlloc* pa )
|
|
{
|
|
Word i;
|
|
UWord* pool;
|
|
vg_assert(pa);
|
|
vg_assert(pa->nextFree == NULL);
|
|
pool = pa->alloc_fn( pa->cc, pa->elemSzB * pa->nPerPool );
|
|
/* extend the freelist through the new pool. Place the freelist
|
|
pointer in the first word of each element. That's why the
|
|
element size must be at least one word. */
|
|
for (i = pa->nPerPool-1; i >= 0; i--) {
|
|
UChar* elemC = ((UChar*)pool) + i * pa->elemSzB;
|
|
UWord* elem = (UWord*)elemC;
|
|
vg_assert(0 == (((UWord)elem) % sizeof(UWord)));
|
|
*elem = (UWord)pa->nextFree;
|
|
pa->nextFree = elem;
|
|
}
|
|
/* and add to our collection of pools */
|
|
VG_(addToXA)( pa->pools, &pool );
|
|
}
|
|
|
|
UWord VG_(sizePA) ( PoolAlloc* pa)
|
|
{
|
|
vg_assert(pa);
|
|
return pa->nPerPool * VG_(sizeXA) (pa->pools);
|
|
}
|
|
|
|
void* VG_(allocEltPA) ( PoolAlloc* pa)
|
|
{
|
|
UWord* elem;
|
|
if (UNLIKELY(pa->nextFree == NULL)) {
|
|
pal_add_new_pool(pa);
|
|
}
|
|
elem = pa->nextFree;
|
|
pa->nextFree = (void*)*elem;
|
|
*elem = 0; /* unnecessary, but just to be on the safe side */
|
|
return elem;
|
|
}
|
|
|
|
void VG_(freeEltPA) ( PoolAlloc* pa, void* p)
|
|
{
|
|
UWord* elem = (UWord*)p;
|
|
*elem = (UWord)pa->nextFree;
|
|
pa->nextFree = elem;
|
|
}
|
|
|
|
|
|
void VG_(addRefPA) ( PoolAlloc* pa)
|
|
{
|
|
pa->nrRef++;
|
|
}
|
|
|
|
UWord VG_(releasePA)(PoolAlloc* pa)
|
|
{
|
|
UWord nrRef;
|
|
|
|
vg_assert(pa->nrRef > 0);
|
|
nrRef = --pa->nrRef;
|
|
if (nrRef == 0)
|
|
VG_(deletePA)(pa);
|
|
return nrRef;
|
|
}
|