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
Support parsing Go 1.17 stack traces #62
Conversation
c9cb48c
to
815bb15
Compare
Codecov Report
@@ Coverage Diff @@
## main #62 +/- ##
=======================================
- Coverage 90.0% 89.9% -0.1%
=======================================
Files 12 12
Lines 3471 3587 +116
=======================================
+ Hits 3124 3226 +102
- Misses 282 291 +9
- Partials 65 70 +5
Continue to review full report at Codecov.
|
Wow thanks so much for working on this. Since it's a somewhat tricky change, would you mind creating one PR with the Answering your questions:
|
815bb15
to
f60448a
Compare
Fixes maruel#61. In Go 1.17, the format of function arguments printed in stack traces was improved. This is mentioned in the release notes: https://tip.golang.org/doc/go1.17#compiler > The format of stack traces from the runtime (printed when an uncaught > panic occurs, or when runtime.Stack is called) is improved. Previously, > the function arguments were printed as hexadecimal words based on the > memory layout. Now each argument in the source code is printed > separately, separated by commas. Aggregate-typed (struct, array, string, > slice, interface, and complex) arguments are delimited by curly braces. > A caveat is that the value of an argument that only lives in a register > and is not stored to memory may be inaccurate. Function return values > (which were usually inaccurate) are no longer printed. This runtime change was primarily performed in https://go-review.googlesource.com/c/go/+/304470. The description on that CL presents the change in greater detail. This commit adds support to panicparse for parsing these new aggregate-typed arguments. It does so while retaining the type structure from the stack traces, which allows for the structure to be faithfully recreated and for aggregate-type information to be accurately augmented, when available. The aggregate-type structure is stored in a tree of mutually recursive `Args` and `Arg` structs. The commit also adds support for handling the new "offset too large" operator that was added in the same runtime CL. This operator comes in the form of an "_" scalar argument in cases where the argument's frame offset was too large (>= 0xf0), preventing the argument from being printed in the stack trace. This change raises questions about backwards compatability in a few different areas. - this change does not break backwards compatability with pre-1.17 stack traces. However, due to the nature of how most of the unit tests are set up (i.e. shelling out to local go binary), we are losing some test coverage of pre-1.17 stack trace parsing. Is that ok? - similarly, this change breaks the library's tests for pre-1.17 installations of Go. As a result, it bumps the Go version run in CI. Is that ok? - this change will not cause users of the `github.com/maruel/panicparse/v2/stack` library to fail to compile. However, due to the additions to the `Arg` struct, users of the library will fail to observe all arguments when parsing post-1.17 stack traces (but not pre-1.17 stack traces) unless they are aware of the new `IsAggregate` field. Is that ok? The change has the following effect on microbenchmarks: ``` name old time/op new time/op delta ScanSnapshot_Passthru-16 2.45ns ± 3% 2.42ns ± 2% ~ (p=0.094 n=9+9) Aggregated_ToHTML-16 5.81ms ± 1% 5.87ms ± 3% ~ (p=0.079 n=10+9) ScanSnapshot_NoGuess-16 2.36ms ± 3% 2.52ms ± 1% +7.10% (p=0.000 n=10+9) ScanSnapshot_Guess-16 2.35ms ± 4% 2.53ms ± 1% +7.52% (p=0.000 n=9+10) Aggregate-16 139µs ± 2% 195µs ± 3% +40.14% (p=0.000 n=9+10) name old alloc/op new alloc/op delta Aggregated_ToHTML-16 1.17MB ± 0% 1.17MB ± 0% -0.18% (p=0.010 n=9+10) ScanSnapshot_Passthru-16 0.00B 0.00B ~ (all equal) ScanSnapshot_NoGuess-16 730kB ± 0% 1076kB ± 0% +47.39% (p=0.000 n=10+10) ScanSnapshot_Guess-16 730kB ± 0% 1076kB ± 0% +47.39% (p=0.000 n=10+10) Aggregate-16 143kB ± 0% 254kB ± 0% +77.81% (p=0.000 n=10+10) name old allocs/op new allocs/op delta Aggregate-16 565 ± 0% 565 ± 0% ~ (all equal) ScanSnapshot_Passthru-16 0.00 0.00 ~ (all equal) Aggregated_ToHTML-16 41.0k ± 0% 41.1k ± 0% +0.16% (p=0.000 n=10+8) ScanSnapshot_Guess-16 8.73k ± 0% 9.39k ± 0% +7.46% (p=0.000 n=10+9) ScanSnapshot_NoGuess-16 8.73k ± 0% 9.39k ± 0% +7.46% (p=0.000 n=9+10) ```
This change uses a small bit of unsafe code to avoid a `string->[]byte` cast on each use of `strconv.ParseUint`. This saves about 20% of the heap allocations in the `ScanSnapshot` benchmarks. ``` name old time/op new time/op delta ScanSnapshot_NoGuess-16 2.60ms ± 4% 2.48ms ± 1% -4.37% (p=0.008 n=5+5) Aggregate-16 195µs ± 2% 196µs ± 5% ~ (p=0.841 n=5+5) ScanSnapshot_Guess-16 2.58ms ± 5% 2.50ms ± 2% ~ (p=0.056 n=5+5) ScanSnapshot_Passthru-16 2.43ns ± 5% 2.43ns ± 3% ~ (p=0.548 n=5+5) Aggregated_ToHTML-16 5.81ms ± 1% 5.84ms ± 1% ~ (p=0.421 n=5+5) name old alloc/op new alloc/op delta ScanSnapshot_NoGuess-16 1.08MB ± 0% 1.06MB ± 0% -1.67% (p=0.008 n=5+5) ScanSnapshot_Guess-16 1.08MB ± 0% 1.06MB ± 0% -1.65% (p=0.008 n=5+5) Aggregate-16 254kB ± 0% 254kB ± 0% ~ (p=0.722 n=5+5) ScanSnapshot_Passthru-16 0.00B 0.00B ~ (all equal) Aggregated_ToHTML-16 1.17MB ± 0% 1.17MB ± 0% ~ (p=0.841 n=5+5) name old allocs/op new allocs/op delta ScanSnapshot_Guess-16 9.39k ± 0% 7.49k ± 0% -20.26% (p=0.008 n=5+5) ScanSnapshot_NoGuess-16 9.39k ± 0% 7.49k ± 0% -20.26% (p=0.000 n=5+4) Aggregate-16 565 ± 0% 565 ± 0% ~ (all equal) ScanSnapshot_Passthru-16 0.00 0.00 ~ (all equal) Aggregated_ToHTML-16 41.0k ± 0% 41.0k ± 0% ~ (p=0.492 n=5+5) ```
f60448a
to
21cb5f0
Compare
Thanks @maruel, I'm glad this is going in the right direction and that you're open to an external contribution. Also, thank you for this library - we're big fans over at CockroachDB!
I updated the commit to expand the version-dependent testing to support pre and post-1.17 stack traces.
CI should be green now across the board.
Sounds good to me. I'm happy to answer questions if I can be of any help. |
Update: I fixed issues that a debian maintainer discovered so you'll want to rebase. I'd like to have the unsafeString() change to be in a separate PR. It's unrelated to the fix. Is the handling about ast.BasicLit and ast.Ellipsis in source.go also unrelated? |
Excited for this to land! |
Sorry for the late response. This PR is quite hard to review because it changes multiple things at once. It would really help if "1 feature change = 1 PR". Here I can see that you further disable inlining, improve source parsing and improve go1.17 processing support. These should be separate. |
Thanks @maruel for the help with this change, and thanks again for the fantastic library! |
Thanks to both of you! When should we expect a release with this included? |
@derekperkins I think @maruel already has you covered with v2.2.0: https://github.com/maruel/panicparse/releases/tag/v2.2.0. |
Thanks. I saw that and since it only referenced GitHub Actions, I thought it was a maintenance release and didn't dig deeper. |
Oh thanks for the note, converted to a real release. https://github.com/maruel/panicparse/releases/tag/v2.2.0 now talks about go1.17. |
Thanks! |
Fixes #61.
In Go 1.17, the format of function arguments printed in stack traces was improved. This is mentioned in the release notes: https://tip.golang.org/doc/go1.17#compiler
This runtime change was primarily performed in https://go-review.googlesource.com/c/go/+/304470. The description on that CL presents the change in greater detail.
This commit adds support to panicparse for parsing these new aggregate-typed arguments. It does so while retaining the type structure from the stack traces, which allows for the structure to be faithfully recreated and for aggregate-type information to be accurately augmented, when available. The aggregate-type structure is stored in a tree of mutually recursive
Args
andArg
structs.The commit also adds support for handling the new "offset too large" operator that was added in the same runtime CL. This operator comes in the form of an "_" scalar argument in cases where the argument's frame offset was too large (>= 0xf0), preventing the argument from being printed in the stack trace.
This change raises questions about backwards compatability in a few different areas.
github.com/maruel/panicparse/v2/stack
library to fail to compile. However, due to the additions to theArg
struct, users of the library will fail to observe all arguments when parsing post-1.17 stack traces (but not pre-1.17 stack traces) unless they are aware of the newIsAggregate
field. Is that ok?