rep stosb指令如何比等效循环执行得更快?

Pro*_*ala 13 optimization performance x86 assembly micro-optimization

指令如何rep stosb比这段代码执行得更快?

    Clear: mov byte [edi],AL       ; Write the value in AL to memory
           inc edi                 ; Bump EDI to next byte in the buffer
           dec ecx                 ; Decrement ECX by one position
           jnz Clear               ; And loop again until ECX is 0
Run Code Online (Sandbox Code Playgroud)

在所有现代CPU上都能保证这一点吗?我是否应该总是喜欢使用rep stosb而不是手动编写循环?

Pet*_*des 23

在现代CPU中,rep stosb's和rep movsb's'的微编码实现实际上使用宽度大于1B的存储,因此它可以比每个时钟一个字节快得多.

(注意这只适用于stos和movs,而不是repe cmpsb或者repne scasb.不幸的是,它们仍然很慢,就像在Skylake上每个字节最多2个周期一样,vpcmpeqb对于实现memcmp或memchr而言,这与AVX2相比是可悲的.请参阅https:// agner .org/optimize /用于指令表,以及x86标签wiki其他perf链接)


它具有显着的启动开销,但对于大型memset/memcpy来说也很好.(有关何时使用repnz scasb与小缓冲区的矢量化循环的讨论,请参阅英特尔/ AMD的优化手册.)但是,如果没有ERMSB功能,strlen则针对中到小的存储器进行调整,并且它是最佳使用rep stos/movsrep stos(如果您不是打算使用SIMD循环).

当使用调试器单步执行时,rep stosb只进行一次迭代(ecx/rcx的一次递减),因此微代码实现永远不会进行.不要让这种欺骗你以为这一切都可以做.

请参阅REP做什么设置?有关英特尔P6/SnB系列微体系结构如何实现的一些细节rep stosd.

有关内存带宽注意事项的memcpy,请参阅增强型REP MOVSBrep stosq,以及具有ERMSB功能的Intel CPU上的SSE或AVX环路.(特别注意,多核Xeon CPU只能通过一个线程来满足DRAM带宽,因为一次有多少缓存未命中限,以及RFO与非RFO存储协议.)


一个现代的英特尔CPU应该在每个时钟的一次迭代中运行问题中的asm循环,但AMD推土机系列核心可能甚至不能每个时钟管理一个存储.(处理inc/dec /分支指令的两个整数执行端口的瓶颈.如果循环条件是cmp/jcc rep stos,则AMD核心可以对比较和分支进行宏融合.)


所谓的快速字符串操作(rep movs以及rep movsbIntel P6和SnB系列CPU)的一个主要特点是,当存储到以前未缓存的内存时,它们会避免读取所有权缓存一致性流量.所以就像使用NT存储来写整个缓存行,但仍然强烈订购.(ERMSB功能确实使用弱排序的存储).

IDK对AMD的实施有多好.


(还有一个更正:我之前曾说过,英特尔SnB只能处理每2个时钟一个的分支吞吐量,但事实上它可以在每个时钟的一次迭代中运行微小的循环.)

查看从标记wiki 链接的优化资源(尤其是Agner Fog的指南).


英特尔IvyBridge以及后来的ERMSB,允许edirep movs使用弱排序的商店(如 rep stos),允许商店承诺缓存无序.如果并非所有目标在L1缓存中已经很热,则这是一个优势.我相信,从文档的措辞来看,在快速字符串操作结束时存在隐含的内存障碍,因此任何重新排序仅在字符串op创建的存储之间可见,而不是在它与其他存储之间.即你还不需要rep stos[b/w/d/q] 之后 rep movs[b/w/d/q].

因此,对于Intel IvB及更高版本上的大型对齐缓冲区,movnt实现sfence可以胜过任何其他实现.使用rep movs存储(不将数据保留在缓存中)的应该也接近于使主存储器写入带宽饱和,但实际上可能并不完全跟上.请参阅评论以进行讨论,但我无法找到任何数字.

对于小缓冲区,不同的方法具有非常不同的开销量.微型标记可以使SSE/AVX复制循环看起来比它们更好,因为每次执行具有相同大小和对齐的副本可以避免启动/清除代码中的分支错误预测.IIRC,建议在Intel CPU(非rep stos)上使用128B以下的副本进行矢量化循环.阈值可能高于该阈值,具体取决于CPU和周围代码.

英特尔的优化手册也讨论了不同memcpy实现的开销,并且memset对于未对齐有较大的惩罚movnt.


有关实际操作的更多信息,请参阅优化的memset/memcpy实现的代码.(例如Agner Fog的图书馆).

  • 从我指向你的链接我写道:"你的意思是我可以为我的1 GB案例做得比movntdqa更好吗?" 然后Stephen Canon写道:"是的,在Ivybridge和Haswell流式传输到内存时,rep movsb比movntdqa要快得多(但请注意,Ivybridge之前的速度很慢!)" (2认同)

Max*_*tin 6

如果您的 CPU 具有 CPUID ERMSB 位,则rep movsbrep stosb命令的执行方式与旧处理器不同。

请参阅英特尔优化参考手册,第 3.7.6 节增强型 REP MOVSB 和 REP STOSB 操作 (ERMSB)。

手册和我的测试都表明,在rep stosbSkylake 微架构的 32 位 CPU 上与通用 32 位寄存器移动相比的优势仅出现在大于 128 字节的大内存块上。在较小的块上,例如 5 字节,您显示的代码 ( mov byte [edi],al; inc edi; dec ecx; jnz Clear) 会快得多,因为 的启动成本rep stosb非常高 - 大约 35 个周期。

为了rep stosb在具有 CPUID ERMSB 位的新处理器上获得优势,应满足以下条件:

  • 目标缓冲区必须与 16 字节边界对齐;
  • 如果长度是64的倍数,则可以产生更高的性能;
  • 方向位应设置为“向前”(由cld指令设置)。

根据英特尔优化手册,当内存块的长度至少为 128 字节时,ERMSB 通过 Skylake 上的常规寄存器开始优于内存存储,因为,正如我所写的,ERMSB 中有很高的内部启动 - 大约 35 个周期。当长度超过 2048 字节时,ERMSB 开始明显优于其他方法,包括 AVX 复制和填充。但是,这主要适用于 Skylake 微架构,其他 CPU 微架构不一定如此。

在某些处理器上,但在其他处理器上,当目标缓冲区是 16 字节对齐时,使用 ERMSB 的 REP STOSB 可以比 SIMD 方法(即,使用 MMX 或 SSE 寄存器时)执行得更好。当目标缓冲区未对齐时,对于基于英特尔微架构代号 Ivy Bridge 的处理器,使用 ERMSB 的 memset() 性能相对于对齐情况会降低约 20%。相比之下,根据英特尔的优化手册,当目的地未对齐时,REP STOSB 的 SIMD 实现将经历更可忽略不计的降级。

基准

我做了一些基准测试。代码多次填充同一个固定大小的缓冲区,因此缓冲区保留在缓存中(L1、L2、L3),具体取决于缓冲区的大小。迭代次数如总执行时间应约为两秒。

天湖

在英特尔酷睿 i5 6600 处理器上,于 2015 年 9 月发布,基于 Skylake-S 四核微架构(3.30 GHz 基频,3.90 GHz 最大睿频),具有 4 x 32K L1 缓存、4 x 256K L2 缓存和 6MB L3 缓存,我可以在具有 32K 块的 REP STOSB 上获得 ~100 GB/秒。

使用的 memset() 实现REP STOSB

  • 1297920000 块 16 字节:13.6022 秒 1455.9909 兆字节/秒
  • 0648960000 块 32 字节:06.7840 秒 2919.3058 兆字节/秒
  • 1622400000 块 64 字节:16.9762 秒 5833.0883 兆字节/秒
  • 817587402 块 127 字节:8.5698 秒 11554.8914 兆字节/秒
  • 811200000 块 128 字节:8.5197 秒 11622.9306 兆字节/秒
  • 804911628 块 129 字节:9.1513 秒 10820.6427 兆字节/秒
  • 407190588 块 255 字节:5.4656 秒 18117.7029 兆字节/秒
  • 405600000 块 256 字节:5.0314 秒 19681.1544 兆字节/秒
  • 202800000 块 512 字节:2.7403 秒 36135.8273 兆字节/秒
  • 101400000 块 1024 字节:1.6704 秒 59279.5229 兆字节/秒
  • 3168750 个 32768 字节的块:0.9525 秒103957.8488兆字节/秒 (!),即 10 GB/秒
  • 2028000 个 51200 字节的块:1.5321 秒 64633.5697 兆字节/秒
  • 413878 块 250880 字节:1.7737 秒 55828.1341 兆字节/秒
  • 19805 块 5242880 字节:2.6009 秒 38073.0694 兆字节/秒

使用的 memset() 实现MOVDQA [RCX],XMM0

  • 1297920000 块 16 字节:3.5795 秒 5532.7798 兆字节/秒
  • 0648960000 块 32 字节:5.5538 秒 3565.9727 兆字节/秒
  • 1622400000 块 64 字节:15.7489 秒 6287.6436 兆字节/秒
  • 817587402 块 127 字节:9.6637 秒 10246.9173 兆字节/秒
  • 811200000 块 128 字节:9.6236 秒 10289.6215 兆字节/秒
  • 804911628 块 129 字节:9.4852 秒 10439.7473 兆字节/秒
  • 407190588 块 255 字节:6.6156 秒 14968.1754 兆字节/秒
  • 405600000 块 256 字节:6.6437 秒 14904.9230 兆字节/秒
  • 202800000 块 512 字节:5.0695 秒 19533.2299 兆字节/秒
  • 101400000 个 1024 字节的块:4.3506 秒 22761.0460 兆字节/秒
  • 3168750 块 32768 字节:3.7269 秒26569.8145兆字节/秒(!),即 26 GB/秒
  • 2028000 块 51200 字节:4.0538 秒 24427.4096 兆字节/秒
  • 413878 块 250880 字节:3.9936 秒 24795.5548 兆字节/秒
  • 19805 块 5242880 字节:4.5892 秒 21577.7860 兆字节/秒

请注意,使用 XMM0 寄存器的缺点是它是 128 位(16 字节),而我可以使用 256 位(32 字节)的 YMM0 寄存器。无论如何,stosb使用非 RFO 协议。自 1996 年的 Pentium Pro (P6) 以来,Intel x86 就有了“快速字符串”。P6 快速字符串采用 REP MOVSB 和更大的格式,并通过 64 位微码加载和存储以及非 RFO 缓存协议实现它们。与 Ivy Bridge 中的 ERMSB 不同,它们没有违反内存顺序。有关更多详细信息和来源,请参阅/sf/answers/2373412121/

无论如何,即使你只比较我提供的两种方法,尽管第二种方法远非理想,如你所见,在 64 位块rep stosb上速度较慢,但​​从 128 字节块rep stosb开始,开始优于其他方法,并且从 512 字节和更长的块开始,差异非常显着,前提是您在缓存中一次又一次地清除相同的内存块。

因此,对于REP STOSB,最大速度为每秒 103957(十万三千九百五十七)兆字节,而使用 MOVDQA [RCX],XMM0 时仅为 26569(二万六千五百六十九)二万六千五百六十九。

如您所见,最高性能出现在 32K 块上,这相当于我进行基准测试的 CPU 的 32K 一级缓存。

冰湖

REP STOSB 与 AVX-512 商店

我还在 2019 年 8 月发布的 Intel i7 1065G7 CPU(Ice Lake/Sunny Cove 微架构)上进行了测试,基本频率:1.3 GHz,最大睿频频率 3.90 GHz。它支持 AVX512F 指令集。它具有4 x 32K L1指令缓存和4 x 48K数据缓存、4x512K L2缓存和8 MB L3缓存。

目的地对齐

在由 归零的 32K 块上rep stosb,性能从目标未对齐 1 字节(例如 $7FF4FDCFFFFF)的 175231 MB/s 快速上升到 64 字节对齐的 219464 MB/s(例如 $7FF4FDCFFFC0),然后逐渐上升到 222424 MB /sec 用于按 256 字节对齐的目标(对齐到 256 字节,即 $7FF4FDCFFF00)。之后,速度没有上升,即使目的地对齐了 32KB(例如 $7FF4FDD00000),仍然是 224850 MB/秒。

rep stosb和之间的速度没有差异rep stosq

在按 32K 对齐的缓冲区上,AVX-512 存储的速度与 for 完全相同rep stosb,for 循环从循环中的 2 个存储开始(227777 MB/秒),并且为 4 个甚至 16 个存储展开的循环没有增长。但是,对于只有 1 个存储的循环,速度稍低 - 203145 MB/秒。

但是,如果目标缓冲区仅错位 1 个字节,则 AVX512 存储的速度会急剧下降,即下降 2 倍以上,达到 93811 MB/秒,而rep stosb类似的缓冲区则为 175231 MB/秒。

缓冲区大小

  • 对于 1K(1024 字节)块,AVX-512 (205039 KB/s) 比rep stosb(71817 MB/s)快 3 倍
  • 对于 512 字节的块,AVX-512 的性能始终与较大的块类型 (194181 MB/s) 相同,而rep stosb下降到 38682 MB/s。在这种块类型中,差异是 AVX-512 的 5 倍。
  • 对于 2K (2048) 块,AVX-512 的速度为 210696 MB/s,而rep stosb它的速度为 123207 MB/s,几乎慢了两倍。同样,rep stosb和之间没有区别rep stosq
  • 对于 4K (4096) 块,AVX-512 有 225179 MB/s,而 rep stosb:180384 MB/s,几乎赶上了。
  • 对于 8K (8192) 块,AVX-512 为 222259 MB/s,而 rep stosb:194358 MB/s,关闭!
  • 对于 32K (32768) 个块,AVX-512 有228432 MB/srep stosb220515 MB/s - 现在终于!我们正在接近我的 CPU 的 L0 数据缓存大小 - 48Kb!这是每秒 220 GB!
  • 对于 64K (65536) 块,AVX-512 有 61405 MB/s,rep stosb:70395 MB/s!
  • 当我们用完 L0 缓存时,下降幅度如此之大!而且,很明显,从这一点rep stosb开始,其表现开始优于 AVX-512 商店。
  • 现在让我们检查 L1 缓存大小。对于 512K 块,AVX-512 达到 62907 MB/s,rep stosb达到 70653 MB/s。这就是rep stosb开始优于 AVX-512 的地方。差异尚不显着,但缓冲区越大,差异越大。
  • 现在让我们使用 1GB (1073741824) 的巨大缓冲区。使用 AVX-512,速度为 14319 MB/s,rep stosb为 27412 MB/s,即是 AVX-512 的两倍!

我还尝试使用非时间指令来填充 32K 缓冲区vmovntdq [rcx], zmm31,但性能比仅vmovdqa64 [rcx], zmm31. vmovntdq填充内存缓冲区时如何利用?是否应该有一些特定大小的缓冲区才能vmovntdq利用?

此外,如果目标缓冲区至少对齐 64 位,则vmovdqa64vmovdqu64. 因此,我确实有一个问题:vmovdqa64当我们有时,指令是否只用于调试和安全vmovdqu64

图 1:迭代存储到同一缓冲区的速度,MB/s

block     AVX   stosb
-----   -----  ------
 0.5K  194181   38682
   1K  205039  205039
   2K  210696  123207
   4K  225179  180384
   8K  222259  194358 
  32K  228432  220515 
  64K   61405   70395 
 512K   62907   70653 
   1G   14319   27412
Run Code Online (Sandbox Code Playgroud)

多次清除缓存内同一个内存块的性能总结

rep stosb在 Ice Lake CPU 上的性能开始优于 AVX-512 存储,仅用于重复清除大于 L0 缓存大小的相同内存缓冲区,即 Intel i7 1065G7 CPU 上的 48K。在小内存缓冲区上,AVX-512 存储要快得多:1KB - 快 3 倍,512 字节 - 快 5 倍。

但是,AVX-512 存储容易受到未对齐的缓冲区的影响,而对未对齐的rep stosb情况不那么敏感。

因此,我发现rep stosb仅在超过 L0 数据缓存大小或 48KB(如 Intel i7 1065G7 CPU 的情况下)的缓冲区上才开始优于 AVX-512 存储。这个结论至少在 Ice Lake CPU 上是有效的。早期的英特尔建议字符串复制开始优于 AVX 复制从 2KB 缓冲区开始,也应该针对较新的微架构重新测试。

清除不同的内存缓冲区,每个仅一次

我之前的基准测试连续多次填充相同的缓冲区。更好的基准可能是分配许多不同的缓冲区,并且每个缓冲区只填充一次,以免干扰缓存。

在这种情况下,两者之间没有太大区别 rep stosb和 AVX-512 商店。唯一的区别是在 Windows 10 64 位下,所有数据都没有接近物理内存限制。在以下基准测试中,总数据大小低于 8 GB,总物理内存为 16 GB。当我分配大约 12 GB 时,无论使用哪种方法,性能都会下降大约 20 倍。Windows 开始丢弃清除的内存页,并且可能在内存即将满时做了一些其他的事情。i7 1065G7 CPU 上 8MB 的 L3 缓存大小似乎与基准测试无关。重要的是您不必接近物理内存限制,这取决于您的操作系统如何处理此类情况。正如我所说,在 Windows 10 下,如果我只占用一半的物理内存,那没问题,但是我占用了 3/4 的可用内存,我的基准测试速度慢了 20 倍。我没有' 甚至不要尝试超过 3/4。正如我所说,总内存大小为 16 GB。根据任务管理器的说法,可用容量为 12 GB。

这是在总内存为 16 GB 的单线程 i7 1065G7 CPU 上用零(以 MB/秒为单位)填充总计 8 GB 的各种内存块的速度基准。“AVX”是指“AVX-512”普通商店,“s​​tosb”是指“rep stosb”。

图 2:存储到多个缓冲区的速度,每个缓冲区,MB/s

block    AVX  stosb
-----   ----   ----
 0.5K   3641   2759
   1K   4709   3963
   2K  12133  13163
   4K   8239  10295
   8K   3534   4675
  16K   3396   3242
  32K   3738   3581
  64K   2953   3006
 128K   3150   2857
 256K   3773   3914
 512K   3204   3680
1024K   3897   4593
2048K   4379   3234
4096K   3568   4970
8192K   4477   5339
Run Code Online (Sandbox Code Playgroud)

关于清除缓存中的内存的结论

如果您的内存不存在于缓存中,rep stosb那么当您需要用零填充内存时,AVX-512 存储的性能大致相同。重要的是缓存,而不是这两种方法之间的选择。

使用非临时存储清除不在缓存中的内存

我正在将 6-10 GB 的内存归零,这些内存由一系列按 64 字节对齐的缓冲区划分。没有缓冲区被清零两次。较小的缓冲区有一些开销,而且我只有 16 GB 的物理内存,所以我用较小的缓冲区将更少的内存归零。我对从 256 字节到每个缓冲区 8 GB 的缓冲区进行了各种测试。我采用了 3 种不同的方法:

  1. 正常的 AVX-512 存储方式vmovdqa64 [rcx+imm], zmm31(循环 4 个存储然后比较计数器);
  2. 非临时 AVX-512 存储vmovntdq [rcx+imm], zmm31(4个存储的相同循环);
  3. rep stosb.

对于小缓冲区,普通的 AVX-512 商店是赢家。然后,从4KB开始,非临时存储领先,但rep stosb仍然落后。

然后,从 256KB 开始,rep stosb性能优于 AVX-512,但不是非临时存储,此后情况没有改变。获胜者是非临时 AVX-512 商店,然后是rep stosb普通的 AVX-512 商店。

图 3. 通过三种不同方法存储到多个缓冲区的速度(每个缓冲区一次,MB/s):正常 AVX-512 存储、非临时 AVX-512 存储和 rep stosb。

Zeroized 6.67 GB: 27962026 blocks of 256 bytes for 2.90s, 2.30 GB/s by normal AVX-512 store
Zeroized 6.67 GB: 27962026 blocks of 256 bytes for 3.05s, 2.18 GB/s by nontemporal AVX-512 store
Zeroized 6.67 GB: 27962026 blocks of 256 bytes for 3.05s, 2.18 GB/s by rep stosb

Zeroized 8.00 GB: 16777216 blocks of 512 bytes for 3.06s, 2.62 GB/s by normal AVX-512 store
Zeroized 8.00 GB: 16777216 blocks of 512 bytes for 3.02s, 2.65 GB/s by nontemporal AVX-512 store
Zeroized 8.00 GB: 16777216 blocks of 512 bytes for 3.66s, 2.18 GB/s by rep stosb

Zeroized 8.89 GB: 9320675 blocks of 1 KB for 3.10s, 2.87 GB/s by normal AVX-512 store
Zeroized 8.89 GB: 9320675 blocks of 1 KB for 3.37s, 2.64 GB/s by nontemporal AVX-512 store
Zeroized 8.89 GB: 9320675 blocks of 1 KB for 4.85s, 1.83 GB/s by rep stosb

Zeroized 9.41 GB: 4934475 blocks of 2 KB for 3.45s, 2.73 GB/s by normal AVX-512 store
Zeroized 9.41 GB: 4934475 blocks of 2 KB for 3.79s, 2.48 GB/s by nontemporal AVX-512 store
Zeroized 9.41 GB: 4934475 blocks of 2 KB for 4.83s, 1.95 GB/s by rep stosb

Zeroized 9.70 GB: 2542002 blocks of 4 KB for 4.40s, 2.20 GB/s by normal AVX-512 store
Zeroized 9.70 GB: 2542002 blocks of 4 KB for 3.46s, 2.81 GB/s by nontemporal AVX-512 store
Zeroized 9.70 GB: 2542002 blocks of 4 KB for 4.40s, 2.20 GB/s by rep stosb

Zeroized 9.85 GB: 1290555 blocks of 8 KB for 3.24s, 3.04 GB/s by normal AVX-512 store
Zeroized 9.85 GB: 1290555 blocks of 8 KB for 2.65s, 3.71 GB/s by nontemporal AVX-512 store
Zeroized 9.85 GB: 1290555 blocks of 8 KB for 3.35s, 2.94 GB/s by rep stosb

Zeroized 9.92 GB: 650279 blocks of 16 KB for 3.37s, 2.94 GB/s by normal AVX-512 store
Zeroized 9.92 GB: 650279 blocks of 16 KB for 2.73s, 3.63 GB/s by nontemporal AVX-512 store
Zeroized 9.92 GB: 650279 blocks of 16 KB for 3.53s, 2.81 GB/s by rep stosb

Zeroized 9.96 GB: 326404 blocks of 32 KB for 3.19s, 3.12 GB/s by normal AVX-512 store
Zeroized 9.96 GB: 326404 blocks of 32 KB for 2.64s, 3.77 GB/s by nontemporal AVX-512 store
Zeroized 9.96 GB: 326404 blocks of 32 KB for 3.44s, 2.90 GB/s by rep stosb

Zeroized 9.98 GB: 163520 blocks of 64 KB for 3.08s, 3.24 GB/s by normal AVX-512 store
Zeroized 9.98 GB: 163520 blocks of 64 KB for 2.58s, 3.86 GB/s by nontemporal AVX-512 store
Zeroized 9.98 GB: 163520 blocks of 64 KB for 3.29s, 3.03 GB/s by rep stosb

Zeroized 9.99 GB: 81840 blocks of 128 KB for 3.22s, 3.10 GB/s by normal AVX-512 store
Zeroized 9.99 GB: 81840 blocks of 128 KB for 2.49s, 4.01 GB/s by nontemporal AVX-512 store
Zeroized 9.99 GB: 81840 blocks of 128 KB for 3.26s, 3.07 GB/s by rep stosb

Zeroized 10.00 GB: 40940 blocks of 256 KB for 2.52s, 3.97 GB/s by normal AVX-512 store
Zeroized 10.00 GB: 40940 blocks of 256 KB for 1.98s, 5.06 GB/s by nontemporal AVX-512 store
Zeroized 10.00 GB: 40940 blocks of 256 KB for 2.43s, 4.11 GB/s by rep stosb

Zeroized 10.00 GB: 20475 blocks of 512 KB for 2.15s, 4.65 GB/s by normal AVX-512 store
Zeroized 10.00 GB: 20475 blocks of 512 KB for 1.70s, 5.87 GB/s by nontemporal AVX-512 store
Zeroized 10.00 GB: 20475 blocks of 512 KB for 1.81s, 5.53 GB/s by rep stosb

Zeroized 10.00 GB: 10238 blocks of 1 MB for 2.18s, 4.59 GB/s by normal AVX-512 store
Zeroized 10.00 GB: 10238 blocks of 1 MB for 1.50s, 6.68 GB/s by nontemporal AVX-512 store
Zeroized 10.00 GB: 10238 blocks of 1 MB for 1.63s, 6.13 GB/s by rep stosb

Zeroized 10.00 GB: 5119 blocks of 2 MB for 2.02s, 4.96 GB/s by normal AVX-512 store
Zeroized 10.00 GB: 5119 blocks of 2 MB for 1.59s, 6.30 GB/s by nontemporal AVX-512 store
Zeroized 10.00 GB: 5119 blocks of 2 MB for 1.54s, 6.50 GB/s by rep stosb

Zeroized 10.00 GB: 2559 blocks of 4 MB for 1.90s, 5.26 GB/s by normal AVX-512 store
Zeroized 10.00 GB: 2559 blocks of 4 MB for 1.37s, 7.29 GB/s by nontemporal AVX-512 store
Zeroized 10.00 GB: 2559 blocks of 4 MB for 1.47s, 6.81 GB/s by rep stosb

Zeroized 9.99 GB: 1279 blocks of 8 MB for 2.04s, 4.90 GB/s by normal AVX-512 store
Zeroized 9.99 GB: 1279 blocks of 8 MB for 1.51s, 6.63 GB/s by nontemporal AVX-512 store
Zeroized 9.99 GB: 1279 blocks of 8 MB for 1.56s, 6.41 GB/s by rep stosb

Zeroized 9.98 GB: 639 blocks of 16 MB for 1.93s, 5.18 GB/s by normal AVX-512 store
Zeroized 9.98 GB: 639 blocks of 16 MB for 1.37s, 7.30 GB/s by nontemporal AVX-512 store
Zeroized 9.98 GB: 639 blocks of 16 MB for 1.45s, 6.89 GB/s by rep stosb

Zeroized 9.97 GB: 319 blocks of 32 MB for 1.95s, 5.11 GB/s by normal AVX-512 store
Zeroized 9.97 GB: 319 blocks of 32 MB for 1.41s, 7.06 GB/s by nontemporal AVX-512 store
Zeroized 9.97 GB: 319 blocks of 32 MB for 1.42s, 7.02 GB/s by rep stosb

Zeroized 9.94 GB: 159 blocks of 64 MB for 1.85s, 5.38 GB/s by normal AVX-512 store
Zeroized 9.94 GB: 159 blocks of 64 MB for 1.33s, 7.47 GB/s by nontemporal AVX-512 store
Zeroized 9.94 GB: 159 blocks of 64 MB for 1.40s, 7.09 GB/s by rep stosb

Zeroized 9.88 GB: 79 blocks of 128 MB for 1.99s, 4.96 GB/s by normal AVX-512 store
Zeroized 9.88 GB: 79 blocks of 128 MB for 1.42s, 6.97 GB/s by nontemporal AVX-512 store
Zeroized 9.88 GB: 79 blocks of 128 MB for 1.55s, 6.37 GB/s by rep stosb

Zeroized 9.75 GB: 39 blocks of 256 MB for 1.83s, 5.32 GB/s by normal AVX-512 store
Zeroized 9.75 GB: 39 blocks of 256 MB for 1.32s, 7.38 GB/s by nontemporal AVX-512 store
Zeroized 9.75 GB: 39 blocks of 256 MB for 1.64s, 5.93 GB/s by rep stosb

Zeroized 9.50 GB: 19 blocks of 512 MB for 1.89s, 5.02 GB/s by normal AVX-512 store
Zeroized 9.50 GB: 19 blocks of 512 MB for 1.31s, 7.27 GB/s by nontemporal AVX-512 store
Zeroized 9.50 GB: 19 blocks of 512 MB for 1.42s, 6.71 GB/s by rep stosb

Zeroized 9.00 GB: 9 blocks of 1 GB for 1.76s, 5.13 GB/s by normal AVX-512 store
Zeroized 9.00 GB: 9 blocks of 1 GB for 1.26s, 7.12 GB/s by nontemporal AVX-512 store
Zeroized 9.00 GB: 9 blocks of 1 GB for 1.29s, 7.00 GB/s by rep stosb

Zeroized 8.00 GB: 4 blocks of 2 GB for 1.48s, 5.42 GB/s by normal AVX-512 store
Zeroized 8.00 GB: 4 blocks of 2 GB for 1.07s, 7.49 GB/s by nontemporal AVX-512 store
Zeroized 8.00 GB: 4 blocks of 2 GB for 1.15s, 6.94 GB/s by rep stosb

Zeroized 8.00 GB: 2 blocks of 4 GB for 1.48s, 5.40 GB/s by normal AVX-512 store
Zeroized 8.00 GB: 2 blocks of 4 GB for 1.08s, 7.40 GB/s by nontemporal AVX-512 store
Zeroized 8.00 GB: 2 blocks of 4 GB for 1.14s, 7.00 GB/s by rep stosb

Zeroized 8.00 GB: 1 blocks of 8 GB for 1.50s, 5.35 GB/s by normal AVX-512 store
Zeroized 8.00 GB: 1 blocks of 8 GB for 1.07s, 7.47 GB/s by nontemporal AVX-512 store
Zeroized 8.00 GB: 1 blocks of 8 GB for 1.21s, 6.63 GB/s by rep stosb
Run Code Online (Sandbox Code Playgroud)

避免 AVX-SSE 转换惩罚

对于所有 AVX-512 代码,我都使用了ZMM31寄存器,因为 SSE 寄存器从 0 到 15,所以 AVX-512 寄存器 16 到 31 没有对应的 SSE,因此不会产生转换损失。

  • *比其他方法* - 嗯,与您测试的*一个*其他方法相比,该方法显然每隔一个时钟周期只存储 16 个字节。(~104GB/s 是我假设在 ~3.3GHz CPU 上为 32B/​​c。)手动 memset 循环应该在 L1d 缓存中命中每个周期实现一次存储,因此您的测试循环使 SSE 看起来很糟糕。如果您使用了 AVX,您应该能够匹配中小型块的 memset。(缓存命中,我们不想使用 movnt 或任何无 RFO 协议的rep stos 可能使用的情况。) (2认同)