Skip to content

Commit

Permalink
perf: nocopy read for ReadString and ReadBinary API if possible (#315)
Browse files Browse the repository at this point in the history
  • Loading branch information
joway authored Apr 23, 2024
1 parent bb9c3f7 commit 05a1094
Show file tree
Hide file tree
Showing 5 changed files with 424 additions and 887 deletions.
62 changes: 54 additions & 8 deletions nocopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ package netpoll

import (
"io"
"reflect"
"unsafe"

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

// Reader is a collection of operations for nocopy reads.
Expand Down Expand Up @@ -108,9 +112,9 @@ type Reader interface {
// The usage of the design is a two-step operation, first apply for a section of memory,
// fill it and then submit. E.g:
//
// var buf, _ = Malloc(n)
// buf = append(buf[:0], ...)
// Flush()
// var buf, _ = Malloc(n)
// buf = append(buf[:0], ...)
// Flush()
//
// Note that it is not recommended to submit self-managed buffers to Writer.
// Since the writer is processed asynchronously, if the self-managed buffer is used and recycled after submission,
Expand Down Expand Up @@ -244,10 +248,52 @@ func NewIOReadWriter(rw ReadWriter) io.ReadWriter {
}

const (
block1k = 1 * 1024
block2k = 2 * 1024
block4k = 4 * 1024
block8k = 8 * 1024
block1k = 1 * 1024
block2k = 2 * 1024
block4k = 4 * 1024
block8k = 8 * 1024
block32k = 32 * 1024

pagesize = block8k
mallocMax = block8k * block1k // mallocMax is 8MB

minReuseBytes = 64 // only reuse bytes if n >= minReuseBytes

defaultLinkBufferMode = 0
// readonly mode indicate that the buffer node memory is not controlled by itself,
// so we cannot reuse the buffer or nocopy read it, default value is false.
readonlyMask uint8 = 1 << 0 // 0000 0001
// nocopyRead mode indicate that the buffer node has been no copy read and cannot reuse the buffer, default value is false.
nocopyReadMask uint8 = 1 << 1 // 0000 0010
)

const pagesize = block8k
// zero-copy slice convert to string
func unsafeSliceToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}

// zero-copy slice convert to string
func unsafeStringToSlice(s string) (b []byte) {
p := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&s)).Data)
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
hdr.Data = uintptr(p)
hdr.Cap = len(s)
hdr.Len = len(s)
return b
}

// malloc limits the cap of the buffer from mcache.
func malloc(size, capacity int) []byte {
if capacity > mallocMax {
return make([]byte, size, capacity)
}
return mcache.Malloc(size, capacity)
}

// free limits the cap of the buffer from mcache.
func free(buf []byte) {
if cap(buf) > mallocMax {
return
}
mcache.Free(buf)
}
Loading

0 comments on commit 05a1094

Please sign in to comment.