Skip to content

Commit

Permalink
spawn/ResourceLimits: optimized hash function for MakeId()
Browse files Browse the repository at this point in the history
The new loads a 64 bit integer at a time instead of calculating the
hash with each byte.
  • Loading branch information
MaxKellermann committed Jan 21, 2025
1 parent 65b67a5 commit 885fb7e
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 3 deletions.
5 changes: 2 additions & 3 deletions src/spawn/ResourceLimits.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
#include "ResourceLimits.hxx"
#include "lib/fmt/SystemError.hxx"
#include "util/Base32.hxx"
#include "util/djb_hash.hxx"
#include "util/CharUtil.hxx"
#include "util/IntHash.hxx"
#include "util/Sanitizer.hxx"
#include "util/SpanCast.hxx"

#include <cassert>
#include <charconv>
Expand Down Expand Up @@ -72,7 +71,7 @@ ResourceLimits::IsEmpty() const noexcept
inline std::size_t
ResourceLimits::GetHash() const noexcept
{
return djb_hash(ReferenceAsBytes(*this));
return IntHashT(*this);
}

char *
Expand Down
65 changes: 65 additions & 0 deletions src/util/IntHash.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: BSD-2-Clause
// Copyright CM4all GmbH
// author: Max Kellermann <mk@cm4all.com>

#pragma once

#include <cstddef>
#include <cstdint>
#include <span>

static constexpr std::size_t INT_HASH_INIT = 17;

/**
* A very simple/naive and fast hash function for integers of
* arbitrary size.
*/
template<std::integral T>
[[nodiscard]] [[gnu::always_inline]] [[gnu::hot]]
constexpr std::size_t
IntHashUpdate(T src, std::size_t hash) noexcept
{
return (hash * 19) + static_cast<std::size_t>(src);
}

template<std::integral T, std::size_t extent=std::dynamic_extent>
[[nodiscard]] [[gnu::hot]]
constexpr std::size_t
IntHash(std::span<const T, extent> src, std::size_t hash=INT_HASH_INIT) noexcept
{
for (const T i : src)
hash = IntHashUpdate(i, hash);
return hash;
}

template<typename T, typename I>
requires(std::has_unique_object_representations_v<T> && sizeof(T) % sizeof(I) == 0 && alignof(T) % sizeof(I) == 0)
[[nodiscard]] [[gnu::hot]]
constexpr std::size_t
_IntHashT(const T &src, std::size_t hash=INT_HASH_INIT) noexcept
{
constexpr std::size_t n = sizeof(src) / sizeof(I);
const std::span<const I, n> span{reinterpret_cast<const I *>(&src), n};
return IntHash(span, hash);
}

/**
* Calculate the hash of an arbitrary (trivial) object, using the
* largest integer according to the object's alignment at compile
* time.
*/
template<typename T>
requires std::has_unique_object_representations_v<T>
[[nodiscard]] [[gnu::hot]]
constexpr std::size_t
IntHashT(const T &src, std::size_t hash=INT_HASH_INIT) noexcept
{
if constexpr (sizeof(T) % 8 == 0)
return _IntHashT<T, uint64_t>(src, hash);
else if constexpr (sizeof(T) % 4 == 0)
return _IntHashT<T, uint32_t>(src, hash);
else if constexpr (sizeof(T) % 2 == 0)
return _IntHashT<T, uint16_t>(src, hash);
else
return _IntHashT<T, uint8_t>(src, hash);
}

0 comments on commit 885fb7e

Please sign in to comment.