]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: fallocate space, and remove all msync calls
authorJeremy Faller <jeremy@golang.org>
Fri, 17 Apr 2020 20:11:28 +0000 (16:11 -0400)
committerJeremy Faller <jeremy@golang.org>
Mon, 20 Apr 2020 18:32:58 +0000 (18:32 +0000)
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>
src/cmd/link/internal/ld/outbuf.go
src/cmd/link/internal/ld/outbuf_darwin.go [new file with mode: 0644]
src/cmd/link/internal/ld/outbuf_linux.go [new file with mode: 0644]
src/cmd/link/internal/ld/outbuf_mmap.go
src/cmd/link/internal/ld/outbuf_nofallocate.go [new file with mode: 0644]
src/cmd/link/internal/ld/outbuf_nommap.go
src/cmd/link/internal/ld/outbuf_test.go
src/cmd/link/internal/ld/outbuf_windows.go

index f043168f1a2630275271cce8a2ace07b674b7681..b58dee368b29632fa91aaa2fec26678734c26fc7 100644 (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
        }
diff --git a/src/cmd/link/internal/ld/outbuf_darwin.go b/src/cmd/link/internal/ld/outbuf_darwin.go
new file mode 100644 (file)
index 0000000..299902e
--- /dev/null
@@ -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
+}
diff --git a/src/cmd/link/internal/ld/outbuf_linux.go b/src/cmd/link/internal/ld/outbuf_linux.go
new file mode 100644 (file)
index 0000000..93e621a
--- /dev/null
@@ -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))
+}
index a2493d7d16eea34a2b0868bafbca0c0aaca3368d..e6ee041abbc92a82553d4a71f2e4faf055c38df9 100644 (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
-}
diff --git a/src/cmd/link/internal/ld/outbuf_nofallocate.go b/src/cmd/link/internal/ld/outbuf_nofallocate.go
new file mode 100644 (file)
index 0000000..51b4fe7
--- /dev/null
@@ -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)
+}
index 472fca22d742c92f4cb0a59bac7e3a06726f3199..51218d8ae7be14bc149ef16f5fa5d7cb51a8daad 100644 (file)
@@ -12,5 +12,4 @@ func (out *OutBuf) Mmap(filesize uint64) error {
        return nil
 }
 
-func (out *OutBuf) munmap()      { panic("unreachable") }
-func (out *OutBuf) Msync() error { panic("unreachable") }
+func (out *OutBuf) munmap() { panic("unreachable") }
index 58f9b10cfa46485ba6305c12f9d30ad44fe7ba71..d8c21426b35d96aad8f76ac280ade77b9bc3569b 100644 (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.
index fc4fc5fb3bc01ae8db9ef15c91a9bc17d1bfa61a..a7140cce388964750c87892a9859053ad41115af 100644 (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)
-}