diff options
| author | Dmitriy Vyukov <dvyukov@google.com> | 2014-01-27 15:11:12 +0400 |
|---|---|---|
| committer | Dmitriy Vyukov <dvyukov@google.com> | 2014-01-27 15:11:12 +0400 |
| commit | bace9523eed9bc695310cd327b19ecdf7aa44612 (patch) | |
| tree | 4681c7cab80d9aa0b49f93db0b7aad22753d485d /src/pkg/runtime/slice.c | |
| parent | 496c030c506bf1ac18c82ba85d4bcc5031253bdf (diff) | |
| download | go-bace9523eed9bc695310cd327b19ecdf7aa44612.tar.xz | |
runtime: smarter slice grow
When growing slice take into account size of the allocated memory block.
Also apply the same optimization to string->[]byte conversion.
Fixes #6307.
benchmark old ns/op new ns/op delta
BenchmarkAppendGrowByte 4541036 4434108 -2.35%
BenchmarkAppendGrowString 59885673 44813604 -25.17%
LGTM=khr
R=khr
CC=golang-codereviews, iant, rsc
https://golang.org/cl/53340044
Diffstat (limited to 'src/pkg/runtime/slice.c')
| -rw-r--r-- | src/pkg/runtime/slice.c | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c index ef8ab7fe0a..c3b240bc83 100644 --- a/src/pkg/runtime/slice.c +++ b/src/pkg/runtime/slice.c @@ -8,6 +8,7 @@ #include "typekind.h" #include "malloc.h" #include "race.h" +#include "stack.h" #include "../../cmd/ld/textflag.h" enum @@ -92,26 +93,53 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret) static void growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret) { - intgo m; + intgo newcap1; + uintptr capmem, lenmem; + int32 flag; + Type *typ; - m = x.cap; + typ = t->elem; + if(typ->size == 0) { + *ret = x; + ret->cap = newcap; + return; + } + + newcap1 = x.cap; // Using newcap directly for m+m < newcap handles // both the case where m == 0 and also the case where // m+m/4 wraps around, in which case the loop // below might never terminate. - if(m+m < newcap) - m = newcap; + if(newcap1+newcap1 < newcap) + newcap1 = newcap; else { do { if(x.len < 1024) - m += m; + newcap1 += newcap1; else - m += m/4; - } while(m < newcap); + newcap1 += newcap1/4; + } while(newcap1 < newcap); } - makeslice1(t, x.len, m, ret); - runtime·memmove(ret->array, x.array, ret->len * t->elem->size); + + if(newcap1 > MaxMem/typ->size) + runtime·panicstring("growslice: cap out of range"); + capmem = runtime·roundupsize(newcap1*typ->size); + flag = FlagNoZero; + if(typ->kind&KindNoPointers) + flag |= FlagNoScan; + // Here we allocate with FlagNoZero but potentially w/o FlagNoScan, + // GC must not see this blocks until memclr below. + m->locks++; + ret->array = runtime·mallocgc(capmem, (uintptr)typ|TypeInfo_Array, flag); + ret->len = x.len; + ret->cap = capmem/typ->size; + lenmem = x.len*typ->size; + runtime·memmove(ret->array, x.array, lenmem); + runtime·memclr(ret->array+lenmem, capmem-lenmem); + m->locks--; + if(m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack + g->stackguard0 = StackPreempt; } // copy(to any, fr any, wid uintptr) int |
