Skip to content

util/must: consider performance implications #108169

@erikgrinaker

Description

@erikgrinaker

The must package isn't suitable for use in hot paths. The main problem is that it takes printf-style format args as []interface{}:

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

Metadata

Metadata

Assignees

Labels

C-performancePerf of queries or internals. Solution not expected to change functional behavior.T-testengTestEng Team

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions