From 36d5650a1c60be5e09abc89774758f525afc7874 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Mon, 21 Mar 2016 10:55:20 +1300 Subject: [PATCH] cmd/internal/obj, cmd/link: put all symbol data in one contiguous section MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Another object file change, gives a reasonable improvement: name old s/op new s/op delta LinkCmdGo 0.46 ± 3% 0.44 ± 9% -3.34% (p=0.000 n=98+82) LinkJuju 4.09 ± 4% 3.92 ± 5% -4.30% (p=0.000 n=98+99) I guess the data section could be mmap-ed instead of read, I haven't tried that. Change-Id: I959eee470a05526ab1579e3f5d3ede41c16c954f Reviewed-on: https://go-review.googlesource.com/20928 Run-TryBot: Michael Hudson-Doyle TryBot-Result: Gobot Gobot Reviewed-by: David Crawshaw --- src/cmd/internal/goobj/read.go | 27 +++++++++------- src/cmd/internal/obj/objfile.go | 49 ++++++++++++++++++++--------- src/cmd/link/internal/ld/objfile.go | 42 ++++++++++--------------- 3 files changed, 67 insertions(+), 51 deletions(-) diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go index a693725e9a..6a906a4627 100644 --- a/src/cmd/internal/goobj/read.go +++ b/src/cmd/internal/goobj/read.go @@ -236,15 +236,16 @@ var ( // An objReader is an object file reader. type objReader struct { - p *Package - b *bufio.Reader - f io.ReadSeeker - err error - offset int64 - limit int64 - tmp [256]byte - pkg string - pkgprefix string + p *Package + b *bufio.Reader + f io.ReadSeeker + err error + offset int64 + dataOffset int64 + limit int64 + tmp [256]byte + pkg string + pkgprefix string } // importPathToPrefix returns the prefix that will be used in the @@ -416,8 +417,8 @@ func (r *objReader) readRef() { // readData reads a data reference from the input file. func (r *objReader) readData() Data { n := r.readInt() - d := Data{Offset: r.offset, Size: int64(n)} - r.skip(int64(n)) + d := Data{Offset: r.dataOffset, Size: int64(n)} + r.dataOffset += int64(n) return d } @@ -610,6 +611,10 @@ func (r *objReader) parseObject(prefix []byte) error { r.readRef() } + dataLength := r.readInt() + r.dataOffset = r.offset + r.skip(int64(dataLength)) + // Symbols. for { if b := r.readByte(); b != 0xfe { diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 43b4be1b9f..42ae86d62d 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -19,8 +19,10 @@ // - byte 1 - version number // - sequence of strings giving dependencies (imported packages) // - empty string (marks end of sequence) -// - sequence of sybol references used by the defined symbols +// - sequence of symbol references used by the defined symbols // - byte 0xff (marks end of sequence) +// - integer (length of following data) +// - data, the content of the defined symbols // - sequence of defined symbols // - byte 0xff (marks end of sequence) // - magic footer: "\xff\xffgo13ld" @@ -96,9 +98,6 @@ // // TODO(rsc): The file format is good for a first pass but needs work. // - There are SymID in the object file that should really just be strings. -// - The actual symbol memory images are interlaced with the symbol -// metadata. They should be separated, to reduce the I/O required to -// load just the metadata. package obj @@ -319,15 +318,42 @@ func Writeobjfile(ctxt *Link, b *Biobuf) { } wrstring(b, "") + var dataLength int64 // Emit symbol references. for _, s := range ctxt.Text { writerefs(ctxt, b, s) + dataLength += int64(len(s.P)) + + pc := s.Pcln + dataLength += int64(len(pc.Pcsp.P)) + dataLength += int64(len(pc.Pcfile.P)) + dataLength += int64(len(pc.Pcline.P)) + for i := 0; i < len(pc.Pcdata); i++ { + dataLength += int64(len(pc.Pcdata[i].P)) + } } for _, s := range ctxt.Data { writerefs(ctxt, b, s) + dataLength += int64(len(s.P)) } Bputc(b, 0xff) + // Write data block + wrint(b, dataLength) + for _, s := range ctxt.Text { + b.w.Write(s.P) + pc := s.Pcln + b.w.Write(pc.Pcsp.P) + b.w.Write(pc.Pcfile.P) + b.w.Write(pc.Pcline.P) + for i := 0; i < len(pc.Pcdata); i++ { + b.w.Write(pc.Pcdata[i].P) + } + } + for _, s := range ctxt.Data { + b.w.Write(s.P) + } + // Emit symbols. for _, s := range ctxt.Text { writesym(ctxt, b, s) @@ -480,7 +506,7 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) { wrint(b, flags) wrint(b, s.Size) wrsym(b, s.Gotype) - wrdata(b, s.P) + wrint(b, int64(len(s.P))) wrint(b, int64(len(s.R))) var r *Reloc @@ -521,12 +547,12 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) { } pc := s.Pcln - wrdata(b, pc.Pcsp.P) - wrdata(b, pc.Pcfile.P) - wrdata(b, pc.Pcline.P) + wrint(b, int64(len(pc.Pcsp.P))) + wrint(b, int64(len(pc.Pcfile.P))) + wrint(b, int64(len(pc.Pcline.P))) wrint(b, int64(len(pc.Pcdata))) for i := 0; i < len(pc.Pcdata); i++ { - wrdata(b, pc.Pcdata[i].P) + wrint(b, int64(len(pc.Pcdata[i].P))) } wrint(b, int64(len(pc.Funcdataoff))) for i := 0; i < len(pc.Funcdataoff); i++ { @@ -564,11 +590,6 @@ func wrstring(b *Biobuf, s string) { b.w.WriteString(s) } -func wrdata(b *Biobuf, v []byte) { - wrint(b, int64(len(v))) - b.Write(v) -} - func wrsym(b *Biobuf, s *LSym) { if s == nil { wrint(b, 0) diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index b842fe15d0..130347e7fd 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -23,6 +23,8 @@ package ld // - empty string (marks end of sequence) // - sequence of sybol references used by the defined symbols // - byte 0xff (marks end of sequence) +// - integer (length of following data) +// - data, the content of the defined symbols // - sequence of defined symbols // - byte 0xff (marks end of sequence) // - magic footer: "\xff\xffgo13ld" @@ -98,9 +100,6 @@ package ld // // TODO(rsc): The file format is good for a first pass but needs work. // - There are SymID in the object file that should really just be strings. -// - The actual symbol memory images are interlaced with the symbol -// metadata. They should be separated, to reduce the I/O required to -// load just the metadata. import ( "bytes" @@ -151,6 +150,10 @@ func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) { readref(ctxt, f, pkg, pn) } + dataLength := rdint64(f) + data := make([]byte, dataLength) + obj.Bread(f, data) + for { c, err := f.Peek(1) if err != nil { @@ -159,7 +162,7 @@ func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) { if c[0] == 0xff { break } - readsym(ctxt, f, pkg, pn) + readsym(ctxt, f, &data, pkg, pn) } buf = [8]uint8{} @@ -173,7 +176,7 @@ func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) { } } -func readsym(ctxt *Link, f *obj.Biobuf, pkg string, pn string) { +func readsym(ctxt *Link, f *obj.Biobuf, buf *[]byte, pkg string, pn string) { if obj.Bgetc(f) != 0xfe { log.Fatalf("readsym out of sync") } @@ -184,7 +187,7 @@ func readsym(ctxt *Link, f *obj.Biobuf, pkg string, pn string) { local := flags&2 != 0 size := rdint(f) typ := rdsym(ctxt, f, pkg) - data := rddata(f) + data := rddata(f, buf) nreloc := rdint(f) var dup *LSym @@ -283,14 +286,14 @@ overwrite: s.Pcln = new(Pcln) pc := s.Pcln - pc.Pcsp.P = rddata(f) - pc.Pcfile.P = rddata(f) - pc.Pcline.P = rddata(f) + pc.Pcsp.P = rddata(f, buf) + pc.Pcfile.P = rddata(f, buf) + pc.Pcline.P = rddata(f, buf) n = rdint(f) pc.Pcdata = make([]Pcdata, n) pc.Npcdata = n for i := 0; i < n; i++ { - pc.Pcdata[i].P = rddata(f) + pc.Pcdata[i].P = rddata(f, buf) } n = rdint(f) pc.Funcdata = make([]*LSym, n) @@ -482,23 +485,10 @@ func rdstring(f *obj.Biobuf) string { return string(rdBuf[:n]) } -const rddataBufMax = 1 << 14 - -var rddataBuf = make([]byte, rddataBufMax) - -func rddata(f *obj.Biobuf) []byte { - var p []byte +func rddata(f *obj.Biobuf, buf *[]byte) []byte { n := rdint(f) - if n > rddataBufMax { - p = make([]byte, n) - } else { - if len(rddataBuf) < n { - rddataBuf = make([]byte, rddataBufMax) - } - p = rddataBuf[:n:n] - rddataBuf = rddataBuf[n:] - } - obj.Bread(f, p) + p := (*buf)[:n:n] + *buf = (*buf)[n:] return p } -- 2.48.1