-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Allow linker to perform deadcode elimination for program using Cobra #1956
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
The CLA thing isn't working for some reason. |
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
Thanks @aarzilli ! |
Unless I made a mistake there shouldn't be any behavior changes (as in, observable from the outside). Happy to explain anything about this if needed. |
Ping? |
1 similar comment
Ping? |
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
@aarzilli I apologize for such a long delay, but I had misunderstood the value of this PR. I now realize that it may help all programs using Cobra, so I'm very interested. I'm trying to convince myself that that this change actually has an impact. Here is what I tried.
I would have expected to see the Could you clarify what I should expect? This is the program:
|
One easy way to see the impact of this change is to compile your example program with and without this PR:
This is an extreme example, where the size of the executable is reduced by 38%, but reductions of 10% are realistic. As to your question, saying that deadcode elimination gets disabled is incorrect: in reality it continues to function but in a reduced capacity. Specifically if Your Unused function is not an exported method so, unless it is called by an exported method, it can always be deadcode eliminated. If you want to see the Unused function make it all the way to the executable you have to do something like this:
All of the noinline directives are needed because small functions like this would be removed by the inliner and the fmt.Println call is needed to make the Astruct type itself reachable (if all calls to the methods of Astruct are static the linker can still prove that Unused is unreachable). With these changes you get:
without the PR and:
with the PR. |
Thanks for the explanation @aarzilli, I can now see the benefits. So, with this PR, programs that don't set new templates (usage, help or version) will be able to do dead code elimination fully. What about programs that do modify those templates? If they want to get full usage of dead code elimination they should convert their template use to a go function like you have done, IIUC? My next step for this review is to try to override the help/usage/version in that fashion and see if it works as expected. I believe that using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great.
I still want to do some testing, but I don't expect any big surprises.
Here are some comments for the PR.
The PR also needs to be rebased.
Thanks again for your patience, I think we can get this in soon.
What do you think about updating the documentation in the three sections starting here https://github.com/spf13/cobra/blob/main/site/content/user_guide.md#defining-your-own-help to explain the side-effect of overriding the template, and therefore that it is recommended to set a function instead? |
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
Yes, this is correct.
It imagine should be trivial. |
This PR exceeds the recommended size of 200 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size. |
@aarzilli thank you for your patience. This took a very long time but you remained very responsive. Your nice attitude (and great technical expertise) made it possible to get this merged. This should benefit many programs! P.S. I wouldn't be against adding a section to the Cobra documentation teaching people what they should do to try to get dead-code-elimination working. Although this is more of a general Go concept, it might help people understand it if they have a small section in the Cobra docs. But I leave that up to you, if you still have energy after this looooong review. |
Nice to see immediate interest 😄 . |
Thanks for getting this merged! |
@jpmcb Could we get a cobra release soon to be able to enjoy this change ? |
Follow-up to spf13#1956. This commit allows a program to reset any of the tree templates to their default behaviour, as it was possible to do before the change of spf13#1956. Signed-off-by: Marc Khouzam <[email protected]>
Follow-up to #1956. This commit allows a program to reset any of the tree templates to their default behaviour, as it was possible to do before the change of #1956. Signed-off-by: Marc Khouzam <[email protected]>
Is there a chance to have |
This modules uses `github.com/expr-lang/expr` which, because of the extensive use of the `reflect` package, disables go's compiler dead code elimination which can lead to bigger binaries. This commit adds a `noexprlang` build tag that allows jsm.go users that do not use expression matching to entirely disable the use of the expr module so that they can benefit from go's dead code elimination if they are eligible to outside jsm.go. References: - https://golab.io/talks/getting-the-most-out-of-dead-code-elimination - https://github.com/aarzilli/whydeadcode - spf13/cobra#1956 Signed-off-by: Sylvain Rabot <[email protected]>
This modules uses `github.com/expr-lang/expr` which, because of the extensive use of the `reflect` package, disables go's compiler dead code elimination which can lead to bigger binaries. This commit adds a `noexprlang` build tag that allows jsm.go users that do not use expression matching to entirely disable the use of the expr module so that they can benefit from go's dead code elimination if they are eligible to outside jsm.go. References: - https://golab.io/talks/getting-the-most-out-of-dead-code-elimination - https://github.com/aarzilli/whydeadcode - spf13/cobra#1956 Signed-off-by: Sylvain Rabot <[email protected]>
This module uses `github.com/expr-lang/expr` which, because of the extensive use of the `reflect` package, disables go's compiler dead code elimination which can lead to bigger binaries. This commit adds a `noexprlang` build tag that allows jsm.go users that do not use expression matching to entirely disable the use of the expr module so that they can benefit from go's dead code elimination if they are eligible to outside jsm.go. References: - https://golab.io/talks/getting-the-most-out-of-dead-code-elimination - https://github.com/aarzilli/whydeadcode - spf13/cobra#1956 Signed-off-by: Sylvain Rabot <[email protected]>
🎉 https://github.com/spf13/cobra/releases/tag/v1.9.0 |
When reflect.MethodByName is used the linker can not fully perform deadcode elimination. This commit updates cobra and rewrites the suitableMethods part of service/rpccommon so that reflect.MethodByName is not used and the linker can fully execute deadcode elimination. The executable size on go1.24.0 on linux is reduced from 25468606 bytes to 22453382 bytes or a reduction of approximately 12%. See also: spf13/cobra#1956 https://github.com/aarzilli/whydeadcode
When reflect.MethodByName is used the linker can not fully perform deadcode elimination. This commit updates cobra and rewrites the suitableMethods part of service/rpccommon so that reflect.MethodByName is not used and the linker can fully execute deadcode elimination. The executable size on go1.24.0 on linux is reduced from 25468606 bytes to 22453382 bytes or a reduction of approximately 12%. See also: spf13/cobra#1956 https://github.com/aarzilli/whydeadcode
When templating is used, the linker cannot know which functions are called and which one are not; this is because tamplating use calls to "MethodByName()" which can be used to call any function (similar to reflection). With the release of Cobra 1.9.1, templates are no longer used by default in Cobra. By also not using templates in the tanzu-plugin-runtime it now gives an opportunity for plugins to try to avoid templates to allow dead-code elimination to work, if they so choose. Ref: spf13/cobra#1956 Signed-off-by: Marc Khouzam <[email protected]>
When templating is used, the linker cannot know which functions are called and which one are not; this is because templating use calls to "MethodByName()" which can be used to call any function (similar to reflection). With the release of Cobra 1.9.1, templates are no longer used by default in Cobra. By also not using templates in the tanzu-plugin-runtime it now gives an opportunity for plugins to try to avoid templates to allow dead-code elimination to work, if they so choose. Ref: spf13/cobra#1956 Signed-off-by: Marc Khouzam <[email protected]>
When templating is used, the linker cannot know which functions are called and which one are not; this is because templating use calls to "MethodByName()" which can be used to call any function (similar to reflection). With the release of Cobra 1.9.1, templates are no longer used by default in Cobra. By also not using templates in the tanzu-plugin-runtime it now gives an opportunity for plugins to try to avoid templates to allow dead-code elimination to work, if they so choose. Ref: spf13/cobra#1956 Signed-off-by: Marc Khouzam <[email protected]>
When templating is used, the linker cannot know which functions are called and which one are not; this is because templating use calls to "MethodByName()" which can be used to call any function (similar to reflection). With the release of Cobra 1.9.1, templates are no longer used by default in Cobra. By also not using templates in the tanzu-plugin-runtime it now gives an opportunity for plugins to try to avoid templates to allow dead-code elimination to work, if they so choose. Ref: spf13/cobra#1956 Signed-off-by: Marc Khouzam <[email protected]>
When templating is used, the linker cannot know which functions are called and which one are not; this is because templating use calls to "MethodByName()" which can be used to call any function (similar to reflection). With the release of Cobra 1.9.1, templates are no longer used by default in Cobra. By also not using templates in the tanzu-plugin-runtime it now gives an opportunity for plugins to try to avoid templates to allow dead-code elimination to work, if they so choose. Ref: spf13/cobra#1956 Signed-off-by: Marc Khouzam <[email protected]>
When templating is used, the linker cannot know which functions are called and which one are not; this is because templating use calls to "MethodByName()" which can be used to call any function (similar to reflection). With the release of Cobra 1.9.1, templates are no longer used by default in Cobra. By also not using templates in the tanzu-plugin-runtime it now gives an opportunity for plugins to try to avoid templates to allow dead-code elimination to work, if they so choose. Ref: spf13/cobra#1956 Signed-off-by: Marc Khouzam <[email protected]>
When templating is used, the linker cannot know which functions are called and which ones are not; this is because templating uses calls to "MethodByName()" which can be used to call any function (similar to reflection). With the release of Cobra 1.9.1, templates are no longer used by default in Cobra. By also not using templates in the tanzu-plugin-runtime it now gives an opportunity for plugins to try to avoid templates to allow dead-code elimination to work, if they so choose. Ref: spf13/cobra#1956 Signed-off-by: Marc Khouzam <[email protected]>
…#228) When templating is used, the linker cannot know which functions are called and which ones are not; this is because templating uses calls to "MethodByName()" which can be used to call any function (similar to reflection). With the release of Cobra 1.9.1, templates are no longer used by default in Cobra. By also not using templates in the tanzu-plugin-runtime it now gives an opportunity for plugins to try to avoid templates to allow dead-code elimination to work, if they so choose. Ref: spf13/cobra#1956 Signed-off-by: Marc Khouzam <[email protected]>
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github.com/spf13/cobra](https://github.com/spf13/cobra) | require | minor | `v1.8.1` -> `v1.9.1` | --- ### Release Notes <details> <summary>spf13/cobra (github.com/spf13/cobra)</summary> ### [`v1.9.1`](https://github.com/spf13/cobra/releases/tag/v1.9.1) [Compare Source](spf13/cobra@v1.9.0...v1.9.1) ##### 🐛 Fixes - Fix CompletionFunc implementation by [@​ccoVeille](https://github.com/ccoVeille) in spf13/cobra#2234 - Revert "Make detection for test-binary more universal ([#​2173](spf13/cobra#2173))" by [@​marckhouzam](https://github.com/marckhouzam) in spf13/cobra#2235 **Full Changelog**: spf13/cobra@v1.9.0...v1.9.1 ### [`v1.9.0`](https://github.com/spf13/cobra/releases/tag/v1.9.0) [Compare Source](spf13/cobra@v1.8.1...v1.9.0) #### ✨ Features - Allow linker to perform deadcode elimination for program using Cobra by [@​aarzilli](https://github.com/aarzilli) in spf13/cobra#1956 - Add default completion command even if there are no other sub-commands by [@​marckhouzam](https://github.com/marckhouzam) in spf13/cobra#1559 - Add CompletionWithDesc helper by [@​ccoVeille](https://github.com/ccoVeille) in spf13/cobra#2231 #### 🐛 Fixes - Fix deprecation comment for Command.SetOutput by [@​thaJeztah](https://github.com/thaJeztah) in spf13/cobra#2172 - Replace deprecated ioutil usage by [@​nirs](https://github.com/nirs) in spf13/cobra#2181 - Fix --version help and output for plugins by [@​nirs](https://github.com/nirs) in spf13/cobra#2180 - Allow to reset the templates to the default by [@​marckhouzam](https://github.com/marckhouzam) in spf13/cobra#2229 #### 🤖 Completions - Make Powershell completion work in constrained mode by [@​lstemplinger](https://github.com/lstemplinger) in spf13/cobra#2196 - Improve detection for flags that accept multiple values by [@​thaJeztah](https://github.com/thaJeztah) in spf13/cobra#2210 - add CompletionFunc type to help with completions by [@​ccoVeille](https://github.com/ccoVeille) in spf13/cobra#2220 - Add similar whitespace escape logic to bash v2 completions than in other completions by [@​kangasta](https://github.com/kangasta) in spf13/cobra#1743 - Print ActiveHelp for bash along other completions by [@​marckhouzam](https://github.com/marckhouzam) in spf13/cobra#2076 - fix(completions): Complete map flags multiple times by [@​gabe565](https://github.com/gabe565) in spf13/cobra#2174 - fix(bash): nounset unbound file filter variable on empty extension by [@​scop](https://github.com/scop) in spf13/cobra#2228 #### 🧪 Testing - Test also with go 1.23 by [@​nirs](https://github.com/nirs) in spf13/cobra#2182 - Make detection for test-binary more universal by [@​thaJeztah](https://github.com/thaJeztah) in spf13/cobra#2173 #### ✍🏼 Documentation - docs: update README.md by [@​eltociear](https://github.com/eltociear) in spf13/cobra#2197 - Improve site formatting by [@​nirs](https://github.com/nirs) in spf13/cobra#2183 - doc: add Conduit by [@​raulb](https://github.com/raulb) in spf13/cobra#2230 - doc: azion project added to the list of CLIs that use cobra by [@​maxwelbm](https://github.com/maxwelbm) in spf13/cobra#2198 - Fix broken links in active_help.md by [@​vuil](https://github.com/vuil) in spf13/cobra#2202 - chore: fix function name in comment by [@​zhuhaicity](https://github.com/zhuhaicity) in spf13/cobra#2216 #### 🔧 Dependency upgrades - build(deps): bump github.com/cpuguy83/go-md2man/v2 from 2.0.5 to 2.0.6 by [@​thaJeztah](https://github.com/thaJeztah) in spf13/cobra#2206 - Update to latest go-md2man by [@​mikelolasagasti](https://github.com/mikelolasagasti) in spf13/cobra#2201 - Upgrade `pflag` dependencies for v1.9.0 by [@​jpmcb](https://github.com/jpmcb) in spf13/cobra#2233 *** Thank you to all of our amazing contributors and all the great work that's been going into the completions feature!! ##### 👋🏼 New Contributors - [@​gabe565](https://github.com/gabe565) made their first contribution in spf13/cobra#2174 - [@​maxwelbm](https://github.com/maxwelbm) made their first contribution in spf13/cobra#2198 - [@​lstemplinger](https://github.com/lstemplinger) made their first contribution in spf13/cobra#2196 - [@​vuil](https://github.com/vuil) made their first contribution in spf13/cobra#2202 - [@​mikelolasagasti](https://github.com/mikelolasagasti) made their first contribution in spf13/cobra#2201 - [@​zhuhaicity](https://github.com/zhuhaicity) made their first contribution in spf13/cobra#2216 - [@​ccoVeille](https://github.com/ccoVeille) made their first contribution in spf13/cobra#2220 - [@​kangasta](https://github.com/kangasta) made their first contribution in spf13/cobra#1743 - [@​aarzilli](https://github.com/aarzilli) made their first contribution in spf13/cobra#1956 **Full Changelog**: spf13/cobra@v1.8.1...v1.9.0 </details> --- ### Configuration 📅 **Schedule**: Branch creation - Between 12:00 AM and 03:59 AM ( * 0-3 * * * ) (UTC), Automerge - Between 12:00 AM and 03:59 AM ( * 0-3 * * * ) (UTC). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC4wLjgiLCJ1cGRhdGVkSW5WZXIiOiI0MC4wLjgiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> Reviewed-on: https://code.forgejo.org/forgejo/runner/pulls/557 Reviewed-by: earl-warren <[email protected]> Co-authored-by: Renovate Bot <[email protected]> Co-committed-by: Renovate Bot <[email protected]>
Fixes #2015
Cobra, in its default configuration, will execute a template to generate help, usage and version outputs. Text/template execution calls MethodByName and MethodByName disables dead code elimination in the Go linker, therefore all programs that make use of cobra will be linked with dead code elimination disabled, even if they end up replacing the default usage, help and version formatters with a custom function and no actual text/template evaluations are ever made at runtime.
Dead code elimination in the linker helps reduce disk space and memory utilization of programs. For example, for the simple example program used by TestDeadcodeElimination 40% of the final executable size is dead code. For a more realistic example, 12% of the size of Delve's executable is deadcode.
This PR changes Cobra so that, in its default configuration, it does not automatically inhibit deadcode elimination by:
See https://github.com/aarzilli/whydeadcode to help find why dead-code-elimination may not work as well as it could in your project.