Created
February 21, 2025 02:29
-
-
Save smallnest/88efe8b969a93ed695f9c1fe1869e2f8 to your computer and use it in GitHub Desktop.
go []byte <-> string benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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