]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj: reduce allocations in object file writing
authorCherry Mui <cherryyz@google.com>
Thu, 10 Nov 2022 21:10:32 +0000 (16:10 -0500)
committerCherry Mui <cherryyz@google.com>
Thu, 10 Nov 2022 22:41:06 +0000 (22:41 +0000)
Some object file writer functions are structured like, having a
local variable, setting fields, then passing it to a Write method
which eventually calls io.Writer.Write. As the Write call is an
interface call it escapes the parameter, which in turn causes the
local variable to be heap allocated. To reduce allocation, use
pre-allocated scratch space instead.

Reduce number of allocations in the compiler:
name        old allocs/op     new allocs/op     delta
Template           679k ± 0%         644k ± 0%  -5.17%  (p=0.000 n=20+20)
Unicode            603k ± 0%         581k ± 0%  -3.67%  (p=0.000 n=20+20)
GoTypes           3.83M ± 0%        3.63M ± 0%  -5.30%  (p=0.000 n=20+20)
Compiler           353k ± 0%         342k ± 0%  -3.09%  (p=0.000 n=18+19)
SSA               31.4M ± 0%        30.4M ± 0%  -3.02%  (p=0.000 n=20+20)
Flate              397k ± 0%         373k ± 0%  -5.92%  (p=0.000 n=20+18)
GoParser           777k ± 0%         735k ± 0%  -5.37%  (p=0.000 n=20+20)
Reflect           2.07M ± 0%        1.90M ± 0%  -7.89%  (p=0.000 n=18+20)
Tar                605k ± 0%         568k ± 0%  -6.26%  (p=0.000 n=19+16)
XML                801k ± 0%         766k ± 0%  -4.36%  (p=0.000 n=20+20)
[Geo mean]        1.18M             1.12M       -5.02%

Change-Id: I9d02a72e459e645527196ac54b6ee643a5ea6bd3
Reviewed-on: https://go-review.googlesource.com/c/go/+/449637
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>

src/cmd/internal/goobj/objfile.go
src/cmd/internal/obj/objfile.go

index 4276df3d19b82c485a2e16a81cb162f6fdba90c0..ae215dfef5e996a5df3217aab3d5ce4952c2e9f5 100644 (file)
@@ -527,6 +527,8 @@ type Writer struct {
        wr        *bio.Writer
        stringMap map[string]uint32
        off       uint32 // running offset
+
+       b [8]byte // scratch space for writing bytes
 }
 
 func NewWriter(wr *bio.Writer) *Writer {
@@ -565,23 +567,20 @@ func (w *Writer) Bytes(s []byte) {
 }
 
 func (w *Writer) Uint64(x uint64) {
-       var b [8]byte
-       binary.LittleEndian.PutUint64(b[:], x)
-       w.wr.Write(b[:])
+       binary.LittleEndian.PutUint64(w.b[:], x)
+       w.wr.Write(w.b[:])
        w.off += 8
 }
 
 func (w *Writer) Uint32(x uint32) {
-       var b [4]byte
-       binary.LittleEndian.PutUint32(b[:], x)
-       w.wr.Write(b[:])
+       binary.LittleEndian.PutUint32(w.b[:4], x)
+       w.wr.Write(w.b[:4])
        w.off += 4
 }
 
 func (w *Writer) Uint16(x uint16) {
-       var b [2]byte
-       binary.LittleEndian.PutUint16(b[:], x)
-       w.wr.Write(b[:])
+       binary.LittleEndian.PutUint16(w.b[:2], x)
+       w.wr.Write(w.b[:2])
        w.off += 2
 }
 
index d75708a3901a5f2ccbf27a13fc7c09cd958526a6..ff0968ecf4c2c061822da925b00a68792eaaa346 100644 (file)
@@ -220,6 +220,16 @@ type writer struct {
        ctxt    *Link
        pkgpath string   // the package import path (escaped), "" if unknown
        pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
+
+       // scratch space for writing (the Write methods escape
+       // as they are interface calls)
+       tmpSym      goobj.Sym
+       tmpReloc    goobj.Reloc
+       tmpAux      goobj.Aux
+       tmpHash64   goobj.Hash64Type
+       tmpHash     goobj.HashType
+       tmpRefFlags goobj.RefFlags
+       tmpRefName  goobj.RefName
 }
 
 // prepare package index list
@@ -379,7 +389,7 @@ func (w *writer) Sym(s *LSym) {
        if s.Size > cutoff {
                w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
        }
-       var o goobj.Sym
+       o := &w.tmpSym
        o.SetName(name, w.Writer)
        o.SetABI(abi)
        o.SetType(uint8(s.Type))
@@ -394,16 +404,16 @@ func (w *writer) Hash64(s *LSym) {
        if !s.ContentAddressable() || len(s.R) != 0 {
                panic("Hash of non-content-addressable symbol")
        }
-       b := contentHash64(s)
-       w.Bytes(b[:])
+       w.tmpHash64 = contentHash64(s)
+       w.Bytes(w.tmpHash64[:])
 }
 
 func (w *writer) Hash(s *LSym) {
        if !s.ContentAddressable() {
                panic("Hash of non-content-addressable symbol")
        }
-       b := w.contentHash(s)
-       w.Bytes(b[:])
+       w.tmpHash = w.contentHash(s)
+       w.Bytes(w.tmpHash[:])
 }
 
 // contentHashSection returns a mnemonic for s's section.
@@ -538,7 +548,7 @@ func makeSymRef(s *LSym) goobj.SymRef {
 }
 
 func (w *writer) Reloc(r *Reloc) {
-       var o goobj.Reloc
+       o := &w.tmpReloc
        o.SetOff(r.Off)
        o.SetSiz(r.Siz)
        o.SetType(uint16(r.Type))
@@ -548,7 +558,7 @@ func (w *writer) Reloc(r *Reloc) {
 }
 
 func (w *writer) aux1(typ uint8, rs *LSym) {
-       var o goobj.Aux
+       o := &w.tmpAux
        o.SetType(typ)
        o.SetSym(makeSymRef(rs))
        o.Write(w.Writer)
@@ -618,7 +628,7 @@ func (w *writer) refFlags() {
                if flag2 == 0 {
                        return // no need to write zero flags
                }
-               var o goobj.RefFlags
+               o := &w.tmpRefFlags
                o.SetSym(symref)
                o.SetFlag2(flag2)
                o.Write(w.Writer)
@@ -644,7 +654,7 @@ func (w *writer) refNames() {
                }
                seen[rs] = true
                symref := makeSymRef(rs)
-               var o goobj.RefName
+               o := &w.tmpRefName
                o.SetSym(symref)
                o.SetName(rs.Name, w.Writer)
                o.Write(w.Writer)