From: Daniel Martí Date: Thu, 12 Jan 2023 18:29:28 +0000 (+0000) Subject: go/printer: reuse go/token.FileSet.PositionFor calls in setPos X-Git-Tag: go1.21rc1~963 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=e21d126ee13031e0fb621e4ec66ae1be403e2d36;p=gostls13.git go/printer: reuse go/token.FileSet.PositionFor calls in setPos setPos is called for most nodes, and in a number of cases, the position is already the same. PositionFor is a relatively expensive call, as it needs to "unpack" a token.Pos into a token.Position. If we can tell that the position is the same in a cheap way, we can then avoid calling setPos and PositionFor. Luckily, we can get the position's offset within the file, and it doesn't involve the relatively expensive unpacking. name old time/op new time/op delta PrintFile-16 4.79ms ± 1% 4.36ms ± 1% -8.88% (p=0.008 n=5+5) name old speed new speed delta PrintFile-16 10.8MB/s ± 1% 11.9MB/s ± 1% +9.73% (p=0.008 n=5+5) name old alloc/op new alloc/op delta PrintFile-16 106kB ± 1% 106kB ± 1% ~ (p=0.167 n=5+5) name old allocs/op new allocs/op delta PrintFile-16 2.42k ± 0% 2.42k ± 0% ~ (all equal) This does assume that the positions of a node being printed are all within a file, as go/token.Position.Offset is relative to each file. This seems like a perfectly fine assumption to make right now, as the largest node which can be printed is an *ast.File. Change-Id: I2ae55f507ba8ba9f280898c9c8e01c994d9b2a26 Reviewed-on: https://go-review.googlesource.com/c/go/+/461739 Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Gopher Robot Reviewed-by: David Chase --- diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go index 741e3f782c..c90791556e 100644 --- a/src/go/printer/printer.go +++ b/src/go/printer/printer.go @@ -878,8 +878,12 @@ func mayCombine(prev token.Token, next byte) (b bool) { } func (p *printer) setPos(pos token.Pos) { + // If p.pos is already equivalent to pos, + // we can avoid calling posFor again. if pos.IsValid() { - p.pos = p.posFor(pos) // accurate position of next item + if file := p.fset.File(pos); file != nil && file.Offset(pos) != p.pos.Offset { + p.pos = p.posFor(pos) // accurate position of next item + } } }