Bug 1249174 (part 7.5) - Avoid wasted space around XPT strings. r=khuey.

This patch:

- Removes XPTArena's ability to support arbitrary alignments.

- Hardwires two sub-arenas into XPTArena, one with alignment of 8 and one with
  alignment of 1.

- Uses the first sub-arena for most allocations and the second sub-arena for C
  string allocations.

These changes reduce "xpti-working-set" by 56 KiB.

The patch also renames all the used of "malloc" in XPT identifiers with
"calloc", to make clearer that the result is always zeroed.

--HG--
extra : rebase_source : 8e6cc42644621a7f3c80593006734e25420c7229
This commit is contained in:
Nicholas Nethercote 2016-02-23 16:17:58 +11:00
parent 941e0d3432
commit 2ddfe18454
8 changed files with 118 additions and 92 deletions

View File

@ -48,9 +48,10 @@ xptiInterfaceEntry::Create(const char* name, const nsID& iid,
xptiTypelibGuts* aTypelib)
{
int namelen = strlen(name);
return new (XPT_MALLOC(gXPTIStructArena,
sizeof(xptiInterfaceEntry) + namelen))
xptiInterfaceEntry(name, namelen, iid, aDescriptor, aTypelib);
void* place =
XPT_CALLOC8(gXPTIStructArena, sizeof(xptiInterfaceEntry) + namelen);
return new (place) xptiInterfaceEntry(name, namelen, iid, aDescriptor,
aTypelib);
}
xptiInterfaceEntry::xptiInterfaceEntry(const char* name,

View File

@ -52,7 +52,7 @@ XPTInterfaceInfoManager::CollectReports(nsIHandleReportCallback* aHandleReport,
// Measure gXPTIStructArena here, too. This is a bit grotty because it
// doesn't belong to the XPTIInterfaceInfoManager, but there's no
// obviously better place to measure it.
amount += XPT_SizeOfArena(gXPTIStructArena, XPTIMallocSizeOf);
amount += XPT_SizeOfArenaIncludingThis(gXPTIStructArena, XPTIMallocSizeOf);
return MOZ_COLLECT_REPORT(
"explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, amount,

View File

@ -22,11 +22,10 @@ xptiTypelibGuts*
xptiTypelibGuts::Create(XPTHeader* aHeader)
{
NS_ASSERTION(aHeader, "bad param");
void* place = XPT_MALLOC(gXPTIStructArena,
sizeof(xptiTypelibGuts) +
(sizeof(xptiInterfaceEntry*) *
(aHeader->num_interfaces - 1)));
if(!place)
size_t n = sizeof(xptiTypelibGuts) +
sizeof(xptiInterfaceEntry*) * (aHeader->num_interfaces - 1);
void* place = XPT_CALLOC8(gXPTIStructArena, n);
if (!place)
return nullptr;
return new(place) xptiTypelibGuts(aHeader);
}

View File

@ -13,8 +13,10 @@
using namespace mozilla;
#define XPTI_STRUCT_ARENA_BLOCK_SIZE (1024 * 16)
#define XPTI_HASHTABLE_LENGTH 1024
static const size_t XPTI_ARENA8_BLOCK_SIZE = 16 * 1024;
static const size_t XPTI_ARENA1_BLOCK_SIZE = 8 * 1024;
static const uint32_t XPTI_HASHTABLE_LENGTH = 1024;
XPTInterfaceInfoManager::xptiWorkingSet::xptiWorkingSet()
: mTableReentrantMonitor("xptiWorkingSet::mTableReentrantMonitor")
@ -23,8 +25,8 @@ XPTInterfaceInfoManager::xptiWorkingSet::xptiWorkingSet()
{
MOZ_COUNT_CTOR(xptiWorkingSet);
gXPTIStructArena =
XPT_NewArena(XPTI_STRUCT_ARENA_BLOCK_SIZE, sizeof(double));
gXPTIStructArena = XPT_NewArena(XPTI_ARENA8_BLOCK_SIZE,
XPTI_ARENA1_BLOCK_SIZE);
}
void

View File

@ -29,49 +29,55 @@ struct BLK_HDR
/* XXX this is lame. Should clone the code to do this bitwise */
#define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a)))
struct XPTArena
struct XPTSubArena
{
BLK_HDR *first;
uint8_t *next;
size_t space;
size_t alignment;
size_t block_size;
};
XPT_PUBLIC_API(XPTArena *)
XPT_NewArena(uint32_t block_size, size_t alignment)
struct XPTArena
{
XPTArena *arena = (XPTArena*)calloc(1, sizeof(XPTArena));
// We have one sub-arena with 8-byte alignment for most allocations, and
// one with 1-byte alignment for C string allocations. The latter sub-arena
// avoids significant amounts of unnecessary padding between C strings.
XPTSubArena subarena8;
XPTSubArena subarena1;
};
XPT_PUBLIC_API(XPTArena *)
XPT_NewArena(size_t block_size8, size_t block_size1)
{
XPTArena *arena = static_cast<XPTArena*>(calloc(1, sizeof(XPTArena)));
if (arena) {
XPT_ASSERT(alignment);
if (alignment > sizeof(double))
alignment = sizeof(double);
arena->alignment = alignment;
if (block_size8 < XPT_MIN_BLOCK_SIZE)
block_size8 = XPT_MIN_BLOCK_SIZE;
arena->subarena8.block_size = ALIGN_RND(block_size8, 8);
if (block_size < XPT_MIN_BLOCK_SIZE)
block_size = XPT_MIN_BLOCK_SIZE;
arena->block_size = ALIGN_RND(block_size, alignment);
/* must have room for at least one item! */
XPT_ASSERT(arena->block_size >=
ALIGN_RND(sizeof(BLK_HDR), alignment) +
ALIGN_RND(1, alignment));
if (block_size1 < XPT_MIN_BLOCK_SIZE)
block_size1 = XPT_MIN_BLOCK_SIZE;
arena->subarena1.block_size = block_size1;
}
return arena;
}
static void
DestroySubArena(XPTSubArena *subarena)
{
BLK_HDR* cur = subarena->first;
while (cur) {
BLK_HDR* next = cur->next;
free(cur);
cur = next;
}
return arena;
}
XPT_PUBLIC_API(void)
XPT_DestroyArena(XPTArena *arena)
{
BLK_HDR* cur;
BLK_HDR* next;
cur = arena->first;
while (cur) {
next = cur->next;
free(cur);
cur = next;
}
DestroySubArena(&arena->subarena8);
DestroySubArena(&arena->subarena1);
free(arena);
}
@ -81,11 +87,8 @@ XPT_DestroyArena(XPTArena *arena)
*/
XPT_PUBLIC_API(void *)
XPT_ArenaMalloc(XPTArena *arena, size_t size)
XPT_ArenaCalloc(XPTArena *arena, size_t size, size_t alignment)
{
uint8_t *cur;
size_t bytes;
if (!size)
return NULL;
@ -94,55 +97,66 @@ XPT_ArenaMalloc(XPTArena *arena, size_t size)
return NULL;
}
bytes = ALIGN_RND(size, arena->alignment);
XPTSubArena *subarena;
if (alignment == 8) {
subarena = &arena->subarena8;
} else if (alignment == 1) {
subarena = &arena->subarena1;
} else {
XPT_ASSERT(0);
return NULL;
}
if (bytes > arena->space) {
size_t bytes = ALIGN_RND(size, alignment);
if (bytes > subarena->space) {
BLK_HDR* new_block;
size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), arena->alignment);
size_t new_space = arena->block_size;
while (bytes > new_space - block_header_size)
new_space += arena->block_size;
size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), alignment);
size_t new_space = subarena->block_size;
new_block = (BLK_HDR*) calloc(new_space/arena->alignment,
arena->alignment);
while (bytes > new_space - block_header_size)
new_space += subarena->block_size;
new_block =
static_cast<BLK_HDR*>(calloc(new_space / alignment, alignment));
if (!new_block) {
arena->next = NULL;
arena->space = 0;
subarena->next = NULL;
subarena->space = 0;
return NULL;
}
/* link block into the list of blocks for use when we destroy */
new_block->next = arena->first;
arena->first = new_block;
new_block->next = subarena->first;
subarena->first = new_block;
/* set info for current block */
arena->next = ((uint8_t*)new_block) + block_header_size;
arena->space = new_space - block_header_size;
subarena->next =
reinterpret_cast<uint8_t*>(new_block) + block_header_size;
subarena->space = new_space - block_header_size;
#ifdef DEBUG
/* mark block for corruption check */
memset(arena->next, 0xcd, arena->space);
memset(subarena->next, 0xcd, subarena->space);
#endif
}
}
#ifdef DEBUG
{
/* do corruption check */
size_t i;
for (i = 0; i < bytes; ++i) {
XPT_ASSERT(arena->next[i] == 0xcd);
XPT_ASSERT(subarena->next[i] == 0xcd);
}
/* we guarantee that the block will be filled with zeros */
memset(arena->next, 0, bytes);
}
memset(subarena->next, 0, bytes);
}
#endif
cur = arena->next;
arena->next += bytes;
arena->space -= bytes;
return cur;
uint8_t* p = subarena->next;
subarena->next += bytes;
subarena->space -= bytes;
return p;
}
/***************************************************************************/
@ -157,12 +171,12 @@ XPT_AssertFailed(const char *s, const char *file, uint32_t lineno)
}
#endif
XPT_PUBLIC_API(size_t)
XPT_SizeOfArena(XPTArena *arena, MozMallocSizeOf mallocSizeOf)
static size_t
SizeOfSubArenaExcludingThis(XPTSubArena *subarena, MozMallocSizeOf mallocSizeOf)
{
size_t n = mallocSizeOf(arena);
size_t n = 0;
BLK_HDR* cur = arena->first;
BLK_HDR* cur = subarena->first;
while (cur) {
BLK_HDR* next = cur->next;
n += mallocSizeOf(cur);
@ -171,3 +185,12 @@ XPT_SizeOfArena(XPTArena *arena, MozMallocSizeOf mallocSizeOf)
return n;
}
XPT_PUBLIC_API(size_t)
XPT_SizeOfArenaIncludingThis(XPTArena *arena, MozMallocSizeOf mallocSizeOf)
{
size_t n = mallocSizeOf(arena);
n += SizeOfSubArenaExcludingThis(&arena->subarena8, mallocSizeOf);
n += SizeOfSubArenaExcludingThis(&arena->subarena1, mallocSizeOf);
return n;
}

View File

@ -35,24 +35,22 @@ extern "C" {
typedef struct XPTArena XPTArena;
XPT_PUBLIC_API(XPTArena *)
XPT_NewArena(uint32_t block_size, size_t alignment);
XPT_NewArena(size_t block_size8, size_t block_size1);
XPT_PUBLIC_API(void)
XPT_DestroyArena(XPTArena *arena);
XPT_PUBLIC_API(void *)
XPT_ArenaMalloc(XPTArena *arena, size_t size);
XPT_ArenaCalloc(XPTArena *arena, size_t size, size_t alignment);
XPT_PUBLIC_API(size_t)
XPT_SizeOfArena(XPTArena *arena, MozMallocSizeOf mallocSizeOf);
XPT_SizeOfArenaIncludingThis(XPTArena *arena, MozMallocSizeOf mallocSizeOf);
/* --------------------------------------------------------- */
#define XPT_MALLOC(_arena, _bytes) \
XPT_ArenaMalloc((_arena), (_bytes))
#define XPT_CALLOC(_arena, _size) XPT_MALLOC((_arena), (_size))
#define XPT_NEW(_arena, _struct) ((_struct *) XPT_MALLOC((_arena), sizeof(_struct)))
#define XPT_CALLOC8(_arena, _bytes) XPT_ArenaCalloc((_arena), (_bytes), 8)
#define XPT_CALLOC1(_arena, _bytes) XPT_ArenaCalloc((_arena), (_bytes), 1)
#define XPT_NEW(_arena, _struct) ((_struct *) XPT_CALLOC8((_arena), sizeof(_struct)))
#define XPT_NEWZAP(_arena, _struct) XPT_NEW((_arena), _struct)
/* --------------------------------------------------------- */

View File

@ -108,9 +108,9 @@ XPT_DoHeader(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp)
XPT_SetDataOffset(cursor->state, data_pool);
if (header->num_interfaces) {
header->interface_directory =
(XPTInterfaceDirectoryEntry*)XPT_CALLOC(arena, header->num_interfaces *
sizeof(XPTInterfaceDirectoryEntry));
size_t n = header->num_interfaces * sizeof(XPTInterfaceDirectoryEntry);
header->interface_directory =
static_cast<XPTInterfaceDirectoryEntry*>(XPT_CALLOC8(arena, n));
if (!header->interface_directory)
return PR_FALSE;
}
@ -174,7 +174,7 @@ XPT_InterfaceDescriptorAddTypes(XPTArena *arena, XPTInterfaceDescriptor *id,
size_t new_size = (num * sizeof(XPTTypeDescriptor)) + old_size;
/* XXX should grow in chunks to minimize alloc overhead */
new_ = (XPTTypeDescriptor*)XPT_CALLOC(arena, new_size);
new_ = static_cast<XPTTypeDescriptor*>(XPT_CALLOC8(arena, new_size));
if (!new_)
return PR_FALSE;
if (old) {
@ -213,8 +213,9 @@ DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer,
}
if (id->num_methods) {
id->method_descriptors = (XPTMethodDescriptor*)XPT_CALLOC(arena, id->num_methods *
sizeof(XPTMethodDescriptor));
size_t n = id->num_methods * sizeof(XPTMethodDescriptor);
id->method_descriptors =
static_cast<XPTMethodDescriptor*>(XPT_CALLOC8(arena, n));
if (!id->method_descriptors)
return PR_FALSE;
}
@ -229,8 +230,9 @@ DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer,
}
if (id->num_constants) {
id->const_descriptors = (XPTConstDescriptor*)XPT_CALLOC(arena, id->num_constants *
sizeof(XPTConstDescriptor));
size_t n = id->num_constants * sizeof(XPTConstDescriptor);
id->const_descriptors =
static_cast<XPTConstDescriptor*>(XPT_CALLOC8(arena, n));
if (!id->const_descriptors)
return PR_FALSE;
}
@ -313,7 +315,8 @@ DoMethodDescriptor(XPTArena *arena, XPTCursor *cursor, XPTMethodDescriptor *md,
return PR_FALSE;
if (md->num_args) {
md->params = (XPTParamDescriptor*)XPT_CALLOC(arena, md->num_args * sizeof(XPTParamDescriptor));
size_t n = md->num_args * sizeof(XPTParamDescriptor);
md->params = static_cast<XPTParamDescriptor*>(XPT_CALLOC8(arena, n));
if (!md->params)
return PR_FALSE;
}

View File

@ -125,7 +125,7 @@ XPT_DoCString(XPTArena *arena, XPTCursor *cursor, char **identp, bool ignore)
XPT_ASSERT(len > 0);
if (!ignore) {
char *ident = (char*)XPT_MALLOC(arena, len + 1u);
char *ident = (char*)XPT_CALLOC1(arena, len + 1u);
if (!ident)
return PR_FALSE;