mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
Rework our hash functions a bit for significant better performance: * Rename int_hash to u32_hash to mirror u64_hash. * Make pair_int_hash call u64_hash instead of multiple u32_hash()es. * Implement MurmurHash3's fmix32 and fmix64 for u32_hash and u64_hash. On my machine, this speeds up u32_hash by 20%, u64_hash by ~290%, and pair_int_hash by ~260%. We lose the property that an input of 0 results in something that is not 0. I've experimented with an offset to both hash functions, but it resulted in a measurable performance degradation for u64_hash. If there's a good use case for 0 not to result in 0, we can always add in that offset as a countermeasure in the future.
74 lines
1.9 KiB
C++
74 lines
1.9 KiB
C++
/*
|
|
* Copyright (c) 2020, the SerenityOS developers.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibTest/TestCase.h>
|
|
|
|
#include <AK/HashFunctions.h>
|
|
#include <AK/Types.h>
|
|
|
|
TEST_CASE(u32_hash)
|
|
{
|
|
static_assert(u32_hash(42) == 142593372u);
|
|
static_assert(u32_hash(0) == 0u);
|
|
}
|
|
|
|
TEST_CASE(pair_int_hash)
|
|
{
|
|
static_assert(pair_int_hash(42, 17) == 1110885963u);
|
|
static_assert(pair_int_hash(0, 0) == 0u);
|
|
}
|
|
|
|
TEST_CASE(u64_hash)
|
|
{
|
|
static_assert(u64_hash(42) == 2386713036u);
|
|
static_assert(u64_hash(0) == 0u);
|
|
}
|
|
|
|
TEST_CASE(ptr_hash)
|
|
{
|
|
// These tests are not static_asserts because the values are
|
|
// different and the goal is to bind the behavior.
|
|
if constexpr (sizeof(FlatPtr) == 8) {
|
|
EXPECT_EQ(ptr_hash(FlatPtr(42)), 2386713036u);
|
|
EXPECT_EQ(ptr_hash(FlatPtr(0)), 0u);
|
|
|
|
EXPECT_EQ(ptr_hash(reinterpret_cast<void const*>(42)), 2386713036u);
|
|
EXPECT_EQ(ptr_hash(reinterpret_cast<void const*>(0)), 0u);
|
|
} else {
|
|
EXPECT_EQ(ptr_hash(FlatPtr(42)), 142593372u);
|
|
EXPECT_EQ(ptr_hash(FlatPtr(0)), 0u);
|
|
|
|
EXPECT_EQ(ptr_hash(reinterpret_cast<void const*>(42)), 142593372u);
|
|
EXPECT_EQ(ptr_hash(reinterpret_cast<void const*>(0)), 0u);
|
|
}
|
|
}
|
|
|
|
TEST_CASE(constexpr_ptr_hash)
|
|
{
|
|
// This test does not check the result because the goal is just to
|
|
// ensure the function can be executed in a constexpr context. The
|
|
// "ptr_hash" test binds the result.
|
|
static_assert(ptr_hash(FlatPtr(42)));
|
|
}
|
|
|
|
template<typename HashFunction>
|
|
requires(IsCallableWithArguments<HashFunction, unsigned, u64>)
|
|
static void run_benchmark(HashFunction hash_function)
|
|
{
|
|
for (size_t i = 0; i < 1'000'000; ++i) {
|
|
auto a = hash_function(i);
|
|
AK::taint_for_optimizer(a);
|
|
auto b = hash_function(i);
|
|
AK::taint_for_optimizer(b);
|
|
EXPECT_EQ(a, b);
|
|
}
|
|
}
|
|
|
|
BENCHMARK_CASE(deterministic_hash)
|
|
{
|
|
run_benchmark(u64_hash);
|
|
}
|