Investigate missed deadcode elimination optimization
The linker's deadcode elimination may be partially disabled for variety of reasons, e.g. using MethodByName of the reflect package. It appears that Caddy pays this price due to the text/template package. The tool https://github.com/aarzilli/whydeadcode shows the call graph leading to a function that disables deadcode elimination.
It's not clear if avoiding those functions is possible in Caddy, but worth investigating and discussing. These are the ones I found in my attempts:
✗ $ go build -ldflags=-dumpdep . |& whydeadcode
text/template.(*state).evalField reachable from:
text/template.(*state).evalFieldChain
text/template.(*state).evalCommand
text/template.(*state).evalPipeline
text/template.(*state).walk
text/template.(*Template).execute
text/template.(*Template).Execute
github.com/caddyserver/caddy/v2/cmd.init.0.func1.(*Command).SetHelpTemplate.tmpl.2
github.com/caddyserver/caddy/v2/cmd.init.0.func1
github.com/caddyserver/caddy/v2/cmd.init.0.func1·f
github.com/caddyserver/caddy/v2/cmd.init.0
github.com/caddyserver/caddy/v2/cmd..inittask
go:main.inittasks
_
$ go build -ldflags=-dumpdep . |& whydeadcode
text/template.(*state).evalField reachable from:
text/template.(*state).evalFieldChain
text/template.(*state).evalCommand
text/template.(*state).evalPipeline
text/template.(*state).walk
text/template.(*Template).execute
text/template.(*Template).Execute
github.com/caddyserver/caddy/v2/cmd.init.0.func1.(*Command).SetVersionTemplate.tmpl.1
github.com/caddyserver/caddy/v2/cmd.init.0.func1
github.com/caddyserver/caddy/v2/cmd.init.0.func1·f
github.com/caddyserver/caddy/v2/cmd.init.0
github.com/caddyserver/caddy/v2/cmd..inittask
go:main.inittasks
_
$ go build -ldflags=-dumpdep . |& whydeadcode
text/template.(*state).evalField reachable from:
text/template.(*state).evalFieldChain
text/template.(*state).evalCommand
text/template.(*state).evalPipeline
text/template.(*state).walk
text/template.(*Template).execute
github.com/caddyserver/caddy/v2/modules/caddyhttp.buildHTTPServer
github.com/caddyserver/caddy/v2/modules/caddyhttp.cmdRespond
github.com/caddyserver/caddy/v2/modules/caddyhttp.cmdRespond·f
github.com/caddyserver/caddy/v2/modules/caddyhttp.init.9.func1
github.com/caddyserver/caddy/v2/modules/caddyhttp.init.9.func1·f
github.com/caddyserver/caddy/v2/modules/caddyhttp.init.9
github.com/caddyserver/caddy/v2/modules/caddyhttp..inittask
go:main.inittasks
_
I can't find the origin of this one, but it doesn't look easy to eliminate:
text/template.(*state).evalField reachable from:
text/template.(*state).evalFieldChain
text/template.(*state).evalCommand
text/template.(*state).evalPipeline
text/template.(*state).walk
text/template.(*Template).execute
html/template.(*Template).Execute
golang.org/x/net/trace.RenderEvents
golang.org/x/net/trace.Events
golang.org/x/net/trace.Events·f
golang.org/x/net/trace.init.0
golang.org/x/net/trace..inittask
go:main.inittasks
https://github.com/golang/go/issues/62024
but it doesn't look easy to eliminate
Sigh. Thanks for taking a shot! I see now there's discussion at golang/go#72895.
I randomly stumbled on this issue and I don't know much about your code so I can't guarantee it's the same thing, but I know google.golang.org/grpc (which appears in your go.mod) imports golang.org/x/net/trace which uses a template in their init function, thus disabling DCE.
google.golang.org/grpc provides a build tag grpcnotrace to remove the import https://github.com/grpc/grpc-go/pull/6954.
Also for the record there is ongoing work to remove this use of templates https://github.com/golang/go/issues/62024.
While I'm here thanks to https://github.com/spf13/cobra/pull/1956, github.com/spf13/cobra now doesn't disable DCE by default, so if you can remove the uses of SetHelpTemplate and SetVersionTemplate then you might be able to fix this 👍