// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Per-P malloc cache for small objects. // // See malloc.h for an overview. #include "runtime.h" #include "arch.h" #include "malloc.h" extern volatile intgo runtime_MemProfileRate __asm__ (GOSYM_PREFIX "runtime.MemProfileRate"); // dummy MSpan that contains no free objects. static MSpan emptymspan; MCache* runtime_allocmcache(void) { intgo rate; MCache *c; int32 i; runtime_lock(&runtime_mheap); c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc); runtime_unlock(&runtime_mheap); runtime_memclr((byte*)c, sizeof(*c)); for(i = 0; i < _NumSizeClasses; i++) c->alloc[i] = &emptymspan; // Set first allocation sample size. rate = runtime_MemProfileRate; if(rate > 0x3fffffff) // make 2*rate not overflow rate = 0x3fffffff; if(rate != 0) c->next_sample = runtime_fastrand() % (2*rate); return c; } void runtime_freemcache(MCache *c) { runtime_MCache_ReleaseAll(c); runtime_lock(&runtime_mheap); runtime_purgecachedstats(c); runtime_FixAlloc_Free(&runtime_mheap.cachealloc, c); runtime_unlock(&runtime_mheap); } // Gets a span that has a free object in it and assigns it // to be the cached span for the given sizeclass. Returns this span. MSpan* runtime_MCache_Refill(MCache *c, int32 sizeclass) { MCacheList *l; MSpan *s; runtime_m()->locks++; // Return the current cached span to the central lists. s = c->alloc[sizeclass]; if(s->freelist != nil) runtime_throw("refill on a nonempty span"); if(s != &emptymspan) runtime_MCentral_UncacheSpan(&runtime_mheap.central[sizeclass], s); // Push any explicitly freed objects to the central lists. // Not required, but it seems like a good time to do it. l = &c->free[sizeclass]; if(l->nlist > 0) { runtime_MCentral_FreeList(&runtime_mheap.central[sizeclass], l->list); l->list = nil; l->nlist = 0; } // Get a new cached span from the central lists. s = runtime_MCentral_CacheSpan(&runtime_mheap.central[sizeclass]); if(s == nil) runtime_throw("out of memory"); if(s->freelist == nil) { runtime_printf("%d %d\n", s->ref, (int32)((s->npages << PageShift) / s->elemsize)); runtime_throw("empty span"); } c->alloc[sizeclass] = s; runtime_m()->locks--; return s; } void runtime_MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size) { MCacheList *l; // Put on free list. l = &c->free[sizeclass]; p->next = l->list; l->list = p; l->nlist++; // We transfer a span at a time from MCentral to MCache, // so we'll do the same in the other direction. if(l->nlist >= (runtime_class_to_allocnpages[sizeclass]<list); l->list = nil; l->nlist = 0; } } void runtime_MCache_ReleaseAll(MCache *c) { int32 i; MSpan *s; MCacheList *l; for(i=0; i<_NumSizeClasses; i++) { s = c->alloc[i]; if(s != &emptymspan) { runtime_MCentral_UncacheSpan(&runtime_mheap.central[i], s); c->alloc[i] = &emptymspan; } l = &c->free[i]; if(l->nlist > 0) { runtime_MCentral_FreeList(&runtime_mheap.central[i], l->list); l->list = nil; l->nlist = 0; } } }