Skip to content

Commit a85a526

Browse files
authored
Improve performance of FromBytesOrNil (#206)
This pulls code from FromBytes and UnmarshalBinary into FromBytesOrNil which reduces the cost of creating a UUID from a byte slice. It also removes an allocation when the UUID is invalid as it no longer generates an error which is discarded. One downside of this approach is that it duplicates the logic from UnmarshalBinary. ``` goos: linux goarch: amd64 pkg: github.com/gofrs/uuid/v5 cpu: AMD Ryzen 9 5950X 16-Core Processor │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ FromBytesOrNil/valid-32 3.814n ± 0% 1.118n ± 1% -70.69% (n=100) FromBytesOrNil/empty-32 135.3500n ± 0% 0.6514n ± 1% -99.52% (n=100) geomean 22.72n 0.8534n -96.24% │ old.txt │ new.txt │ │ B/op │ B/op vs base │ FromBytesOrNil/valid-32 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=100) ¹ FromBytesOrNil/empty-32 96.00 ± 0% 0.00 ± 0% -100.00% (n=100) │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ FromBytesOrNil/valid-32 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=100) ¹ FromBytesOrNil/empty-32 2.000 ± 0% 0.000 ± 0% -100.00% (n=100) ```
1 parent 1404e37 commit a85a526

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

codec.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,15 @@ func FromBytes(input []byte) (UUID, error) {
3434
// FromBytesOrNil returns a UUID generated from the raw byte slice input.
3535
// Same behavior as FromBytes(), but returns uuid.Nil instead of an error.
3636
func FromBytesOrNil(input []byte) UUID {
37-
uuid, err := FromBytes(input)
38-
if err != nil {
37+
// The logic here is duplicated from UnmarshalBinary as there is unnecessary
38+
// overhead generating errors which would be checked and discarded.
39+
if len(input) != Size {
3940
return Nil
4041
}
42+
43+
uuid := UUID{}
44+
copy(uuid[:], input)
45+
4146
return uuid
4247
}
4348

codec_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,22 @@ func BenchmarkFromString(b *testing.B) {
342342
})
343343
}
344344

345+
var FromBytesOrNilResult UUID
346+
347+
func BenchmarkFromBytesOrNil(b *testing.B) {
348+
b.Run("valid", func(b *testing.B) {
349+
for i := 0; i < b.N; i++ {
350+
FromBytesOrNilResult = FromBytesOrNil(codecTestData)
351+
}
352+
})
353+
354+
b.Run("empty", func(b *testing.B) {
355+
for i := 0; i < b.N; i++ {
356+
FromBytesOrNilResult = FromBytesOrNil([]byte{})
357+
}
358+
})
359+
}
360+
345361
func BenchmarkUnmarshalText(b *testing.B) {
346362
b.Run("canonical", func(b *testing.B) {
347363
text := []byte(Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")).String())

0 commit comments

Comments
 (0)