-
Notifications
You must be signed in to change notification settings - Fork 70
errorbase: optimize errors.Is #153
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 is a benchmark created by @rafi. It demonstrates `errors.Is` is very inefficient when the reference error does not match the input error.
Previously, `errors.Is` was very inefficient if the reference error did not match any errors in the chain. There were two significant sources of inefficiency: 1. The code would pessimistically construct the error mark for every error in the input error chain. This is O(chain_length^2). This was a lot of unnecessary allocations and caused the runtime to be O(n^2) in the average case instead of O(n). 2. The code compared the `Error()` message before comparing the types. It is possible to compare error types with zero allocations whereas computing the message often requires an allocation.
3ff6ee5 to
3a21e3d
Compare
| if m1.msg != m2.msg { | ||
| return false | ||
| } | ||
| if len(m1.types) != len(m2.types) { |
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 is a bug that is pretty unlikely to occur in the original implementation that checks error message before types, but its somewhat likely now that we check the types first.
| return true | ||
| } | ||
| for _, reference := range references { | ||
| if Is(err, reference) { |
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.
I think the reason we didn't use this implementation originally is Is was pretty slow. So it was better to use the quick check before the slow mark check. Now that Is is efficient, we don't need to duplicate the implementations.
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.
Thanks for the consolidation.
|
dhartunian
left a comment
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.
@dhartunian reviewed 1 of 3 files at r1, all commit messages.
Reviewable status: 1 of 3 files reviewed, 2 unresolved discussions (waiting on @jeffswenson)
| return true | ||
| } | ||
| for _, reference := range references { | ||
| if Is(err, reference) { |
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.
Thanks for the consolidation.
|
Thanks for the review! |
Update the errors package to get the performance optimization from cockroachdb/errors#153. Release note: none Informs: cockroachdb#154125
Update the errors package to get the performance optimization from cockroachdb/errors#153. Release note: none Informs: cockroachdb#154125
155254: go.mod: update cockroachdb/errors package r=jeffswenson a=jeffswenson Update the errors package to get the performance optimization from cockroachdb/errors#153. Release note: none Informs: #154125 Co-authored-by: Jeff Swenson <jeffswenson@betterthannull.com>
Update the errors package to get the performance optimization from cockroachdb/errors#153. Release note: none Informs: cockroachdb#154125
benchmark: add a benchmark for the errors package
This is a benchmark created by @rafiss. It demonstrates
errors.Isis very inefficient when the reference error does not match the
input error.
errbase: optimize errors.Is
Previously,
errors.Iswas very inefficient if the reference error didnot match any errors in the chain.
There were two significant sources of inefficiency:
error in the input error chain. This is O(chain_length^2). This was
a lot of unnecessary allocations and caused the runtime to be O(n^2)
in the average case instead of O(n).
Error()message before comparing the types.It is possible to compare error types with zero allocations whereas
computing the message often requires an allocation.
refs: cockroachdb/cockroach#154555
This change is