Commit f6f2f771 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: cache one GC workbuf in thread-local storage

We call scanblock for lots of small root pieces
e.g. for every stack frame args and locals area.
Every scanblock invocation calls getempty/putempty,
which accesses lock-free stack shared among all worker threads.
One-element local cache allows most scanblock calls
to proceed without accessing the shared stack.

LGTM=rsc
R=golang-codereviews, rlh
CC=golang-codereviews, khr, rsc
https://golang.org/cl/121250043
parent 22e08d1a
...@@ -334,6 +334,8 @@ struct MCache ...@@ -334,6 +334,8 @@ struct MCache
StackFreeList stackcache[NumStackOrders]; StackFreeList stackcache[NumStackOrders];
void* gcworkbuf;
// Local allocator stats, flushed during GC. // Local allocator stats, flushed during GC.
uintptr local_nlookup; // number of pointer lookups uintptr local_nlookup; // number of pointer lookups
uintptr local_largefree; // bytes freed for large objects (>MaxSmallSize) uintptr local_largefree; // bytes freed for large objects (>MaxSmallSize)
...@@ -344,6 +346,7 @@ struct MCache ...@@ -344,6 +346,7 @@ struct MCache
MSpan* runtime·MCache_Refill(MCache *c, int32 sizeclass); MSpan* runtime·MCache_Refill(MCache *c, int32 sizeclass);
void runtime·MCache_ReleaseAll(MCache *c); void runtime·MCache_ReleaseAll(MCache *c);
void runtime·stackcache_clear(MCache *c); void runtime·stackcache_clear(MCache *c);
void runtime·gcworkbuffree(void *b);
enum enum
{ {
......
...@@ -44,6 +44,7 @@ freemcache(MCache *c) ...@@ -44,6 +44,7 @@ freemcache(MCache *c)
{ {
runtime·MCache_ReleaseAll(c); runtime·MCache_ReleaseAll(c);
runtime·stackcache_clear(c); runtime·stackcache_clear(c);
runtime·gcworkbuffree(c->gcworkbuf);
runtime·lock(&runtime·mheap); runtime·lock(&runtime·mheap);
runtime·purgecachedstats(c); runtime·purgecachedstats(c);
runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c); runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
......
...@@ -570,9 +570,18 @@ markroot(ParFor *desc, uint32 i) ...@@ -570,9 +570,18 @@ markroot(ParFor *desc, uint32 i)
static Workbuf* static Workbuf*
getempty(Workbuf *b) getempty(Workbuf *b)
{ {
MCache *c;
if(b != nil) if(b != nil)
runtime·lfstackpush(&work.full, &b->node); runtime·lfstackpush(&work.full, &b->node);
b = (Workbuf*)runtime·lfstackpop(&work.empty); b = nil;
c = g->m->mcache;
if(c->gcworkbuf != nil) {
b = c->gcworkbuf;
c->gcworkbuf = nil;
}
if(b == nil)
b = (Workbuf*)runtime·lfstackpop(&work.empty);
if(b == nil) if(b == nil)
b = runtime·persistentalloc(sizeof(*b), CacheLineSize, &mstats.gc_sys); b = runtime·persistentalloc(sizeof(*b), CacheLineSize, &mstats.gc_sys);
b->nobj = 0; b->nobj = 0;
...@@ -582,9 +591,23 @@ getempty(Workbuf *b) ...@@ -582,9 +591,23 @@ getempty(Workbuf *b)
static void static void
putempty(Workbuf *b) putempty(Workbuf *b)
{ {
MCache *c;
c = g->m->mcache;
if(c->gcworkbuf == nil) {
c->gcworkbuf = b;
return;
}
runtime·lfstackpush(&work.empty, &b->node); runtime·lfstackpush(&work.empty, &b->node);
} }
void
runtime·gcworkbuffree(void *b)
{
if(b != nil)
putempty(b);
}
// Get a full work buffer off the work.full list, or return nil. // Get a full work buffer off the work.full list, or return nil.
static Workbuf* static Workbuf*
getfull(Workbuf *b) getfull(Workbuf *b)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment