问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

XxHash:非常快速的非加密哈希算法

创作时间:
作者:
@小白创作中心

XxHash:非常快速的非加密哈希算法

引用
CSDN
1.
https://blog.csdn.net/xcntime/article/details/142924832

xxHash是一种非常快速的哈希算法,在RAM速度限制下运行。它成功地完成了SMHasher测试套件,用于评估哈希函数的碰撞、分散和随机性。代码具有很高的可移植性,哈希在所有平台上都是相同的(little/big-endian)。

性能基准测试

参考系统使用Intel i7-9700K CPU,运行Ubuntu X64 20.04。开源基准测试程序是用clang v10.0使用-O3标志编译的。

Hash Name
Width
Bandwidth (GB/s)
Small Data Velocity
Quality
Comment
XXH3 (SSE2)
64
31.5 GB/s
133.1
10
XXH128 (SSE2)
128
29.6 GB/s
118.1
10
RAM顺序读取
N/A
28.0 GB/s
N/A
N/A
for reference
City64
64
22.0 GB/s
76.6
10
T1ha2
64
22.0 GB/s
99.0
9
稍差的碰撞
City128
128
21.7 GB/s
57.7
10
XXH64
64
19.4 GB/s
71.0
10
SpookyHash
64
19.3 GB/s
53.2
10
Mum
64
18.0 GB/s
67.0
9
稍差的碰撞
XXH32
32
9.7 GB/s
71.9
10
City32
32
9.1 GB/s
66.0
10
Murmur3
32
3.9 GB/s
56.1
10
SipHash
64
3.0 GB/s
43.2
10
FNV64
64
1.2 GB/s
62.7
5
雪崩特性差
Blake2
256
1.1 GB/s
5.1
10
Cryptographic
SHA1
160
0.8 GB/s
5.6
10
加密但已损坏
MD5
128
0.6 GB/s
7.8
10
加密但已损坏

注1: 小数据速率是对小数据的算法效率的粗略评估。有关更详细的分析,请参阅下一段。

注2: 有些算法比RAM速度快。在这种情况下,只有当输入数据已经在CPU缓存(L3或更高)中时,它们才能达到全速。否则,它们会在RAM速度限制下达到最大值。

小数据性能

对大数据的性能只是图片的一部分。哈希在哈希表和bloom过滤器等构造中也非常有用。在这些用例中,经常散列大量的小数据(从几个字节开始)。在这种情况下,算法的性能可能会有很大的不同,因为算法的某些部分,例如初始化或终结,变成了固定成本。分支mis-prediction的影响也变得更加明显。

XXH3的设计在长输入和小输入方面都具有出色的性能,可以在下图中观察到这一点:

有关更详细的分析,请访问wiki:https://github.com/Cyan4973/xxHash/wiki/Performance-comparison#benchmarks-concentrating-on-small-data-

散列质量

速度不是唯一重要的属性。产生的散列值必须尊重优秀的分散性和随机性,这样它的任何sub-section都可以用来最大限度地扩展一个表或索引,并将碰撞量减少到最小理论水平,遵循生日悖论。

xxHash已经用austinappleby的优秀SMHasher测试套件进行了测试,并通过了所有测试,确保了合理的质量水平。它还通过了来自新的SMHasher分支的扩展测试,具有附加的场景和条件。

最后,xxHash提供了自己的大规模碰撞测试程序,能够生成和比较数十亿个哈希来测试64-bit哈希算法的极限。在这方面,xxHash也有很好的效果,符合生日悖论。wiki中记录了更详细的分析。

构建修饰符

可以在编译时设置以下宏来修改libxxhash的行为。它们通常在默认情况下被禁用。

  • XXH_INLINE_ALL:使所有函数inline,实现直接包含在xxhash.h中。内联函数有助于提高小按键的速度。当密钥长度被表示为编译时常数时,它非常有效,性能改进在+200%范围内。有关详细信息,请参阅本文。
  • XXH_PRIVATE_API:与XXH_INLINE_ALL的结果相同。仍然可用于遗留支持。该名称强调XXH_*符号将不会导出。
  • XXH_NAMESPACE:在所有符号前面加上XXH_NAMESPACE的值。此宏只能使用可编译字符集。当xxHash的源代码包含多个时,有助于避免符号命名冲突。客户机应用程序仍然使用常规函数名,因为符号是通过xxhash.h自动转换的。
  • XXH_FORCE_MEMORY_ACCESS:默认方法0使用可移植的memcpy()符号。方法1使用gcc-specific packed属性,该属性可以为某些目标提供更好的性能。方法2强制执行未对齐的读取,这不符合标准,但有时可能是提取更好的读取性能的唯一方法。方法3使用byteshift操作,这最适用于那些不在没有byteswap指令的memcpy()或big-endian系统的旧编译器
  • XXH_FORCE_ALIGN_CHECK:对齐输入时使用更快的直接读取路径。当哈希的输入在32或64-bit边界上对齐时,当在无法从未对齐的地址加载内存的体系结构上运行时,或由于它而受到性能损失时,此选项可以显著提高性能。在具有良好的未对齐内存访问性能(对齐和未对齐访问的相同指令)的平台上,这是(稍微)有害的。此选项在x86、x64和aarch64上自动禁用,并在所有其他平台上启用。
  • XXH_VECTOR:手动选择一个向量指令集(在编译时默认为auto-selected)。可用的指令集有XXH_SCALAR、XXH_SSE2、XXH_AVX2、XXH_AVX512、XXH_NEON和XXH_VSX。编译器可能需要额外的标志来确保正确的支持(例如,linux上的gcc对于AVX2需要-mavx2,对于AVX512需要-mavx512f)。
  • XXH_NO_PREFETCH:禁用预取。仅限XXH3。
  • XXH_PREFETCH_DIST:选择完善距离。仅限XXH3。
  • XXH_NO_INLINE_HINTS:默认情况下,xxHash使用__attribute__((always_inline))和__forceinline来提高性能,但以代码大小为代价。将此宏定义为1将所有内部函数标记为static,允许编译器决定是否内联函数。这在优化最小二进制大小时非常有用,并且在GCC和Clang上使用-O0、-Os、-Oz或-fno-inline编译时自动定义。这还可以根据编译器和体系结构提高性能。
  • XXH_REROLL:通过不展开某些循环来减少生成代码的大小。对性能的影响可能会有所不同,这取决于平台和算法。
  • XXH_ACCEPT_NULL_INPUT_POINTER:如果设置为1,当输入是NULL指针时,xxHash的结果与zero-length输入相同(而不是取消引用segfault)。在每个哈希的开头添加一个分支。
  • XXH_STATIC_LINKING_ONLY:为静态分配提供对状态声明的访问。由于ABI更改的风险,与动态链接不兼容。
  • XXH_NO_LONG_LONG:删除依赖64-bit类型(XXH3和XXH64)的算法编译。只编译XXH32。对于没有64-bit支持的目标(体系结构和编译器)很有用。
  • XXH_IMPORT:MSVC-specific:只应为动态链接定义,因为它可以防止链接错误。
  • XXH_CPU_LITTLE_ENDIAN:默认情况下,endianess由编译时解析的运行时测试确定。如果由于某种原因,编译器不能简化运行时测试,则会降低性能。可以跳过auto-detection,通过将这个宏设置为1,简单地声明体系结构是little-endian。将其设置为0状态big-endian。

对于命令行界面xxhsum,还可以设置以下环境变量:

  • DISPATCH=1:根据本地主机,使用xxh_x86dispatch.c在运行时自动选择scalar、sse2、avx2或avx512指令集。此选项仅对x86/x64系统有效。

使用vcpkg构建xxHash

您可以使用vcpkg依赖关系管理器下载并安装xxHash:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install xxhash

vcpkg中的xxHash端口由Microsoft团队成员和社区贡献者保持最新。如果版本已过期,请在vcpkg存储库上创建问题或请求请求。

示例代码

最简单的示例调用XXHASH 64-bit变体作为one-shot函数,从单个缓冲器生成哈希值,并从C/C++程序调用:

#include "xxhash.h"
(...)
XXH64_hash_t hash = XXH64(buffer, size, seed);
}

流式变体涉及更多,但可以增量提供数据:

#include "stdlib.h" /* abort() */
#include "xxhash.h"

XXH64_hash_t calcul_hash_streaming(FileHandler fh)
{
    /* create a hash state */
    XXH64_state_t*const state = XXH64_createState();
    if(state == NULL) abort();

    size_t const bufferSize = SOME_SIZE;
    void* const buffer = malloc(bufferSize);
    if(buffer == NULL) abort();

    /* Initialize state with selected seed */
    XXH64_hash_t const seed = 0; /* or any other value */
    if(XXH64_reset(state, seed) == XXH_ERROR) abort();

    /* Feed the state with input data, any size, any number of times */
    (...)
    while(/* some data left */) {
        size_t const length = get_more_data(buffer, bufferSize, fh);
        if(XXH64_update(state, buffer, length) == XXH_ERROR) abort();
        (...)
    }
    (...)

    /* Produce the final hash value */
    XXH64_hash_t const hash = XXH64_digest(state);

    /* State could be re-used; but in this example, it is simply freed */
    free(buffer);
    XXH64_freeState(state);
    return hash;
}

许可证

库文件xxhash.c和xxhash.h是BSD授权的。实用程序xxhsum是GPL授权的。

其他编程语言

除了C参考版本之外,xxHash还可以从许多不同的编程语言中获得,这要感谢伟大的贡献者。它们列在这里。

特别感谢

  • Takayuki Matsuoka,又名@t-mat,用于在xxh早期版本中创建xxhsum -c和一般支持
  • Mathias Westerdahl,又名@JCash,因为他介绍了XXH64的第一个版本
  • Devin Hussey,又名@easyaspi314,他对XXH3和XXH128进行了出色的low-level优化
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号