From 47e0a3d7b12bbb12a513d7d1a4ebef8632a471ae Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Tue, 28 May 2013 10:47:35 +0400 Subject: [PATCH] runtime: introduce helper persistentalloc() function It is a caching wrapper around SysAlloc() that can allocate small chunks. Use it for symtab allocations. Reduces number of symtab walks from 4 to 3 (reduces buildfuncs time from 10ms to 7.5ms on a large binary, reduces initial heap size by 680K on the same binary). Also can be used for type info allocation, itab allocation. There are also several places in GC where we do the same thing, they can be changed to use persistentalloc(). Also can be used in FixAlloc, because each instance of FixAlloc allocates in 128K regions, which is too eager. R=golang-dev, daniel.morsing, khr CC=golang-dev https://golang.org/cl/9805043 --- src/pkg/runtime/malloc.goc | 47 ++++++++++++++++++++++++++++++++++++++ src/pkg/runtime/malloc.h | 1 + src/pkg/runtime/symtab.c | 32 ++++++-------------------- 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc index b59693b5989..cf18e8c9e59 100644 --- a/src/pkg/runtime/malloc.goc +++ b/src/pkg/runtime/malloc.goc @@ -484,6 +484,53 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n) return p; } +static struct +{ + Lock; + byte* pos; + byte* end; +} persistent; + +enum +{ + PersistentAllocChunk = 256<<10, + PersistentAllocMaxBlock = 64<<10, // VM reservation granularity is 64K on windows +}; + +// Wrapper around SysAlloc that can allocate small chunks. +// There is no associated free operation. +// Intended for things like function/type/debug-related persistent data. +// If align is 0, uses default align (currently 8). +void* +runtime·persistentalloc(uintptr size, uintptr align) +{ + byte *p; + + if(align) { + if(align&(align-1)) + runtime·throw("persistentalloc: align is now a power of 2"); + if(align > PageSize) + runtime·throw("persistentalloc: align is too large"); + } else + align = 8; + if(size >= PersistentAllocMaxBlock) + return runtime·SysAlloc(size); + runtime·lock(&persistent); + persistent.pos = (byte*)ROUND((uintptr)persistent.pos, align); + if(persistent.pos + size > persistent.end) { + persistent.pos = runtime·SysAlloc(PersistentAllocChunk); + if(persistent.pos == nil) { + runtime·unlock(&persistent); + runtime·throw("runtime: cannot allocate memory"); + } + persistent.end = persistent.pos + PersistentAllocChunk; + } + p = persistent.pos; + persistent.pos += size; + runtime·unlock(&persistent); + return p; +} + static Lock settype_lock; void diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index e732e3d15d6..99a19660716 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -445,6 +445,7 @@ void runtime·MHeap_MapBits(MHeap *h); void runtime·MHeap_Scavenger(void); void* runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed); +void* runtime·persistentalloc(uintptr size, uintptr align); int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s); void runtime·gc(int32 force); void runtime·markallocated(void *v, uintptr n, bool noptr); diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c index 5edcb49bda8..fdebe2cae37 100644 --- a/src/pkg/runtime/symtab.c +++ b/src/pkg/runtime/symtab.c @@ -69,11 +69,6 @@ struct Sym static uintptr mainoffset; -// A dynamically allocated string containing multiple substrings. -// Individual strings are slices of hugestring. -static String hugestring; -static int32 hugestring_len; - extern void main·main(void); static uintptr @@ -288,7 +283,6 @@ makepath(byte *buf, int32 nbuf, byte *path) return p - buf; } -// appends p to hugestring static String gostringn(byte *p, int32 l) { @@ -296,13 +290,8 @@ gostringn(byte *p, int32 l) if(l == 0) return runtime·emptystring; - if(hugestring.str == nil) { - hugestring_len += l; - return runtime·emptystring; - } - s.str = hugestring.str + hugestring.len; s.len = l; - hugestring.len += s.len; + s.str = runtime·persistentalloc(l, 1); runtime·memmove(s.str, p, l); return s; } @@ -333,8 +322,6 @@ dosrcline(Sym *sym) switch(sym->symtype) { case 't': case 'T': - if(hugestring.str == nil) - break; if(runtime·strcmp(sym->name, (byte*)"etext") == 0) break; f = &func[nfunc++]; @@ -559,11 +546,12 @@ buildfuncs(void) walksymtab(dofunc); // Initialize tables. - // Can use FlagNoPointers - all pointers either point into sections of the executable - // or point into hugestring. - func = runtime·mallocgc((nfunc+1)*sizeof func[0], FlagNoPointers, 0, 1); + // Memory obtained from runtime·persistentalloc() is not scanned by GC, + // this is fine because all pointers either point into sections of the executable + // or also obtained from persistentmalloc(). + func = runtime·persistentalloc((nfunc+1)*sizeof func[0], 0); func[nfunc].entry = (uint64)etext; - fname = runtime·mallocgc(nfname*sizeof fname[0], FlagNoPointers, 0, 1); + fname = runtime·persistentalloc(nfname*sizeof fname[0], 0); nfunc = 0; lastvalue = 0; walksymtab(dofunc); @@ -573,15 +561,9 @@ buildfuncs(void) // record src file and line info for each func files = runtime·malloc(maxfiles * sizeof(files[0])); - walksymtab(dosrcline); // pass 1: determine hugestring_len - hugestring.str = runtime·mallocgc(hugestring_len, FlagNoPointers, 0, 0); - hugestring.len = 0; - walksymtab(dosrcline); // pass 2: fill and use hugestring + walksymtab(dosrcline); files = nil; - if(hugestring.len != hugestring_len) - runtime·throw("buildfunc: problem in initialization procedure"); - m->nomemprof--; }