From 5497300d9c9327005fa9ab14c6897d6c883139c5 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 10 Nov 2022 16:10:32 -0500 Subject: [PATCH] cmd/internal/obj: reduce allocations in object file writing MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: David Chase Run-TryBot: Cherry Mui --- src/cmd/internal/goobj/objfile.go | 17 ++++++++--------- src/cmd/internal/obj/objfile.go | 28 +++++++++++++++++++--------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/cmd/internal/goobj/objfile.go b/src/cmd/internal/goobj/objfile.go index 4276df3d19..ae215dfef5 100644 --- a/src/cmd/internal/goobj/objfile.go +++ b/src/cmd/internal/goobj/objfile.go @@ -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 } diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index d75708a390..ff0968ecf4 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -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) -- 2.50.0