Description
Go version
go version go1.24.1 linux/amd64
What did you do?
Compile the ast
package of the Go-based TypeScript compiler (https://github.com/microsoft/typescript-go).
$ git clone https://github.com/microsoft/typescript-go && cd typescript-go
$ go1.24.1 build -a -v -gcflags='-bench=base.bench' github.com/microsoft/typescript-go/internal/ast
What did you see happen?
If the changes in #72815 land, it looks like the large typescript-go/internal/ast
package then becomes the long pole for the overall typescript-go compilation.
There might be some opportunities within cmd/compile or cmd/go to speed it up. There might also be some workarounds that could be used today, which might in turn hint towards possible changes within the Go toolchain.
To get some starting data points, I tried compiling the typescript-go ast
package with Go 1.24.1 to see what might speed it up:
compile time max RSS
baseline: 8.812 sec 1,499 MiB # Go 1.24.1
add -c=16: 6.651 sec 1,582 MiB # -gcflags='-c=16'
add disable-gc: 6.255 sec 3,834 MiB # GOGC=off, -gcflags='-c=16'
add disable-inline: 4.312 sec 2,747 MiB # GOGC=off, -gcflags='-c=16 -l'
add disable-other-opt: 3.808 sec 2,441 MiB # GOGC=off, -gcflags='-c=16 -l -N'
(The adjustments here are cumulative. The reported seconds are just for compiling the ast
package itself, and were measured via -gcflags='-bench=<file>.txt'
and then summarized with benchstat. Peak RSS was measured via time
).
Possible changes to the Go toolchain might include:
-
Perhaps the default cmd/compile concurrency (
-gcflags=-c=N
) could be increased by default or increased via some heuristic or threshold, such as perhaps a trivial threshold like number of input bytes in a package or function count or ____. (I think I recall older comments maybe by Josh saying that as HW evolves it might make sense to adjust the default of 4 upwards. Some related discussion in cmd/go,cmd/compile: let cmd/compile choose how much concurrency to use #48497). -
Perhaps cmd/compile could be more aggressive about adjusting
GOGC
. (Probably part of the reason it didn't help too much to disable the GC here is that the compiler is already somewhat aggressive about this. See for example https://go.dev/cl/436235 by David Chase, which introduces a fairly aggressive adjustment toGOGC
, but perhaps that could be revisited for some modest benefit). -
Perhaps other changes based on examining the current performance.
In terms of workarounds, some of the above flags might be useful today for the TypeScript team (for example, perhaps something like -gcflags='-c=16'
is useful now if the TypeScript team is not already adjusting that).
Others, such as disabling inlining, might waste total wall clock time if for example the immediate next step is to then kick off multiple minutes of regression tests, but some chance it could make sense in other cases if for example the next step is to instead run, say, ~500ms of tests via go test -short
or similar. (Separately, maybe someone will find it interesting to look at cmd/compile performance with and without inlining enabled for this package -- maybe the resulting performance delta is "expected", or maybe it shows something more interesting).
What did you expect to see?
Ideally, it would be faster.
Additional Details
Here is a high-level breakdown of wall clock time spent overall (as reported by -gcflags=-bench=<file>.txt
) comparing the starting point vs. the final experiment above (and then below that are individual results for each step).
commit: go1.24.1
goos: linux
goarch: amd64
│ 1-base.bench │ 5-add-disable-opt.bench │
│ sec/op │ sec/op vs base │
Compile:fe:init 931.6µ ± 13% 917.3µ ± 16% ~ (p=0.394 n=6)
Compile:fe:loadsys 126.8µ ± 8% 123.6µ ± 5% ~ (p=0.065 n=6)
Compile:fe:parse 1.601 ± 1% 1.390 ± 1% -13.18% (p=0.002 n=6)
Compile:fe:pgo-load-profile 910.0n ± 33% 1005.5n ± 14% ~ (p=0.331 n=6)
Compile:fe:devirtualize-and-inline 1580.2m ± 1% 425.3m ± 2% -73.09% (p=0.002 n=6)
Compile:fe:escapes 291.0m ± 6% 119.4m ± 4% -58.96% (p=0.002 n=6)
Compile:fe:subtotal 3.486 ± 1% 1.935 ± 1% -44.50% (p=0.002 n=6)
Compile:be:compilefuncs 4002.8m ± 1% 897.5m ± 4% -77.58% (p=0.002 n=6)
Compile:be:dumpobj 1316.8m ± 4% 974.2m ± 2% -26.02% (p=0.002 n=6)
Compile:be:subtotal 5.326 ± 1% 1.874 ± 2% -64.81% (p=0.002 n=6)
Compile:total 8.812 ± 1% 3.808 ± 1% -56.79% (p=0.002 n=6)
$ benchstat 1-base.bench 2-add-c16.bench
commit: go1.24.1 goos: linux goarch: amd64 │ 1-base.bench │ 2-add-c16.bench │ │ sec/op │ sec/op vs base │ Compile:fe:init 931.6µ ± 13% 890.7µ ± 11% ~ (p=0.394 n=6) Compile:fe:loadsys 126.8µ ± 8% 126.9µ ± 5% ~ (p=0.513 n=6) Compile:fe:parse 1.601 ± 1% 1.572 ± 1% -1.83% (p=0.002 n=6) Compile:fe:pgo-load-profile 910.0n ± 33% 815.5n ± 26% ~ (p=0.132 n=6) Compile:fe:devirtualize-and-inline 1.580 ± 1% 1.569 ± 1% -0.71% (p=0.026 n=6) Compile:fe:escapes 291.0m ± 6% 285.8m ± 2% ~ (p=0.240 n=6) Compile:fe:subtotal 3.486 ± 1% 3.430 ± 0% -1.61% (p=0.002 n=6) Compile:be:compilefuncs 4.003 ± 1% 1.867 ± 1% -53.36% (p=0.002 n=6) Compile:be:dumpobj 1.317 ± 4% 1.346 ± 3% ~ (p=0.818 n=6) Compile:be:subtotal 5.326 ± 1% 3.218 ± 2% -39.58% (p=0.002 n=6) Compile:total 8.812 ± 1% 6.651 ± 1% -24.53% (p=0.002 n=6)
$ benchstat 2-add-c16.bench 3-add-disable-gc.bench
commit: go1.24.1 goos: linux goarch: amd64 │ 2-add-c16.bench │ 3-add-disable-gc.bench │ │ sec/op │ sec/op vs base │ Compile:fe:init 890.7µ ± 11% 918.5µ ± 6% ~ (p=0.394 n=6) Compile:fe:loadsys 126.9µ ± 5% 123.7µ ± 7% ~ (p=0.699 n=6) Compile:fe:parse 1.572 ± 1% 1.402 ± 1% -10.85% (p=0.002 n=6) Compile:fe:pgo-load-profile 815.5n ± 26% 900.0n ± 11% ~ (p=0.193 n=6) Compile:fe:devirtualize-and-inline 1.569 ± 1% 1.376 ± 1% -12.30% (p=0.002 n=6) Compile:fe:escapes 285.8m ± 2% 249.8m ± 2% -12.57% (p=0.002 n=6) Compile:fe:subtotal 3.430 ± 0% 3.020 ± 1% -11.93% (p=0.002 n=6) Compile:be:compilefuncs 1.867 ± 1% 1.950 ± 2% +4.46% (p=0.002 n=6) Compile:be:dumpobj 1.346 ± 3% 1.273 ± 2% -5.41% (p=0.002 n=6) Compile:be:subtotal 3.218 ± 2% 3.222 ± 1% ~ (p=0.310 n=6) Compile:total 6.651 ± 1% 6.255 ± 1% -5.95% (p=0.002 n=6)
$ benchstat 3-add-disable-gc.bench 4-add-disable-inline.bench
commit: go1.24.1 goos: linux goarch: amd64 │ 3-add-disable-gc.bench │ 4-add-disable-inline.bench │ │ sec/op │ sec/op vs base │ Compile:fe:init 918.5µ ± 6% 914.2µ ± 22% ~ (p=1.000 n=6) Compile:fe:loadsys 123.7µ ± 7% 126.1µ ± 113% ~ (p=0.394 n=6) Compile:fe:parse 1.402 ± 1% 1.390 ± 1% ~ (p=0.394 n=6) Compile:fe:pgo-load-profile 900.0n ± 11% 990.0n ± 14% ~ (p=0.221 n=6) Compile:fe:devirtualize-and-inline 1376.1m ± 1% 459.9m ± 1% -66.58% (p=0.002 n=6) Compile:fe:escapes 249.8m ± 2% 117.6m ± 3% -52.92% (p=0.002 n=6) Compile:fe:subtotal 3.020 ± 1% 1.971 ± 0% -34.75% (p=0.002 n=6) Compile:be:compilefuncs 1.950 ± 2% 1.206 ± 3% -38.19% (p=0.002 n=6) Compile:be:dumpobj 1.273 ± 2% 1.129 ± 1% -11.30% (p=0.002 n=6) Compile:be:subtotal 3.222 ± 1% 2.337 ± 1% -27.48% (p=0.002 n=6) Compile:total 6.255 ± 1% 4.312 ± 1% -31.07% (p=0.002 n=6)
$ benchstat 4-add-disable-inline.bench 5-add-disable-opt.bench
commit: go1.24.1 goos: linux goarch: amd64 │ 4-add-disable-inline.bench │ 5-add-disable-opt.bench │ │ sec/op │ sec/op vs base │ Compile:fe:init 914.2µ ± 22% 917.3µ ± 16% ~ (p=0.818 n=6) Compile:fe:loadsys 126.1µ ± 113% 123.6µ ± 5% ~ (p=0.310 n=6) Compile:fe:parse 1.390 ± 1% 1.390 ± 1% ~ (p=0.937 n=6) Compile:fe:pgo-load-profile 990.0n ± 14% 1005.5n ± 14% ~ (p=0.686 n=6) Compile:fe:devirtualize-and-inline 459.9m ± 1% 425.3m ± 2% -7.53% (p=0.002 n=6) Compile:fe:escapes 117.6m ± 3% 119.4m ± 4% ~ (p=0.818 n=6) Compile:fe:subtotal 1.971 ± 0% 1.935 ± 1% -1.83% (p=0.002 n=6) Compile:be:compilefuncs 1205.6m ± 3% 897.5m ± 4% -25.55% (p=0.002 n=6) Compile:be:dumpobj 1129.1m ± 1% 974.2m ± 2% -13.72% (p=0.002 n=6) Compile:be:subtotal 2.337 ± 1% 1.874 ± 2% -19.79% (p=0.002 n=6) Compile:total 4.312 ± 1% 3.808 ± 1% -11.69% (p=0.002 n=6)
Metadata
Metadata
Labels
Type
Projects
Status