mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
os: avoid allocation in File.WriteString
Instead of alloc+copy to convert the string to a byte slice, do an unsafe conversion. Rely on the kernel not to scribble on the buffer during the write. Fixes #42406 Change-Id: I66f4838b43a11bcc3d67bbfa1706726318d55343 Reviewed-on: https://go-review.googlesource.com/c/go/+/268020 Trust: Josh Bleecher Snyder <josharian@gmail.com> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
This commit is contained in:
parent
194b636f8f
commit
526ee96f49
2 changed files with 26 additions and 1 deletions
|
|
@ -44,11 +44,13 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"internal/poll"
|
"internal/poll"
|
||||||
"internal/testlog"
|
"internal/testlog"
|
||||||
|
"internal/unsafeheader"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name returns the name of the file as presented to Open.
|
// Name returns the name of the file as presented to Open.
|
||||||
|
|
@ -246,7 +248,12 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
|
||||||
// WriteString is like Write, but writes the contents of string s rather than
|
// WriteString is like Write, but writes the contents of string s rather than
|
||||||
// a slice of bytes.
|
// a slice of bytes.
|
||||||
func (f *File) WriteString(s string) (n int, err error) {
|
func (f *File) WriteString(s string) (n int, err error) {
|
||||||
return f.Write([]byte(s))
|
var b []byte
|
||||||
|
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
|
||||||
|
hdr.Data = (*unsafeheader.String)(unsafe.Pointer(&s)).Data
|
||||||
|
hdr.Cap = len(s)
|
||||||
|
hdr.Len = len(s)
|
||||||
|
return f.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mkdir creates a new directory with the specified name and permission
|
// Mkdir creates a new directory with the specified name and permission
|
||||||
|
|
|
||||||
|
|
@ -2773,3 +2773,21 @@ func TestReadFileProc(t *testing.T) {
|
||||||
t.Fatalf("read %s: not newline-terminated: %q", name, data)
|
t.Fatalf("read %s: not newline-terminated: %q", name, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteStringAlloc(t *testing.T) {
|
||||||
|
if runtime.GOOS == "js" {
|
||||||
|
t.Skip("js allocates a lot during File.WriteString")
|
||||||
|
}
|
||||||
|
d := t.TempDir()
|
||||||
|
f, err := Create(filepath.Join(d, "whiteboard.txt"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
allocs := testing.AllocsPerRun(100, func() {
|
||||||
|
f.WriteString("I will not allocate when passed a string longer than 32 bytes.\n")
|
||||||
|
})
|
||||||
|
if allocs != 0 {
|
||||||
|
t.Errorf("expected 0 allocs for File.WriteString, got %v", allocs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue