1
0
mirror of https://github.com/golang/go synced 2024-11-18 19:14:40 -07:00

[dev.link] cmd/link: fallocate space, and remove all msync calls

The fallocate calls will lower the chances of SIGBUS in the linker, but
it might still happen on other unsupported platforms and filesystems.

Darwin cmd/compile stats:

Munmap                    16.0ms ± 8%     0.8ms ± 3%   -95.19%  (p=0.000 n=8+10)
TotalTime                  484ms ± 2%     462ms ± 2%    -4.52%  (p=0.000 n=10+9)

Updates #37310

Change-Id: I41c6e490adec26fa1ebee49a5b268828f5ba05e1
Reviewed-on: https://go-review.googlesource.com/c/go/+/228385
Run-TryBot: Jeremy Faller <jeremy@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Jeremy Faller 2020-04-17 16:11:28 -04:00
parent 7d4c455a80
commit 8ab37b1baf
8 changed files with 73 additions and 30 deletions

View File

@ -13,6 +13,13 @@ import (
"os"
)
// If fallocate is not supported on this platform, return this error.
// Note this is the same error returned by filesystems that don't support
// fallocate, and that is intentional. The error is ignored where needed, and
// OutBuf writes to heap memory.
const fallocateNotSupportedErr = "operation not supported"
const outbufMode = 0775
// OutBuf is a buffered file writer.
//
// It is simlar to the Writer in cmd/internal/bio with a few small differences.
@ -70,7 +77,7 @@ func (out *OutBuf) Open(name string) error {
if out.f != nil {
return errors.New("cannot open more than one file")
}
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, outbufMode)
if err != nil {
return err
}

View File

@ -0,0 +1,26 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ld
import (
"syscall"
"unsafe"
)
func (out *OutBuf) fallocate(size uint64) error {
store := &syscall.Fstore_t{
Flags: syscall.F_ALLOCATEALL,
Posmode: syscall.F_PEOFPOSMODE,
Offset: 0,
Length: int64(size),
}
_, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
if err != 0 {
return err
}
return nil
}

View File

@ -0,0 +1,11 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ld
import "syscall"
func (out *OutBuf) fallocate(size uint64) error {
return syscall.Fallocate(int(out.f.Fd()), outbufMode, 0, int64(size))
}

View File

@ -8,11 +8,19 @@ package ld
import (
"syscall"
"unsafe"
)
func (out *OutBuf) Mmap(filesize uint64) error {
err := out.f.Truncate(int64(filesize))
err := out.fallocate(filesize)
if err != nil {
// Some file systems do not support fallocate. We ignore that error as linking
// can still take place, but you might SIGBUS when you write to the mmapped
// area.
if err.Error() != fallocateNotSupportedErr {
return err
}
}
err = out.f.Truncate(int64(filesize))
if err != nil {
Exitf("resize output file failed: %v", err)
}
@ -24,27 +32,10 @@ func (out *OutBuf) munmap() {
if out.buf == nil {
return
}
err := out.Msync()
if err != nil {
Exitf("msync output file failed: %v", err)
}
syscall.Munmap(out.buf)
out.buf = nil
_, err = out.f.Seek(out.off, 0)
_, err := out.f.Seek(out.off, 0)
if err != nil {
Exitf("seek output file failed: %v", err)
}
}
func (out *OutBuf) Msync() error {
if out.buf == nil {
return nil
}
// TODO: netbsd supports mmap and msync, but the syscall package doesn't define MSYNC.
// It is excluded from the build tag for now.
_, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&out.buf[0])), uintptr(len(out.buf)), syscall.MS_SYNC)
if errno != 0 {
return errno
}
return nil
}

View File

@ -0,0 +1,13 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !darwin,!linux
package ld
import "errors"
func (out *OutBuf) fallocate(size uint64) error {
return errors.New(fallocateNotSupportedErr)
}

View File

@ -13,4 +13,3 @@ func (out *OutBuf) Mmap(filesize uint64) error {
}
func (out *OutBuf) munmap() { panic("unreachable") }
func (out *OutBuf) Msync() error { panic("unreachable") }

View File

@ -33,6 +33,9 @@ func TestMMap(t *testing.T) {
if err := ob.Mmap(1 << 20); err != nil {
t.Errorf("error mmapping file %v", err)
}
if !ob.isMmapped() {
t.Errorf("should be mmapped")
}
}
// TestWriteLoc ensures that the math surrounding writeLoc is correct.

View File

@ -41,10 +41,3 @@ func (out *OutBuf) munmap() {
Exitf("UnmapViewOfFile failed: %v", err)
}
}
func (out *OutBuf) Msync() error {
if out.buf == nil {
return nil
}
return syscall.FlushViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])), 0)
}