-
Notifications
You must be signed in to change notification settings - Fork 4.1k
util/must: consider performance implications #108169
Description
The must package isn't suitable for use in hot paths. The main problem is that it takes printf-style format args as []interface{}:
cockroach/pkg/util/must/must.go
Lines 265 to 275 in 3250477
| func Equal[T comparable](ctx context.Context, a, b T, format string, args ...interface{}) error { | |
| // TODO(erikgrinaker): Consider erroring out on pointers, if possible. It's | |
| // usually not what one wants, and can be a footgun. | |
| if a == b { | |
| return nil | |
| } | |
| // TODO(erikgrinaker): Consider printing a diff, or otherwise improve the | |
| // formatting, for large values like entire structs. | |
| format += ": %#v != %#v" | |
| return failDepth(ctx, 1, format, append(args, a, b)...) | |
| } |
This has a couple of problems: the interface boxing incurs an allocation for certain types, and arguments can escape to the heap. One might hope that the compiler deferred the boxing until after the a == b condition when inlining, but no such luck.
Most likely, the better option is to significantly simplify the API. Something basically similar to:
if a != b {
return must.Fail(ctx, "a=%v != b=%v", a, b)
}This only incurs the cost of boxing on the unhappy path, and the heap escape can similarly be deferred by copying the format args value in the branch.
However, let's consider some other options here, and see if we can come up with something suitable.
Jira issue: CRDB-30342