Skip to content
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

cmd/compile: PGO compiler diagnostics #58153

Open
prattmic opened this issue Jan 30, 2023 · 5 comments
Open

cmd/compile: PGO compiler diagnostics #58153

prattmic opened this issue Jan 30, 2023 · 5 comments
Assignees
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@prattmic
Copy link
Member

Today, the compiler has some limited diagnostics of behavior with PGO using the -d=pgoinline=1 flag. These are really just ad-hoc logging points. We want more robust diagnostics, for reasons @josharian lays out well in #55022 (comment):

The more opaque the toolchain and its inputs are, the harder it is to (a) write safety checks that detect performance problems before they make it to production and (b) diagnose performance issues after they make it to production.

Plus (c) of making it easier for us to investigate compilers issues filed here.

Our current thinking for initial work here is to provide more complete/structured output of all optimization decisions, rather than just "decisions due to PGO", because the latter is ambiguous. e.g., if we decide to do an inline because of PGO and that affects the non-PGO heuristics further up the call tree, does that count as a "PGO" decision.

cc @cherrymui @aclements

@prattmic prattmic added this to the Go1.21 milestone Jan 30, 2023
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jan 30, 2023
@mknyszek mknyszek added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jan 30, 2023
@prattmic
Copy link
Member Author

prattmic commented Jun 5, 2023

Bumping to 1.22. There is more structural work to be done.

For 1.21, PGO devirtualization does include structured JSON output with -d=pgodebug=3 detailing every single call with its type (direct, indirect interface, etc) and whether it was devirtualized. That can then be used for external analysis (e.g., with a tool like https://go.dev/cl/494717).

@prattmic prattmic modified the milestones: Go1.21, Go1.22 Jun 5, 2023
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/528400 mentions this issue: cmd/compile: add pgohash for debugging/bisecting PGO optimizations

gopherbot pushed a commit that referenced this issue Sep 19, 2023
When a PGO build fails or produces incorrect program, it is often
unclear what the problem is. Add pgo hash so we can bisect to
individual optimization decisions, which often helps debugging.

Related to #58153.

Change-Id: I651ffd9c53bad60f2f28c8ec2a90a3f532982712
Reviewed-on: https://go-review.googlesource.com/c/go/+/528400
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Michael Pratt <[email protected]>
@prattmic
Copy link
Member Author

Minor change: -m differentiates PGO vs static devirtualization, but doesn't note PGO-enabled inlines (-d=pgodebug=1 is required for that).

@cherrymui cherrymui modified the milestones: Go1.22, Backlog Nov 27, 2023
@mknyszek mknyszek marked this as a duplicate of #71278 Jan 15, 2025
@qinlonglong123
Copy link

In addition to structured output, we also hope to print some statistics, such as the total number of hotspot function calls in package A is xx, the actual number of inlined function calls is xx, and the hotspot function inlining rate is xx%.

@dr2chase
Copy link
Contributor

I saw this and thought, "can't this be obtained from the compiler's -json output"?
My experiment is to rebuild the compiler, with and without its profile, with json logging enabled, and to extract the inline information from the json files that are generated.

go install -a -gcflags=all=-json=0,`pwd`/nopgo -pgo=off cmd/compile
go install -a -gcflags=all=-json=0,`pwd`/pgo                      cmd/compile
cd pgo
grepall "*" -i "cannotinlinecall" > ../pgo.cic
grepall "*" -i caninlinefunction > ../pgo.cif
cd ../nopgo
grepall "*" -i "cannotinlinecall" > ../nopgo.cic
grepall "*" -i caninlinefunction > ../nopgo.cif
cd ../
wc -l *.cic
   4337 nopgo.cic
   41172 pgo.cic
   45509 total
wc -l *.cif
   10309 nopgo.cif
   11051 pgo.cif
   21360 total

and then if you diff the .cif files, you'll see things like

diff -C 0 nopgo.cif pgo.cif | more
*** nopgo.cif   Tue Jan 21 16:06:35 2025
--- pgo.cif     Tue Jan 21 16:06:16 2025
***************
*** 78 ****
--- 79 ----
+ ./bufio/bufio.json:{"range":{"start":{"line":677,"character":6},"end":{"line":677,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 206"}
***************
*** 140 ****
--- 142 ----
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/dwarf.json:{"range":{"start":{"line":297,"character":6},"end":{"line":297,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 239"}
***************
*** 145 ****
--- 148 ----
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/dwarf.json:{"range":{"start":{"line":346,"character":6},"end":{"line":346,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 105"}
***************
*** 146 ****
--- 150,151 ----
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/dwarf.json:{"range":{"start":{"line":472,"character":6},"end":{"line":472,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 1986"}
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/dwarf.json:{"range":{"start":{"line":497,"character":6},"end":{"line":497,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 1871"}
***************
*** 148 ****
--- 154,156 ----
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/scope.json:{"range":{"start":{"line":18,"character":6},"end":{"line":18,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 139"}
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/scope.json:{"range":{"start":{"line":22,"character":6},"end":{"line":22,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 93"}
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/scope.json:{"range":{"start":{"line":23,"character":31},"end":{"line":23,"character":31}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 147"}
***************
*** 149 ****
--- 158,160 ----
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/scope.json:{"range":{"start":{"line":23,"character":31},"end":{"line":23,"character":31}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 65"}
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/scope.json:{"range":{"start":{"line":32,"character":6},"end":{"line":32,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 540"}
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/scope.json:{"range":{"start":{"line":68,"character":6},"end":{"line":68,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 344"}
***************
*** 155 ****
--- 167,168 ----
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/dwinl.json:{"range":{"start":{"line":29,"character":6},"end":{"line":29,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 1545"}
+ ./cmd%2Fcompile%2Finternal%2Fdwarfgen/dwinl.json:{"range":{"start":{"line":227,"character":6},"end":{"line":227,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 340"}

There will be more complicated changes in places, because sometimes inlining can reduce a function's cost.

note: "grepall" is

#!/bin/bash

if [ $# -lt 2 ] ; then
  echo grepall "<find-pattern>" "[grep-options]" "<grep-pattern>"
  exit 1
fi

findpat=$1
shift
echo find . -name "$findpat" -exec egrep "$@" /dev/null  "{}" ";"
find . \( -name "$findpat" -and -type f \) -exec egrep "$@" /dev/null "{}" ";"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Development

No branches or pull requests

6 participants