Skip to content
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

json: extendSlice optimization is still valid for go1.19 #127

Merged
merged 1 commit into from
Oct 7, 2022

Conversation

chriso
Copy link
Contributor

@chriso chriso commented Oct 7, 2022

This PR enables the extendSlice optimization for go1.18 and go1.19, where it's still valid. The optimization will be disabled again in go1.20 in case internals change.

I get the following improvement for go test ./json -run=^$ -bench=CodeUnmarshal$ -benchtime=2000x -count 10 on arm64:

name              old time/op    new time/op    delta
CodeUnmarshal-10     706µs ± 2%     695µs ± 2%  -1.50%  (p=0.002 n=10+10)

name              old speed      new speed      delta
CodeUnmarshal-10  2.75GB/s ± 2%  2.79GB/s ± 2%  +1.52%  (p=0.002 n=10+10)

The optimization was previously enabled for go1.17 in #96.

@achille-roussel
Copy link
Contributor

It's been 5 versions of Go since we introduced this optimization and it's never been invalidated by the runtime. Maybe we would spend less engineering time if we were to remove the build tag and address if the build ever breaks in a future Go version?

@chriso
Copy link
Contributor Author

chriso commented Oct 7, 2022

I think it's still better to opt-in to the unsafe code.

If the internals do change, and we don't remember to check whether it still works each time a new version is released, do we risk exposing users to segfaults?

//go:linkname unsafe_NewArray reflect.unsafe_NewArray
func unsafe_NewArray(rtype unsafe.Pointer, length int) unsafe.Pointer

//go:linkname typedslicecopy reflect.typedslicecopy
//go:noescape
func typedslicecopy(elemType unsafe.Pointer, dst, src slice) int

func extendSlice(t reflect.Type, s *slice, n int) slice {
	elemTypeRef := t.Elem()
	elemTypePtr := ((*iface)(unsafe.Pointer(&elemTypeRef))).ptr

	d := slice{
		data: unsafe_NewArray(elemTypePtr, n),
		len:  s.len,
		cap:  n,
	}

	typedslicecopy(elemTypePtr, d, *s)
	return d
}

On the other hand, if we forget to (re)enable it when a new version is released, our code only gets ~1.5% slower.

@chriso chriso merged commit 3391c4a into master Oct 7, 2022
@chriso chriso deleted the extend-slice-1.19 branch October 7, 2022 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants