Skip to content

Instantly share code, notes, and snippets.

@smallnest
Created February 21, 2025 02:29
Show Gist options
  • Save smallnest/88efe8b969a93ed695f9c1fe1869e2f8 to your computer and use it in GitHub Desktop.
Save smallnest/88efe8b969a93ed695f9c1fe1869e2f8 to your computer and use it in GitHub Desktop.
go []byte <-> string benchmark
package main
import (
"fmt"
"runtime"
"testing"
"unsafe"
)
func toBytes(s string) []byte {
if len(s) == 0 {
return nil
}
return unsafe.Slice(unsafe.StringData(s), len(s))
}
func toString(b []byte) string {
if len(b) == 0 {
return ""
}
return unsafe.String(unsafe.SliceData(b), len(b))
}
func toReflectBytes(s string) []byte {
if len(s) == 0 {
return nil
}
x := (*[2]uintptr)(unsafe.Pointer(&s))
h := [3]uintptr{x[0], x[1], x[1]}
return *(*[]byte)(unsafe.Pointer(&h))
}
func toReflectString(b []byte) string {
if len(b) == 0 {
return ""
}
return *(*string)(unsafe.Pointer(&b))
}
func toK8sBytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&s))
}
func toK8sString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func toRawBytes(s string) []byte {
if len(s) == 0 {
return nil
}
return []byte(s)
}
func toRawString(b []byte) string {
if len(b) == 0 {
return ""
}
return string(b)
}
var s = "hello, world"
var bts = []byte("hello, world")
func BenchmarkStringToBytesUnsafe(b *testing.B) {
for i := 0; i < b.N; i++ {
toBytes(s)
}
}
func BenchmarkBytesToStringUnsafe(b *testing.B) {
for i := 0; i < b.N; i++ {
toString(bts)
}
}
func BenchmarkStringToBytesReflect(b *testing.B) {
for i := 0; i < b.N; i++ {
toReflectBytes(s)
}
}
func BenchmarkBytesToStringReflect(b *testing.B) {
for i := 0; i < b.N; i++ {
toReflectString(bts)
}
}
func BenchmarkStringToBytesK8s(b *testing.B) {
for i := 0; i < b.N; i++ {
toK8sBytes(s)
}
}
func BenchmarkBytesToStringK8s(b *testing.B) {
for i := 0; i < b.N; i++ {
toK8sString(bts)
}
}
func BenchmarkStringToBytesRaw(b *testing.B) {
for i := 0; i < b.N; i++ {
toRawBytes(s)
}
}
func BenchmarkBytesToStringRaw(b *testing.B) {
for i := 0; i < b.N; i++ {
toRawString(bts)
}
}
func TestGC(t *testing.T) {
for i := 0; i < 1000; i++ {
b := toBytes(s)
runtime.GC()
if b[11] != 'd' {
t.Errorf("want %c, got %c", 'd', b[11])
}
ss := toString(bts)
runtime.GC()
if ss != s {
t.Errorf("want %s, got %s", s, ss)
}
}
for i := 0; i < 1000; i++ {
b := toReflectBytes(s)
runtime.GC()
if b[11] != 'd' {
t.Errorf("want %c, got %c", 'd', b[11])
}
ss := toReflectString(bts)
runtime.GC()
if ss != s {
t.Errorf("want %s, got %s", s, ss)
}
}
for i := 0; i < 1000; i++ {
b := toK8sBytes(s)
runtime.GC()
if b[11] != 'd' {
t.Errorf("want %c, got %c", 'd', b[11])
}
ss := toK8sString(bts)
runtime.GC()
if ss != s {
t.Errorf("want %s, got %s", s, ss)
}
}
for i := 0; i < 1000; i++ {
b := toRawBytes(s)
runtime.GC()
if b[11] != 'd' {
t.Errorf("want %c, got %c", 'd', b[11])
}
ss := toRawString(bts)
runtime.GC()
if ss != s {
t.Errorf("want %s, got %s", s, ss)
}
}
}
func Test_toK8sBytes(t *testing.T) {
a := *(*[3]int64)(unsafe.Pointer(&s))
fmt.Printf("%d, %d, %d\n", a[0], a[1], a[2])
b := *(*[]byte)(unsafe.Pointer(&s))
fmt.Printf("%d, %d, %d\n", unsafe.SliceData(b), len(b), cap(b))
b = append(b, '!')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment