From 0d028dc26833da467886846c0774af173fc26ccd Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 23 Apr 2026 15:23:58 +0800 Subject: [PATCH 1/3] bench --- bench/hash_bench_test.mbt | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 bench/hash_bench_test.mbt diff --git a/bench/hash_bench_test.mbt b/bench/hash_bench_test.mbt new file mode 100644 index 0000000000..342a460537 --- /dev/null +++ b/bench/hash_bench_test.mbt @@ -0,0 +1,38 @@ +///| +test "bench Hash for Bytes (small)" (it : @bench.T) { + let data = Bytes::make(16, 0xAB) + it.bench(fn() { it.keep(Hash::hash(data)) }) +} + +///| +test "bench Hash for Bytes (medium)" (it : @bench.T) { + let data = Bytes::make(256, 0xAB) + it.bench(fn() { it.keep(Hash::hash(data)) }) +} + +///| +test "bench Hash for Bytes (large)" (it : @bench.T) { + let data = Bytes::make(4096, 0xAB) + it.bench(fn() { it.keep(Hash::hash(data)) }) +} + +///| +test "bench Hash for BytesView (small)" (it : @bench.T) { + let data = Bytes::make(16, 0xAB) + let view = data.view() + it.bench(fn() { it.keep(Hash::hash(view)) }) +} + +///| +test "bench Hash for BytesView (medium)" (it : @bench.T) { + let data = Bytes::make(256, 0xAB) + let view = data.view() + it.bench(fn() { it.keep(Hash::hash(view)) }) +} + +///| +test "bench Hash for BytesView (large)" (it : @bench.T) { + let data = Bytes::make(4096, 0xAB) + let view = data.view() + it.bench(fn() { it.keep(Hash::hash(view)) }) +} From bda8c1f698835db278c975d1b83bc69096d970e5 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 28 Apr 2026 22:52:27 +0800 Subject: [PATCH 2/3] perf: hash bytes with u32le view patterns --- builtin/hasher.mbt | 65 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/builtin/hasher.mbt b/builtin/hasher.mbt index a696483f40..a610f4aea3 100644 --- a/builtin/hasher.mbt +++ b/builtin/hasher.mbt @@ -354,15 +354,22 @@ pub fn Hasher::combine_byte(self : Hasher, value : Byte) -> Unit { /// } /// ``` pub fn Hasher::combine_bytes(self : Hasher, value : Bytes) -> Unit { - let (cur, remain) = for cur = 0, remain = value.length(); remain >= 4; { - self.consume4(endian32(value, cur)) - continue cur + 4, remain - 4 - } nobreak { - (cur, remain) - } - for cur = cur, remain = remain; remain >= 1; { - self.consume1(value[cur]) - continue cur + 1, remain - 1 + for data = value.view() { + if data is [u32le(x), .. rest] { + self.consume4(x) + continue rest + } else { + if data is [b0, .. data] { + self.consume1(b0) + if data is [b1, .. data] { + self.consume1(b1) + if data is [b2, ..] { + self.consume1(b2) + } + } + } + break + } } } @@ -462,16 +469,6 @@ fn rotl(x : UInt, r : Int) -> UInt { (x << r) | (x >> (32 - r)) } -///| -fn endian32(input : Bytes, cur : Int) -> UInt { - input[cur + 0].to_uint() | - ( - (input[cur + 1].to_uint() << 8) | - (input[cur + 2].to_uint() << 16) | - (input[cur + 3].to_uint() << 24) - ) -} - ///| /// Implements the `Hash` trait for `String` type, providing a method to combine /// a string's hash value with a hasher's state. @@ -651,20 +648,22 @@ pub impl[T : Hash, E : Hash] Hash for Result[T, E] with hash_combine( ///| pub impl Hash for BytesView with hash_combine(self : BytesView, hasher : Hasher) { - let data = self.bytes() - let (start, rest) = for start = self.start(), rest = self.len(); rest >= 4; { - let result = for i in 0..<=3; result = (0 : UInt) { - continue result | (data.unsafe_get(i + start).to_uint() << (8 * i)) - } nobreak { - result + for data = self { + if data is [u32le(x), .. rest] { + hasher.combine_uint(x) + continue rest + } else { + // only 0-3 bytes left + if data is [b0, .. data] { + hasher.combine_byte(b0) + if data is [b1, .. data] { + hasher.combine_byte(b1) + if data is [b2, ..] { + hasher.combine_byte(b2) + } + } + } + break } - hasher.combine_uint(result) - continue start + 4, rest - 4 - } nobreak { - (start, rest) - } - for start = start, rest = rest; rest >= 1; { - hasher.combine_byte(data.unsafe_get(start)) - continue start + 1, rest - 1 } } From 5966c74add7d75ebbe494f6997fac90888e1dc18 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 8 May 2026 17:59:55 +0800 Subject: [PATCH 3/3] Add license header to hash bench --- bench/hash_bench_test.mbt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bench/hash_bench_test.mbt b/bench/hash_bench_test.mbt index 342a460537..d54cf3d71f 100644 --- a/bench/hash_bench_test.mbt +++ b/bench/hash_bench_test.mbt @@ -1,3 +1,17 @@ +// Copyright 2026 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + ///| test "bench Hash for Bytes (small)" (it : @bench.T) { let data = Bytes::make(16, 0xAB)