From bcf1f915a81445eda2a0b10c601ba551a09a4c4d Mon Sep 17 00:00:00 2001 From: Ayan George Date: Thu, 3 Aug 2023 05:18:30 -0400 Subject: [PATCH] Use .EqualFold() to parse urn prefixed UUIDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this commit we used a comparison with the result of ToLower() to test for a "urn:uuid" prefix in both UUID strings and byte slices. This commit replaces the ToLower and string comparison with both strings.EqualFold() and bytes.EqualFold(). This reduces the CPU time across the board for UUIDs that start with "urn:uuid" and eliminates some allocations when parsing bytes. The benchmark output was generated by adding "urn:uuid" to the test input. goos: linux goarch: amd64 pkg: github.com/google/uuid cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz │ /tmp/output1 │ /tmp/output2 │ │ sec/op │ sec/op vs base │ Parse-8 35.87n ± ∞ ¹ 33.75n ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBytes-8 65.10n ± ∞ ¹ 35.56n ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBytesUnsafe-8 35.31n ± ∞ ¹ 34.70n ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBytesCopy-8 78.01n ± ∞ ¹ 61.21n ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBadLength-8 3.499n ± ∞ ¹ 3.084n ± ∞ ¹ ~ (p=1.000 n=1) ² ParseLen32Truncated-8 3.335n ± ∞ ¹ 3.334n ± ∞ ¹ ~ (p=1.000 n=1) ² ParseLen36Corrupted-8 63.02n ± ∞ ¹ 58.26n ± ∞ ¹ ~ (p=1.000 n=1) ² geomean 24.11n 20.51n -14.92% ¹ need >= 6 samples for confidence interval at level 0.95 ² need >= 4 samples to detect a difference at alpha level 0.05 │ /tmp/output1 │ /tmp/output2 │ │ B/op │ B/op vs base │ Parse-8 0.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBytes-8 16.00 ± ∞ ¹ 0.00 ± ∞ ¹ ~ (p=1.000 n=1) ³ ParseBytesUnsafe-8 0.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBytesCopy-8 48.00 ± ∞ ¹ 48.00 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBadLength-8 0.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseLen32Truncated-8 0.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseLen36Corrupted-8 16.00 ± ∞ ¹ 16.00 ± ∞ ¹ ~ (p=1.000 n=1) ² geomean ⁴ ? ⁴ ⁵ ¹ need >= 6 samples for confidence interval at level 0.95 ² all samples are equal ³ need >= 4 samples to detect a difference at alpha level 0.05 ⁴ summaries must be >0 to compute geomean ⁵ ratios must be >0 to compute geomean │ /tmp/output1 │ /tmp/output2 │ │ allocs/op │ allocs/op vs base │ Parse-8 0.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBytes-8 1.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ³ ParseBytesUnsafe-8 0.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBytesCopy-8 1.000 ± ∞ ¹ 1.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseBadLength-8 0.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseLen32Truncated-8 0.000 ± ∞ ¹ 0.000 ± ∞ ¹ ~ (p=1.000 n=1) ² ParseLen36Corrupted-8 1.000 ± ∞ ¹ 1.000 ± ∞ ¹ ~ (p=1.000 n=1) ² geomean ⁴ ? ⁴ ⁵ ¹ need >= 6 samples for confidence interval at level 0.95 ² all samples are equal ³ need >= 4 samples to detect a difference at alpha level 0.05 ⁴ summaries must be >0 to compute geomean ⁵ ratios must be >0 to compute geomean --- uuid.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/uuid.go b/uuid.go index a57207a..a56138c 100644 --- a/uuid.go +++ b/uuid.go @@ -69,7 +69,7 @@ func Parse(s string) (UUID, error) { // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36 + 9: - if strings.ToLower(s[:9]) != "urn:uuid:" { + if !strings.EqualFold(s[:9], "urn:uuid:") { return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) } s = s[9:] @@ -101,7 +101,8 @@ func Parse(s string) (UUID, error) { 9, 11, 14, 16, 19, 21, - 24, 26, 28, 30, 32, 34} { + 24, 26, 28, 30, 32, 34, + } { v, ok := xtob(s[x], s[x+1]) if !ok { return uuid, errors.New("invalid UUID format") @@ -117,7 +118,7 @@ func ParseBytes(b []byte) (UUID, error) { switch len(b) { case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { + if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) { return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) } b = b[9:] @@ -145,7 +146,8 @@ func ParseBytes(b []byte) (UUID, error) { 9, 11, 14, 16, 19, 21, - 24, 26, 28, 30, 32, 34} { + 24, 26, 28, 30, 32, 34, + } { v, ok := xtob(b[x], b[x+1]) if !ok { return uuid, errors.New("invalid UUID format")