-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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/compile: avoid convT2E for T = struct{} (empty struct) #18402
Comments
But the current suggested way for context keys is to
save it into a variable of type interface{} to reduce
the cost of interface conversion?
i.e.
type contextKey struct{}
var SomethingKey interface{} = contextKey{}
then the proposed optimization won't be as useful?
My concern is just that it introduces a special case
to object representation to optimize a case where
there already is another user visible way to optimize.
|
Why should there be any cost to interface conversion of a struct{} ? ISTM that the suggested workaround should be unnecessary. FWIW the "current suggested way" as seen in https://blog.golang.org/context is |
BTW I think the compiler should probably completely optimize out all "struct{}"-valued variables. Using such a variable could be exactly the same as using a struct{}{} literal. Currently different code is generated for:
and
I don't see any reason that there should be a difference. That should perhaps be considered another issue though. |
See also #17725.
This is a general way to optimize doing the interface construction only once. Optimizing struct{} won't invalidate that whole pattern. But it does become useless for struct{}. I'm ok with that. |
That already seems to be the case. The pointer value in interface{}(struct{}{}) is the same as &struct{}{}. |
Right. But we don't need to call convT2E, which calls mallocgc, which then returns &zerobase. We can just use &zerobase directly. |
(Why did this reply not appear on the issue? Weird.)
On Wed, Dec 21, 2016 at 9:41 AM, Chris Stockton ***@***.***> wrote:
Hello, I believe the performance differences I mention are due to workload
on the GC. This workload is not related to the representation of the values
when assigned to an interface, it's how (lifecycle of) they are assigned.
The efficiency of interface{}(struct{}{}) is as efficient as
interface{}((*int)(nil)) for assignment operations. Both will reuse the
same address each time, meaning this is unrelated to #17725
<#17725>. The issue here is the GC has
to take ownership when type TypKey struct{} is moved to the heap. This
may be easier explained in a butchered SSA form.
This is true of all interface{} assignments. They are just the move of two
words, regardless of the type of thing in the interface{}.
This issue (and 17725) are only about constructing the interface{}.
This issue in particular has nothing at all to do with GC (17725 does). We
aren't allocating anything for interfaces containing zero-sized objects.
But we are calling convT2E + mallocgc unnecessarily, which I believe is the
core of this issue.
Unless you think that nil vs &zerobase affects the work GC has to do? I
don't think that is the case.
…
When using a struct literal such as context.WithValue(ctx, TypKey{}, val).
t1 = local TypKey
t2 = *t1
t3 = make interface{} <- t2
t4 = context.WithValue(t0, t3, ...)
When using an addressable value on the heap, context.WithValue(ctx,
VarKey, val)`.
t1 = *VarKey
t2 = make interface{} <- t1
t3 = context.WithValue(t0, t2, ...)
I can't think of a way this could be avoided without a SSA pass that
detects empty composite literals and allocates a single address for each T
in a scratch space, only when T is a empty struct. I may be way off here,
but I wanted to clarify a bit.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#18402 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AGkgIEA9h_zN2QRnfK6iqpNj32v85JzPks5rKWS4gaJpZM4LSytq>
.
|
@randall77 I deleted the post after I made it, I was thinking the conversation was headed around higher level assignment semantics, this makes sense I think:
|
As an additional data point golint checks basic data types for suitability as context keys and explicitly OK's |
Gophetbot still seems ill, so: CL 35562 |
CL https://golang.org/cl/35562 mentions this issue. |
go version devel +0b2daa5 Thu Dec 1 11:23:17 2016 +0000 linux/amd64
An empty struct is held in an interface value as a non-nil pointer. This means that
converting an empty struct to an interface is more expensive that
it needs to be be - it involves a call to convT2E.
Given that conversion of empty structs to interfaces is common (for example,
empty structs are often used as context keys) it may be better to use
the nil pointer as the value part of the interface, making
interface{}(struct{}{}) as efficient as interface{}((*int)(nil)).
The text was updated successfully, but these errors were encountered: