1
0
mirror of https://github.com/golang/go synced 2024-11-26 17:16:54 -07: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:
Josh Bleecher Snyder 2020-11-06 17:37:03 -08:00
parent 194b636f8f
commit 526ee96f49
2 changed files with 26 additions and 1 deletions

View File

@ -44,11 +44,13 @@ import (
"errors"
"internal/poll"
"internal/testlog"
"internal/unsafeheader"
"io"
"io/fs"
"runtime"
"syscall"
"time"
"unsafe"
)
// 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
// a slice of bytes.
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

View File

@ -2773,3 +2773,21 @@ func TestReadFileProc(t *testing.T) {
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)
}
}