Skip to content
This repository has been archived by the owner on Jul 31, 2023. It is now read-only.

Commit

Permalink
Optimize Record() to avoid extra allocations (#1267)
Browse files Browse the repository at this point in the history
* Register metrics in benchmark

Currently, the metric we record is not registered. This hits the
fast-path code of not actually recording the metric, so we miss out on
detecting any performance to that main code path.

This registers the metrics so we actually trigger `record`.

* Optimize Record() to avoid extra allocations

Currently, `Record()` re-uses code with `RecordWithOptions`. This always creates
allocations for createRecordOption, which is not needed in this case - we only
have measurements and not generic options.

With a little code duplication, we can reduce these allocations.

```
name                    old time/op    new time/op    delta
Record0-6                 92.2ns ± 9%     1.7ns ± 4%   -98.11%  (p=0.008 n=5+5)
Record1-6                  665ns ± 5%     634ns ± 6%    -4.57%  (p=0.095 n=5+5)
Record8-6                 1.24µs ± 5%    1.21µs ± 5%    -2.18%  (p=0.206 n=5+5)
Record8_WithRecorder-6     796ns ± 5%     777ns ± 5%    -2.45%  (p=0.222 n=5+5)
Record8_Parallel-6        1.21µs ± 2%    1.26µs ±24%      ~     (p=0.690 n=5+5)
Record8_8Tags-6           1.23µs ± 4%    1.23µs ± 2%      ~     (p=0.968 n=5+5)

name                    old alloc/op   new alloc/op   delta
Record0-6                  80.0B ± 0%      0.0B       -100.00%  (p=0.008 n=5+5)
Record1-6                   200B ± 0%      120B ± 0%   -40.00%  (p=0.008 n=5+5)
Record8-6                   424B ± 0%      344B ± 0%   -18.87%  (p=0.008 n=5+5)
Record8_WithRecorder-6      424B ± 0%      424B ± 0%      ~     (all equal)
Record8_Parallel-6          424B ± 0%      344B ± 0%   -18.87%  (p=0.008 n=5+5)
Record8_8Tags-6             424B ± 0%      344B ± 0%   -18.87%  (p=0.008 n=5+5)

name                    old allocs/op  new allocs/op  delta
Record0-6                   1.00 ± 0%      0.00       -100.00%  (p=0.008 n=5+5)
Record1-6                   4.00 ± 0%      3.00 ± 0%   -25.00%  (p=0.008 n=5+5)
Record8-6                   4.00 ± 0%      3.00 ± 0%   -25.00%  (p=0.008 n=5+5)
Record8_WithRecorder-6      4.00 ± 0%      4.00 ± 0%      ~     (all equal)
Record8_Parallel-6          4.00 ± 0%      3.00 ± 0%   -25.00%  (p=0.008 n=5+5)
Record8_8Tags-6             4.00 ± 0%      3.00 ± 0%   -25.00%  (p=0.008 n=5+5)
```
  • Loading branch information
howardjohn committed Sep 14, 2021
1 parent dcf8515 commit a55fb71
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
10 changes: 9 additions & 1 deletion stats/benchmark_test.go
Expand Up @@ -109,5 +109,13 @@ func BenchmarkRecord8_8Tags(b *testing.B) {
}

func makeMeasure() *stats.Int64Measure {
return stats.Int64("m", "test measure", "")
m := stats.Int64("m", "test measure", "")
v := &view.View{
Measure: m,
Aggregation: view.Sum(),
}
if err := view.Register(v); err != nil {
panic(err.Error())
}
return m
}
19 changes: 18 additions & 1 deletion stats/record.go
Expand Up @@ -89,7 +89,24 @@ func createRecordOption(ros ...Options) *recordOptions {
// Record records one or multiple measurements with the same context at once.
// If there are any tags in the context, measurements will be tagged with them.
func Record(ctx context.Context, ms ...Measurement) {
RecordWithOptions(ctx, WithMeasurements(ms...))
// Record behaves the same as RecordWithOptions, but because we do not have to handle generic functionality
// (RecordOptions) we can reduce some allocations to speed up this hot path
if len(ms) == 0 {
return
}
recorder := internal.DefaultRecorder
record := false
for _, m := range ms {
if m.desc.subscribed() {
record = true
break
}
}
if !record {
return
}
recorder(tag.FromContext(ctx), ms, nil)
return
}

// RecordWithTags records one or multiple measurements at once.
Expand Down

0 comments on commit a55fb71

Please sign in to comment.