godbus / dbus

Native Go bindings for D-Bus
BSD 2-Clause "Simplified" License
976 stars 225 forks source link

Reduce bytes to strings allocs in decoder #367

Closed marselester closed 1 year ago

marselester commented 1 year ago

Instead of allocating when converting small byte slices to strings in the decoder, we can write to a 4kb buffer and use unsafe.String which refers to that buffer. This approach was successfully tested in https://github.com/marselester/systemd which is used by https://github.com/parca-dev/parca-agent.

Note, BenchmarkUnixFDs showed 8 allocs reduction. With larger dbus messages, the savings should be significant.

$ go test -bench='^BenchmarkUnixFDs$' -benchmem
# new
BenchmarkUnixFDs-2          8052        241806 ns/op       11181 B/op        357 allocs/op
# old
BenchmarkUnixFDs-2          8899        265314 ns/op       11187 B/op        365 allocs/op

The caveat is that we should bump Go to 1.20, I am not sure if that's something you're comfortable with.

marselester commented 1 year ago

That's a good idea to leverage build tags. Maybe I am doing something wrong, but for some reason go1.20 tag clashes with go 1.12 version defined in the go.mod.

$ go test .
# github.com/godbus/dbus/v5 [github.com/godbus/dbus/v5.test]
./btos_new.go:10:9: unsafe.String requires go1.20 or later (-lang was set to go1.12; check go.mod)
FAIL    github.com/godbus/dbus/v5 [build failed]
FAIL
marselester commented 1 year ago

We can use the old way of converting strings in all the Go versions instead of the build tags.

func toString(b []byte) string {
    var s string
    h := (*reflect.StringHeader)(unsafe.Pointer(&s))
    h.Data = uintptr(unsafe.Pointer(&b[0]))
    h.Len = len(b)

    return s
}
guelfey commented 1 year ago

Thanks!