跳转到主要内容

Instructions of x86

1. 指令类型

1.1. 指令占比概览

1.2. 指令类型及占比

以下是业务中各类指令的占比情况:

指令类别占比 (%)指令类别占比 (%)指令类别占比 (%)
数据传输 (DATAXFER)44.00算术运算 (BINARY)17.00条件跳转 (COND_BR)14.00
逻辑运算 (LOGICAL)7.00移位操作 (SHIFT)4.00其他 (MISC)3.00
空操作 (NOP)2.00出栈 (POP)1.00入栈 (PUSH)1.00
无条件跳转 (UNCOND_BR)1.00函数调用 (CALL)1.00函数返回 (RET)1.00
矢量扩展 (AVX)1.00宽 NOP (WIDENOP)1.00数据预取 (PREFETCH)0.00
条件移动 (CMOV)0.00SSE 指令 (SSE)0.00条件设置 (SETCC)0.00
信号量 (SEMAPHORE)0.00数据转换 (CONVERT)0.00字符串操作 (STRINGOP)0.00
浮点逻辑 (LOGICAL_FP)0.00文本处理 (STTNI)0.00位操作扩展 (BMI1)0.00
循环移位 (ROTATE)0.00广播 (BROADCAST)0.00高级矢量扩展 (AVX2)0.00
前导零计数 (LZCNT)0.00位/字节操作 (BITBYTE)0.00系统调用 (SYSCALL)0.00
FMA 指令 (VFMA)0.00位操作扩展 (BMI2)0.00掩码寄存器 (KMASK)0.00
随机数生成 (RDRAND)0.00

1.3. 高占比指令

DATAXFER (44%) - 数据传输指令:负责在寄存器、内存和堆栈之间传输数据。

  • 典型指令:MOV, LEA, XCHG。

  • 高占比表明代码数据移动频繁,可能涉及大量内存访问或寄存器间数据交换。

BINARY (17%) - 算术运算指令:执行整数加法、减法、乘法、除法等操作。

  • 典型指令:ADD, SUB, MUL, DIV, INC, DEC。

  • 占比较高,说明代码涉及大量数值计算。

COND_BR (14%) - 条件跳转指令:依赖标志寄存器的值决定是否跳转。

  • 典型指令:JZ, JNZ, JE, JNE, JA, JB。

  • 说明代码逻辑较复杂,可能存在大量 if-else 结构或循环控制。

LOGICAL (7%) - 逻辑运算指令

  • 处理位运算,如按位与、或、异或等。

  • 典型指令:AND, OR, XOR, NOT, TEST。

  • 这些指令常用于位运算优化、布尔逻辑计算、掩码操作等。

SHIFT (4%) - 移位指令:进行算术或逻辑移位,常用于高效乘除法、哈希计算或数据对齐。

  • 典型指令:SHL, SHR, SAR, ROL, ROR。

  • 表明代码中有一定的位运算优化需求。

MISC (3%) - 其他类型指令:可能包括系统控制、性能测量等特殊指令。

  • 典型指令:CPUID, RDTSC, HLT, RDPMC。

  • 占比较低,说明这部分功能不是代码核心。

NOP (2%) - 空操作指令:NOP 用于对齐、性能优化、流水线填充等。说明代码可能经过一定程度的指令对齐优化。

POP (1%) / PUSH (1%) - 栈操作指令:PUSH 和 POP 用于函数调用、寄存器保存/恢复。低占比说明代码对栈的依赖较少,可能优化了寄存器使用。

UNCOND_BR (1%) - 无条件跳转指令:直接跳转到指定地址,通常用于循环或异常处理。

  • 典型指令:JMP, CALL, RET。

  • 低占比表明代码结构较线性,不依赖大量跳转。

CALL (1%) / RET (1%) - 函数调用与返回:CALL 进入子程序,RET 退出子程序。低占比可能说明函数调用层次较少,或者有内联优化。

1.4. 极低或未使用指令

AVX (1%) - AVX 指令

  • 先进矢量扩展(Advanced Vector Extensions),用于 SIMD 浮点运算。

  • 典型指令:VADDPS, VMULPS。

  • 低占比可能说明代码未针对 SIMD 优化,或者 AVX 计算需求较少。

WIDENOP (1%) - 宽 NOP 指令:主要用于对齐和优化指令流水线。

PREFETCH (0%) - 数据预取指令:用于提前加载数据到缓存,提高缓存命中率。

  • 典型指令:PREFETCHT0, PREFETCHW。

  • 低占比表明代码没有显式使用数据预取优化。

CMOV (0%) - 条件移动指令:避免分支预测失败,提高性能。

  • 典型指令:CMOVZ, CMOVNZ。

  • 低占比可能说明编译器优化不足,或者代码不依赖分支规避技术。

SSE (0%) - SSE 指令

  • 浮点和 SIMD 计算指令。

  • 典型指令:MOVAPS, ADDPS。

  • 占比 0% 可能说明代码没有使用 SSE 或者使用了更先进的 AVX。

SETCC (0%) - 条件设置指令

• 依据标志寄存器结果,将寄存器设置为 0 或 1。

• 典型指令:SETZ, SETNZ。

• 占比 0% 可能说明代码逻辑不依赖条件标志位存储。

SEMAPHORE (0%) - 信号量操作指令

• 多线程同步控制指令。

• 说明代码基本没有多线程同步需求。

CONVERT (0%) - 数据转换指令

• 例如整数与浮点数转换。

• CVTSI2SS, CVTSS2SI。

  1. STRINGOP (0%) - 字符串操作指令

• REP MOVSB, REP SCASB。

• 说明代码不涉及大规模字符串处理。

  1. LOGICAL_FP (0%) - 浮点逻辑指令

• 处理浮点数的逻辑操作。

  1. STTNI (0%) - 文本处理指令

• 主要用于字符串匹配。

  1. BMI1 (0%) / BMI2 (0%) - 位操作扩展指令

• 主要用于高效位操作。

• 典型指令:PDEP, PEXT。

  1. ROTATE (0%) - 循环移位指令

• 典型指令:ROL, ROR。

• 说明代码不涉及循环移位优化。

  1. BROADCAST (0%) - 广播指令

• 用于 SIMD 数据扩展。

• VBROADCASTSS。

  1. AVX2 (0%) - AVX2 指令

• 比 AVX 更高级的 SIMD 指令。

• VPACKSSWB, VPMADDWD。

  1. LZCNT (0%) - 前导零计数指令

• 计数最高位前的零位数。

  1. BITBYTE (0%) - 位和字节操作指令

• BT, BTS, BTC。

  1. SYSCALL (0%) - 系统调用指令

• SYSCALL。

  1. VFMA (0%) - FMA 指令

• VFMADD132PS,用于 fused multiply-add(FMA)计算。

  1. KMASK (0%) - 掩码寄存器操作

• 主要用于 AVX-512。

  1. RDRAND (0%) - 随机数生成指令

• RDRAND,用于硬件随机数生成。


总结

• 代码主要是 数据传输(44%)+ 计算(17%)+ 逻辑判断(14%),符合通用计算或控制逻辑密集型应用的特点。

• 几乎没有 SIMD(AVX/SSE),说明未做高性能矢量化优化。

无 SYSCALL、多线程同步(SEMAPHORE),可能是单线程用户态应用。

低 PREFETCH,说明内存访问优化较少。

2. REP MOVSB 指令

2.1. REP MOVSB 指令解析

2.1.1. 1. 指令基础简介

  • 全称:Repeat Move String Byte(重复移动字节串)
  • 功能:将内存中一段连续的字节数据(字节串)从源地址逐字节复制到目标地址,通过前缀 REP(重复)实现批量操作。
  • 所属指令集:x86 汇编语言中的串操作指令(String Operations),适用于 Intel 和 AMD 处理器。

2.1.2. 指令格式

  • 汇编语法

    REP MOVSB
  • 操作数

    • 源串地址:由寄存器 ESI(源变址寄存器,默认对应段寄存器 DS)指向。
    • 目标串地址:由寄存器 EDI(目标变址寄存器,默认对应段寄存器 ES)指向。
    • 重复次数:由寄存器 RCX(64 位模式)或 CX(32 位及以下模式)指定,每执行一次 MOVSBRCX/CX 减 1,直到其值为 0 时停止。
  • 方向标志:由标志位 DF(Direction Flag)控制地址变化方向:

    • DF=0(默认):每次操作后 ESI/EDI 递增(适用于正向复制)。
    • DF=1:每次操作后 ESI/EDI 递减(适用于反向复制,如重叠内存区域的复制)。

2.1.3. 3. 执行过程

  1. 初始化
    • 设定 ESI 指向源串首地址(或末地址,取决于 DF),EDI 指向目标串首地址(或末地址),RCX/CX 为待复制的字节数。
  2. 循环执行
    • 每次循环执行一次 MOVSB,将 [ESI] 处的字节数据复制到 [EDI] 处。
    • 根据 DF 更新 ESIEDI+1-1),RCX/CX 减 1。
  3. 终止条件:当 RCX/CX 减为 0 时,停止执行。

2.1.4. 4. 对标志位的影响

  • REP 前缀本身不影响标志位,仅控制循环次数。
  • MOVSB 指令本身也不改变标志位(串操作指令中,仅 SCASBCMPSB 等会影响标志位)。

2.1.5. 5. 增强版本:ERMS(Enhanced REP MOVSB/STOSB)

  • 背景:现代处理器(如 AMD Zen 系列、Intel Xeon 等)对 REP MOVSBREP STOSB(存储字节串)进行了硬件级优化,称为 ERMS(增强型重复串操作)。
  • 优化点
    • 支持批量处理多个字节(而非逐字节操作),减少循环开销。
    • 利用缓存预取技术,提升大块内存复制的效率。
  • 限制
    • 性能与数据大小、内存对齐方式密切相关。例如,在 AMD Zen3+ 处理器上,当数据大小在默认阈值(如 2113 字节到 524288 字节)时,ERMS 可能因对齐问题导致性能低于向量化指令(如使用 SIMD 指令手动实现的内存复制)。

2.1.6. 6. 性能影响因素(结合网页内容)

  1. 数据大小
    • 当数据大小在 rep_movsb_threshold(默认 2113 字节)到 rep_movsb_stop_threshold(Zen3 核心 L2 缓存大小,524288 字节)时,glibc 会启用 ERMS。
    • 超出此范围时,可能切换为向量化指令(如 memcpy 的向量实现)。
  2. 内存对齐
    • 目标地址未对齐(如对齐值为 15 字节)时,ERMS 性能可能大幅下降(网页中数据显示吞吐量从 84GB/s 骤降至 4.4GB/s)。
  3. 可调参数
    • 通过环境变量 GLIBC_TUNABLES 调整阈值,例如:

      GLIBC_TUNABLES=glibc.cpu.x86_rep_movsb_threshold=1000000

      可强制对更大数据使用向量化指令,避免 ERMS 在低对齐场景下的性能问题。

2.1.7. 7. 应用场景

  • 内存复制:用于 memcpy 函数的底层实现(当数据大小适合 ERMS 时)。
  • 系统调用:内核或库函数中批量数据移动(如缓冲区拷贝)。
  • 兼容性:支持跨架构,但优化效果因处理器型号而异(如 Zen3+ 与 Intel Xeon 的 ERMS 实现不同)。

2.1.8. 总结

REP MOVSB 是 x86 架构中高效批量复制字节数据的指令,配合 ERMS 优化可提升大块内存操作性能。但在特定硬件(如 AMD Zen3+)和数据场景(小尺寸、未对齐)下,可能因阈值设置或硬件特性导致性能瓶颈,需通过可调参数或代码优化(如手动向量化)规避。实际开发中,需结合硬件架构和工作负载选择最优策略。

修改历史7 次提交