Skip to content

Commit

Permalink
feat: optimize make bytes to reduce memclr cost (#209)
Browse files Browse the repository at this point in the history
  • Loading branch information
jayantxie authored May 7, 2024
1 parent fefc805 commit 197ded9
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 2 deletions.
43 changes: 43 additions & 0 deletions lang/dirtmake/bytes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2024 ByteDance Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dirtmake

import (
"unsafe"
)

type slice struct {
data unsafe.Pointer
len int
cap int
}

//go:linkname mallocgc runtime.mallocgc
func mallocgc(size uintptr, typ unsafe.Pointer, needzero bool) unsafe.Pointer

// Bytes allocates a byte slice but does not clean up the memory it references.
// Throw a fatal error instead of panic if cap is greater than runtime.maxAlloc.
// NOTE: MUST set any byte element before it's read.
func Bytes(len, cap int) (b []byte) {
if len < 0 || len > cap {
panic("dirtmake.Bytes: len out of range")
}
p := mallocgc(uintptr(cap), nil, false)
sh := (*slice)(unsafe.Pointer(&b))
sh.data = p
sh.len = len
sh.cap = cap
return
}
61 changes: 61 additions & 0 deletions lang/dirtmake/bytes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2024 ByteDance Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dirtmake

import (
"bytes"
"fmt"
"testing"
)

var data []byte

const block1kb = 1024

func BenchmarkParallelDirtBytes(b *testing.B) {
src := make([]byte, block1kb)
for i := range src {
src[i] = byte(i)
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
bs := Bytes(block1kb, block1kb)
copy(bs, src)
if !bytes.Equal(bs, src) {
b.Fatalf("bytes not equal")
}
}
})
}

func BenchmarkDirtBytes(b *testing.B) {
for size := block1kb; size < block1kb*20; size += block1kb * 2 {
b.Run(fmt.Sprintf("size=%dkb", size/block1kb), func(b *testing.B) {
for i := 0; i < b.N; i++ {
data = Bytes(size, size)
}
})
}
}

func BenchmarkOriginBytes(b *testing.B) {
for size := block1kb; size < block1kb*20; size += block1kb * 2 {
b.Run(fmt.Sprintf("size=%dkb", size/block1kb), func(b *testing.B) {
for i := 0; i < b.N; i++ {
data = make([]byte, size)
}
})
}
}
4 changes: 3 additions & 1 deletion lang/mcache/mcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package mcache

import (
"sync"

"github.com/bytedance/gopkg/lang/dirtmake"
)

const maxSize = 46
Expand All @@ -27,7 +29,7 @@ func init() {
for i := 0; i < maxSize; i++ {
size := 1 << i
caches[i].New = func() interface{} {
buf := make([]byte, 0, size)
buf := dirtmake.Bytes(0, size)
return buf
}
}
Expand Down
3 changes: 2 additions & 1 deletion lang/stringx/stringx.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"unicode/utf8"

"github.com/bytedance/gopkg/internal/hack"
"github.com/bytedance/gopkg/lang/dirtmake"
"github.com/bytedance/gopkg/lang/fastrand"
)

Expand Down Expand Up @@ -246,7 +247,7 @@ func Reverse(s string) (string, error) {
return s, nil
}
src := hack.StringToBytes(s)
dst := make([]byte, len(s))
dst := dirtmake.Bytes(len(s), len(s))
srcIndex := len(s)
dstIndex := 0
for srcIndex > 0 {
Expand Down

0 comments on commit 197ded9

Please sign in to comment.