1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2026-06-19 21:45:50 +02:00

attribute: inline hashing for small SLICE and MAP values (#8476)

Fixes #8450

Inlining the hashing logic for SLICE and MAP values of sizes 1 to 5
avoids slice header construction and function call overhead.

Our benchmark results show:
- Hashing speed improved by ~20% to ~44% across small slices and maps
- Heap allocations are completely eliminated (reduced from 1 to 0
allocs/op)

```
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/attribute
cpu: 13th Gen Intel(R) Core(TM) i7-13800H
                                        │   main.txt    │               new.txt               │
                                        │    sec/op     │   sec/op     vs base                │
HashKVs/All-20                             1.649µ ±  2%   1.558µ ± 2%   -5.49% (p=0.000 n=10)
HashKVs/BoolTrue-20                       155.15n ± 15%   32.38n ± 0%  -79.13% (p=0.000 n=10)
HashKVs/BoolFalse-20                      167.95n ±  8%   32.35n ± 0%  -80.74% (p=0.000 n=10)
HashKVs/BoolSliceLen2-20                  186.95n ± 22%   42.20n ± 0%  -77.43% (p=0.000 n=10)
HashKVs/BoolSliceLen3-20                  201.80n ± 10%   53.74n ± 1%  -73.37% (p=0.000 n=10)
HashKVs/IntNegative-20                    173.40n ± 16%   32.34n ± 1%  -81.35% (p=0.000 n=10)
HashKVs/IntZero-20                        158.25n ±  9%   32.36n ± 0%  -79.55% (p=0.000 n=10)
HashKVs/IntSliceLen5-20                   197.00n ±  4%   67.32n ± 1%  -65.83% (p=0.000 n=10)
HashKVs/IntSliceLen1-20                   155.85n ± 10%   36.02n ± 0%  -76.89% (p=0.000 n=10)
HashKVs/Int64One-20                       119.30n ± 12%   32.37n ± 0%  -72.86% (p=0.000 n=10)
HashKVs/Int64-20                          145.25n ± 13%   32.37n ± 0%  -77.71% (p=0.000 n=10)
HashKVs/Int64SliceLen4-20                 159.15n ±  8%   61.33n ± 0%  -61.46% (p=0.000 n=10)
HashKVs/Int64SliceWithZero-20             159.05n ±  8%   61.39n ± 1%  -61.40% (p=0.000 n=10)
HashKVs/Float64-20                        113.15n ±  7%   32.34n ± 0%  -71.41% (p=0.000 n=10)
HashKVs/Float64Large-20                   112.80n ±  6%   32.39n ± 0%  -71.29% (p=0.000 n=10)
HashKVs/Float64SliceLen4-20               162.45n ±  7%   60.64n ± 1%  -62.67% (p=0.000 n=10)
HashKVs/Float64SliceLarge-20              151.85n ±  3%   60.73n ± 2%  -60.00% (p=0.000 n=10)
HashKVs/StringFoo-20                      109.35n ±  8%   30.26n ± 0%  -72.32% (p=0.000 n=10)
HashKVs/StringBar-20                      105.60n ±  8%   30.27n ± 0%  -71.33% (p=0.000 n=10)
HashKVs/StringSliceLen3-20                139.35n ±  5%   48.50n ± 0%  -65.20% (p=0.000 n=10)
HashKVs/StringSliceLooksLikeIntSlice-20   118.50n ±  6%   34.91n ± 0%  -70.54% (p=0.000 n=10)
HashKVs/ByteSliceFoo-20                   108.00n ±  6%   30.25n ± 0%  -72.00% (p=0.000 n=10)
HashKVs/ByteSliceLooksLikeIntSlice-20     105.80n ±  9%   31.39n ± 1%  -70.33% (p=0.000 n=10)
HashKVs/SliceLen0-20                      110.15n ± 50%   29.69n ± 0%  -73.05% (p=0.000 n=10)
HashKVs/SliceLen1-20                      127.70n ±  9%   44.95n ± 0%  -64.80% (p=0.000 n=10)
HashKVs/SliceLen2-20                      160.35n ±  7%   67.96n ± 1%  -57.61% (p=0.000 n=10)
HashKVs/SliceLen3-20                      190.90n ± 15%   86.01n ± 0%  -54.95% (p=0.000 n=10)
HashKVs/SliceLen4-20                       216.5n ±  7%   105.4n ± 0%  -51.32% (p=0.000 n=10)
HashKVs/SliceLen5-20                       243.0n ± 11%   122.3n ± 0%  -49.67% (p=0.000 n=10)
HashKVs/SliceNested-20                     313.5n ±  9%   206.5n ± 0%  -34.11% (p=0.000 n=10)
HashKVs/MapLen0-20                        105.55n ±  7%   29.68n ± 0%  -71.88% (p=0.000 n=10)
HashKVs/MapLen2-20                        172.90n ±  7%   73.95n ± 1%  -57.23% (p=0.000 n=10)
HashKVs/MapNested-20                       277.4n ±  4%   170.9n ± 0%  -38.39% (p=0.000 n=10)
HashKVs/EmptyValue-20                     107.95n ±  6%   29.68n ± 0%  -72.51% (p=0.000 n=10)
HashValueSlice/Len2-20                    140.20n ±  5%   49.48n ± 0%  -64.70% (p=0.000 n=10)
HashValueSlice/Len5-20                     206.2n ±  9%   110.0n ± 1%  -46.64% (p=0.000 n=10)
HashValueSlice/Len8Nested-20               332.3n ±  4%   270.9n ± 0%  -18.46% (p=0.000 n=10)
HashValueMap/Len2-20                      152.95n ± 32%   67.89n ± 1%  -55.61% (p=0.000 n=10)
HashValueMap/Len5-20                       247.8n ±  3%   135.5n ± 0%  -45.35% (p=0.000 n=10)
HashValueMap/Len8Nested-20                 412.7n ±  3%   342.1n ± 1%  -17.11% (p=0.000 n=10)
geomean                                    171.6n         60.79n       -64.57%

                                        │  main.txt  │                new.txt                 │
                                        │    B/op    │   B/op     vs base                     │
HashKVs/All-20                            80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/BoolTrue-20                       80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/BoolFalse-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/BoolSliceLen2-20                  80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/BoolSliceLen3-20                  80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/IntNegative-20                    80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/IntZero-20                        80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/IntSliceLen5-20                   80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/IntSliceLen1-20                   80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Int64One-20                       80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Int64-20                          80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Int64SliceLen4-20                 80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Int64SliceWithZero-20             80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Float64-20                        80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Float64Large-20                   80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Float64SliceLen4-20               80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Float64SliceLarge-20              80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/StringFoo-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/StringBar-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/StringSliceLen3-20                80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/StringSliceLooksLikeIntSlice-20   80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/ByteSliceFoo-20                   80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/ByteSliceLooksLikeIntSlice-20     80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen0-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen1-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen2-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen3-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen4-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen5-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceNested-20                    80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/MapLen0-20                        80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/MapLen2-20                        80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/MapNested-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/EmptyValue-20                     80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashValueSlice/Len2-20                    80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashValueSlice/Len5-20                    80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashValueSlice/Len8Nested-20              80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashValueMap/Len2-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashValueMap/Len5-20                      80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
HashValueMap/Len8Nested-20                80.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
geomean                                   80.00                   ?                       ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean

                                        │  main.txt  │                 new.txt                 │
                                        │ allocs/op  │ allocs/op   vs base                     │
HashKVs/All-20                            1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/BoolTrue-20                       1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/BoolFalse-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/BoolSliceLen2-20                  1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/BoolSliceLen3-20                  1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/IntNegative-20                    1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/IntZero-20                        1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/IntSliceLen5-20                   1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/IntSliceLen1-20                   1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Int64One-20                       1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Int64-20                          1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Int64SliceLen4-20                 1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Int64SliceWithZero-20             1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Float64-20                        1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Float64Large-20                   1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Float64SliceLen4-20               1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/Float64SliceLarge-20              1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/StringFoo-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/StringBar-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/StringSliceLen3-20                1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/StringSliceLooksLikeIntSlice-20   1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/ByteSliceFoo-20                   1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/ByteSliceLooksLikeIntSlice-20     1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen0-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen1-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen2-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen3-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen4-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceLen5-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/SliceNested-20                    1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/MapLen0-20                        1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/MapLen2-20                        1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/MapNested-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashKVs/EmptyValue-20                     1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashValueSlice/Len2-20                    1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashValueSlice/Len5-20                    1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashValueSlice/Len8Nested-20              1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashValueMap/Len2-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashValueMap/Len5-20                      1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
HashValueMap/Len8Nested-20                1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
geomean                                   1.000                    ?                       ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean
```
This commit is contained in:
Dipanshu singh
2026-06-18 10:10:24 +05:30
committed by GitHub
parent 4ef740f17f
commit feac81f60d
+45 -25
View File
@@ -102,15 +102,25 @@ func hashValue(h xxhash.Hash, v Value) xxhash.Hash {
case [0]Value:
// No values to hash, but the type identifier is still hashed above.
case [1]Value:
h = hashValueSlice(h, vals[:])
h = hashValue(h, vals[0])
case [2]Value:
h = hashValueSlice(h, vals[:])
h = hashValue(h, vals[0])
h = hashValue(h, vals[1])
case [3]Value:
h = hashValueSlice(h, vals[:])
h = hashValue(h, vals[0])
h = hashValue(h, vals[1])
h = hashValue(h, vals[2])
case [4]Value:
h = hashValueSlice(h, vals[:])
h = hashValue(h, vals[0])
h = hashValue(h, vals[1])
h = hashValue(h, vals[2])
h = hashValue(h, vals[3])
case [5]Value:
h = hashValueSlice(h, vals[:])
h = hashValue(h, vals[0])
h = hashValue(h, vals[1])
h = hashValue(h, vals[2])
h = hashValue(h, vals[3])
h = hashValue(h, vals[4])
default:
rv := reflect.ValueOf(v.slice)
for i := 0; i < rv.Len(); i++ {
@@ -123,15 +133,40 @@ func hashValue(h xxhash.Hash, v Value) xxhash.Hash {
case [0]KeyValue:
// No values to hash, but the type identifier is still hashed above.
case [1]KeyValue:
h = hashMap(h, vals[:])
h = h.String(string(vals[0].Key))
h = hashValue(h, vals[0].Value)
case [2]KeyValue:
h = hashMap(h, vals[:])
h = h.String(string(vals[0].Key))
h = hashValue(h, vals[0].Value)
h = h.String(string(vals[1].Key))
h = hashValue(h, vals[1].Value)
case [3]KeyValue:
h = hashMap(h, vals[:])
h = h.String(string(vals[0].Key))
h = hashValue(h, vals[0].Value)
h = h.String(string(vals[1].Key))
h = hashValue(h, vals[1].Value)
h = h.String(string(vals[2].Key))
h = hashValue(h, vals[2].Value)
case [4]KeyValue:
h = hashMap(h, vals[:])
h = h.String(string(vals[0].Key))
h = hashValue(h, vals[0].Value)
h = h.String(string(vals[1].Key))
h = hashValue(h, vals[1].Value)
h = h.String(string(vals[2].Key))
h = hashValue(h, vals[2].Value)
h = h.String(string(vals[3].Key))
h = hashValue(h, vals[3].Value)
case [5]KeyValue:
h = hashMap(h, vals[:])
h = h.String(string(vals[0].Key))
h = hashValue(h, vals[0].Value)
h = h.String(string(vals[1].Key))
h = hashValue(h, vals[1].Value)
h = h.String(string(vals[2].Key))
h = hashValue(h, vals[2].Value)
h = h.String(string(vals[3].Key))
h = hashValue(h, vals[3].Value)
h = h.String(string(vals[4].Key))
h = hashValue(h, vals[4].Value)
default:
rv := reflect.ValueOf(v.slice)
for i := 0; i < rv.Len(); i++ {
@@ -151,18 +186,3 @@ func hashValue(h xxhash.Hash, v Value) xxhash.Hash {
}
return h
}
func hashValueSlice(h xxhash.Hash, vals []Value) xxhash.Hash {
for _, v := range vals {
h = hashValue(h, v)
}
return h
}
func hashMap(h xxhash.Hash, vals []KeyValue) xxhash.Hash {
for _, kv := range vals {
h = h.String(string(kv.Key))
h = hashValue(h, kv.Value)
}
return h
}