-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmd/gc: make interface updates atomic wrt garbage collector #8405
Labels
Milestone
Comments
double-word atomic operations are very rarely supported: (hardware transaction memory based implementation not included, and not to mention that HTM is still a new concept with supports from only the latest processors: intel x86 [amd has another incompatible proposal] and power) ARMv6K+, x86/amd64 and Power ISA v2.07+ (e.g. Power 8) support double-word atomic instructions. ARMv5 or below, mips, pre-v2.07 power, sparc all don't support double-word atomic operations. Also, some (not all?) double-word atomic instructions require double-word alignment. For those reasons, I suggest we don't use double-word atomics for interface values. |
On Intel64 double-word atomic operations must be done with LOCK CMPXCHG16B, 128-bit SSE loads and stores are not guaranteed to be atomic. LOCK CMPXCHG16B sort of does not require 16-byte alignment of data; but if the value happen to cross cache-line boundary the cost just goes from 20 cycles up to 5000 cycles. I don't think we want to use atomics here. |
The data is here: https://docs.google.com/spreadsheets/d/1PTJjoWdgKJvY2S63V2Lh3VgLJrXXW3wO_IXxy2rNA8s/preview If we rule out atomics, then it answers all questions. |
Through this link you can also see comments on values, which explain the meaning: https://docs.google.com/spreadsheets/d/1PTJjoWdgKJvY2S63V2Lh3VgLJrXXW3wO_IXxy2rNA8s/edit#gid=0 |
There is another possibility that I consider the best for now (based on the data). Change interface representations so that the data word is always looks like a pointer. Value that would currently be embed is allocated on heap iff it looks like a pointer into heap. Copyin looks along the line of: static void copyin(Type *t, void *src, void **dst) { uintptr size; void *p; byte *v; Alg *alg; size = t->size; alg = t->alg; if(size > sizeof(*dst)) { // large, so must be on heap anyway p = runtime·cnew(t); alg->copy(size, p, src); *dst = p; } else if((t->kind&KindNoPointers) == 0) { // pointer, map, chan - store directly alg->copy(size, dst, src); } else { // not a pointer, but fits into iface v = nil; alg->copy(size, &v, src); // clear unused bytes if any if(v < arena_start || v >= arena_end) { // note arena_end, not arena_used // does not look like a pointer, store directly alg->copy(size, dst, src); } else { // not a pointer, but looks like a pointer - move to heap p = runtime·cnew(t); alg->copy(size, p, src); *dst = p; } } } The data word is always marked as pointer, and GC uses the usual [arena_start, arena_used) check to determine whether it's an interesting pointer or not. According to the data, there are very few values that fall into that last unfortunate "not a pointer, but looks like a pointer" case even on 386 ("heap" column in "iface" tab). So this solution allows to preserve both memory consumption and performance of the current implementation. |
I don't understand the spreadsheet. Did you remove the inlining of interface operations? It doesn't look like it. Interface conversions that fit exactly a word do not use copyin today. They are inlined. g% cat x.go package p func f(x uintptr) interface{} { return x } g% go tool 6g -S x.go "".f t=1 size=32 value=0 args=0x18 locals=0x0 0x0000 00000 (x.go:3) TEXT "".f+0(SB),4,$0-24 0x0000 00000 (x.go:3) NOP , 0x0000 00000 (x.go:3) NOP , 0x0000 00000 (x.go:3) FUNCDATA $2,gclocals·a73fd2a0c6f832642aa9216fd9c5e6be+0(SB) 0x0000 00000 (x.go:3) FUNCDATA $3,gclocals·3280bececceccd33cb74587feedb1f9f+0(SB) 0x0000 00000 (x.go:4) MOVQ "".x+8(FP),BX 0x0005 00005 (x.go:4) MOVQ BX,"".~r1+24(FP) 0x000a 00010 (x.go:4) MOVQ $type.uintptr+0(SB),"".~r1+16(FP) 0x0013 00019 (x.go:4) RET , 0x0000 48 8b 5c 24 08 48 89 5c 24 18 48 c7 44 24 10 00 H.\$.H.\$.H.D$.. ... It looks to me like the spreadsheet numbers do not include any of these conversions. That is going to skew the results considerably. |
I also don't see anything in the spreadsheet that compares the allocation due to interface conversions with the allocations happening in the rest of the program. Would allocating instead of embedding double the number of allocations by the program? Would it increase them by 1%? I can't tell. There are lots of questions it does not answer. |
> It looks to me like the spreadsheet numbers do not include any of these conversions. That is going to skew the results considerably. When did it happen? Don't say that it's this way for 3 years. Yes, the data misses these conversions. I think that the skew affects only iface/{embed, nil, small, heap} values. So the following calculations are still correct. The iface/alloc is the number of allocations due to copyin; malloc tab shows total number of allocations in the same program; heap/iface/eface show number of ifaces in heap during GC. These numbers must be enough to draw conclusions. For example on garbage-amd64 benchmark heap is ~62MB; heap contains ~10M iface/efaces which is 16MB today. If we increase sizeof iface/eface to 3 words, that will increase heap size by 13%. |
changeset: 13832:8c461c433cb5 user: Nigel Tao <nigeltao@golang.org> date: Thu Jun 14 10:43:20 2012 +1000 description: cmd/gc: inline convT2E when T is uintptr-shaped. changeset: 14281:6d4707371015 user: Daniel Morsing <daniel.morsing@gmail.com> date: Tue Sep 11 21:42:30 2012 +0200 description: cmd/gc: Inline pointer sized T2I interface conversions In the spreadsheet, you are missing all the int/uint/uintptr -> interface conversions. You are not seeing the "not a pointer but looks a pointer value" because those are all missing. You're only seeing int16/int8 and maybe some operations coming from reflect, and yes, very few of them look like a pointer. But the inlined ones may be very different. I think you need to run the numbers again without inlining of these operations enabled. |
I've recollected data with the optimization disabled (cl/112090043): https://docs.google.com/spreadsheets/d/1PTJjoWdgKJvY2S63V2Lh3VgLJrXXW3wO_IXxy2rNA8s/preview Now there is indeed much more embed allocations and some KindPointer conversions that were absent previously. There is still 0 "integers pointing into heap" (another bug?) |
> The benefit of (2) is no atomics and no interface value size change. It also brings the gc and gccgo implementations in line (gccgo already does this). Does gccgo allocate an object always? or only if it's not a pointer? We do want the latter, but I suspect that gccgo can be doing the former. According to the new data, most embed values are either pointers or small integers. We don't need to allocate pointers, because they are already pointers. And for the small integers we can have a persistent cache (which has rough edges as was noted previously). |
I am still inclined towards #5. (1) does not look feasible. (3) can considerably increase heap size for some app, and looks much more complex from implementation point of view. (2) is strictly worser than #5 with regard to memory consumption and performance (#5 is somewhat more complex from implementation POV, though) |
CL https://golang.org/cl/129090043 mentions this issue. |
CL https://golang.org/cl/130240043 mentions this issue. |
This issue was closed by revision 950ad4f. Status changed to Fixed. |
CL https://golang.org/cl/133810043 mentions this issue. |
This issue was closed by revision 5b70b71. |
Rolled back due to breakage on ARM. Take 2: 133820043 runtime: adjust errorCString definition to avoid allocation 133830043 cmd/gc: re-enable IfacePointerOnly Owner changed to @rsc. Status changed to Started. |
CL https://golang.org/cl/133820043 mentions this issue. |
CL https://golang.org/cl/133830043 mentions this issue. |
This issue was closed by revision 75b72b1. Status changed to Fixed. |
wheatman
pushed a commit
to wheatman/go-akaros
that referenced
this issue
Jun 25, 2018
Note that there are various cleanups that can be made if we keep this change, but I do not want to start making changes that depend on this one until the 1.4 cycle closes. Fixes golang#8405. LGTM=r R=golang-codereviews, adg, r, bradfitz CC=golang-codereviews, iant https://golang.org/cl/130240043
wheatman
pushed a commit
to wheatman/go-akaros
that referenced
this issue
Jun 25, 2018
This change broke divmod.go on all arm platforms. ««« original CL description cmd/gc: change interface representation: only pointers in data word Note that there are various cleanups that can be made if we keep this change, but I do not want to start making changes that depend on this one until the 1.4 cycle closes. Fixes golang#8405. LGTM=r R=golang-codereviews, adg, r, bradfitz CC=golang-codereviews, iant https://golang.org/cl/130240043 »»» LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/133810043
wheatman
pushed a commit
to wheatman/go-akaros
that referenced
this issue
Jun 25, 2018
CL 130240043 did this but broke ARM, because it made newErrorCString start allocating, so we rolled it back in CL 133810043. CL 133820043 removed that allocation. Try again. Fixes golang#8405. LGTM=bradfitz, dave R=golang-codereviews, bradfitz CC=dave, golang-codereviews, r https://golang.org/cl/133830043
wheatman
pushed a commit
to wheatman/go-akaros
that referenced
this issue
Jul 9, 2018
Note that there are various cleanups that can be made if we keep this change, but I do not want to start making changes that depend on this one until the 1.4 cycle closes. Fixes golang#8405. LGTM=r R=golang-codereviews, adg, r, bradfitz CC=golang-codereviews, iant https://golang.org/cl/130240043
wheatman
pushed a commit
to wheatman/go-akaros
that referenced
this issue
Jul 9, 2018
This change broke divmod.go on all arm platforms. ««« original CL description cmd/gc: change interface representation: only pointers in data word Note that there are various cleanups that can be made if we keep this change, but I do not want to start making changes that depend on this one until the 1.4 cycle closes. Fixes golang#8405. LGTM=r R=golang-codereviews, adg, r, bradfitz CC=golang-codereviews, iant https://golang.org/cl/130240043 »»» LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/133810043
wheatman
pushed a commit
to wheatman/go-akaros
that referenced
this issue
Jul 9, 2018
CL 130240043 did this but broke ARM, because it made newErrorCString start allocating, so we rolled it back in CL 133810043. CL 133820043 removed that allocation. Try again. Fixes golang#8405. LGTM=bradfitz, dave R=golang-codereviews, bradfitz CC=dave, golang-codereviews, r https://golang.org/cl/133830043
This issue was closed.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
The text was updated successfully, but these errors were encountered: