使用AVX512可以将MD5的总哈希加速到800%

使用AVX512可以将MD5的总哈希加速到800%

介绍

尽管在考虑哈希函数时,MD5哈希不再是一个不错的选择,但它仍在各种应用程序中使用。因此,可以考虑对MD5哈希速度进行的任何性能改进。

由于SIMD处理(AVX2,尤其是AVX512)最近有所改进,我们提供了Go md5-simd程序包,该程序包可将MD5哈希在AVX2上的总集成速度提高400%,在AVX512上的最高800%。

通过在单个CPU内核上并行运行8个(AVX2)或16个(AVX512)独立的MD5和,可以提高性能。

重要的是要了解这md5-simd 不会加快单个MD5哈希总和的速度相反,它允许  在同一CPU内核上并行计算多个独立的MD5和,从而更有效地利用计算资源。

性能

下表比较了crypto/md5AVX2和AVX512代码之间的性能


Multi-core-MD5-Aggregated-Hashing-Performance-2.png


与相比crypto/md5,AVX2版本的速度提高了4倍:

$ benchcmp crypto-md5.txt avx2.txt 
benchmark                     old MB/s     new MB/s     speedup
BenchmarkParallel/32KB-4      2229.22      7370.50      3.31x
BenchmarkParallel/64KB-4      2233.61      8248.46      3.69x
BenchmarkParallel/128KB-4     2235.43      8660.74      3.87x
BenchmarkParallel/256KB-4     2236.39      8863.87      3.96x
BenchmarkParallel/512KB-4     2238.05      8985.39      4.01x
BenchmarkParallel/1MB-4       2233.56      9042.62      4.05x
BenchmarkParallel/2MB-4       2224.11      9014.46      4.05x
BenchmarkParallel/4MB-4       2199.78      8993.61      4.09x
BenchmarkParallel/8MB-4       2182.48      8748.22      4.01x

与相比crypto/md5,AVX512的速度提高了8倍:

$ benchcmp crypto-md5.txt avx512.txt
benchmark                     old MB/s     new MB/s     speedup
BenchmarkParallel/32KB-4      2229.22      11605.78     5.21x
BenchmarkParallel/64KB-4      2233.61      14329.65     6.42x
BenchmarkParallel/128KB-4     2235.43      16166.39     7.23x
BenchmarkParallel/256KB-4     2236.39      15570.09     6.96x
BenchmarkParallel/512KB-4     2238.05      16705.83     7.46x
BenchmarkParallel/1MB-4       2233.56      16941.95     7.59x
BenchmarkParallel/2MB-4       2224.11      17136.01     7.70x
BenchmarkParallel/4MB-4       2199.78      17218.61     7.83x
BenchmarkParallel/8MB-4       2182.48      17252.88     7.91x

设计

md5-simd 同时具有AVX2(8通道并行版本)和AVX512(16通道并行版本)算法,可通过以下函数定义来加快计算速度:

//go:noescape
func block8(state *uint32, base uintptr, bufs *int32, cache *byte, n int)

//go:noescape
func block16(state *uint32, ptrs *int64, mask uint64, n int)

AVX2版本基于md5vec存储库,除了微小(外观)更改外,基本上没有变化。

AVX512版本是从AVX2版本衍生而来,但增加了一些进一步的优化和简化。

在上ZMM寄存器中缓存

AVX2版本传入一个cache8内存块(约0.5 KB),用于临时存储中间结果,在ROUND1期间其间将一直使用ROUND2到to ROUND4

由于AVX512的寄存器数量增加了一倍(32个ZMM寄存器与16个YMM寄存器相比),因此可以使用高16个ZMM寄存器将中间状态保留在CPU上。因此,无需将相应的内容cache16传入AVX512块功能。

使用64位指针直接加载

AVX2使用VPGATHERDD指令(用于YMM)使用(8个独立的)32位偏移量并行加载8个通道。由于无法控制传递给(Go)blockMd5函数的8个条带如何布置到内存中,因此无法为所有8个条带派生“基本”地址和相应的偏移量(全部在32位内) 。

因此,AVX2版本使用临时缓冲区从所有8个inut切片中收集要散列的字节切片,并将此缓冲区以及(固定的)32位偏移量传递到汇编代码中。

对于AVX512版本,不需要此临时缓冲区,因为AVX512代码使用一对VPGATHERQD指令直接取消引用64位指针(从已初始化为零的基址地址)。

请注意,需要两个加载(收集)指令,因为AVX512版本并行处理16通道,总共需要加载16倍64位= 1024位。一个简单的VALIGNDVPORD随后用于将下半部分和上半部分合并为一个ZMM寄存器(包含16个通道的32位DWORDS)。

遮罩支持

由于指针是直接从Go切片中传入的,因此我们需要防止NULL指针。为此,在AVX512汇编代码中传递了16位掩码,在VPGATHERQD指令期间使用该16位掩码来掩盖可能会导致段冲突的通道。

运作方式

为了使操作尽可能简单,有一个“服务器”可以协调各个哈希状态并在输入新数据时对其进行更新。可以将其可视化如下:


server-architecture-1.png


只要有可用数据,服务器将收集多达16个散列的数据并并行处理所有16个通道。这意味着,如果有16个哈希具有可用数据,则所有车道将被填充。但是,由于可能并非如此,因此服务器将填充较少的车道并进行一轮回合。车道也可以部分填充。


server-lanes-example-2.png


在这个(简化的)示例中,上面的4条车道已满,部分2条车道已满,最后2条车道为空。黑色区域将简单地从结果中屏蔽掉并被忽略(请注意,实际实现中每个服务器使用16条通道)。

开源的

源代码是在MIT许可下开源的,可在github中的md5-simd存储库中找到试一下,我们欢迎您提供任何反馈。


上一篇 下一篇