Pentium 及 MMX 代码的优化

内存优化

[第五节:高速缓存优化][全篇结束]


6.1 对部分内部访问

  MMXTM寄存器可以使你在不阻塞处理器的情况下移动大数据. 对8位, 16位, 或32位长的单个数组值的读取, 可考虑用对单个四字数据的读取来替代, 然后增大对应的结构或数组的指针.

  任何被 MMXTM 指令处理的数据必须按下列某一种方式读取:

  全部的 SIMD数据应由可存贮64位操作的 MMXTM 指令存贮 (如 MOVQ m64, MM0).

  这些建议有两个目的: 第一, 使用四字数据块来读写 SIMD 数据更为效. 第二, 避免将对 SIMD的8位, 16位, 32位读写操作与 MMXTM对64位读写操作混淆. 这些将防止下列两种情况发生, a)对同一内存区域先大数据量存贮然后小数据量读取, b), 对同一内存区域先小数据量存贮, 再大数据量读取. 动态执行处理器将在上述情况下阻塞(参见1.1的规则表)。

  考虑下面的例子, 在第一种情况中, 在一系列小数据存贮后有一条对相同内存区的大读取 (开始于内存地址"Mem"), 这个"大" 读取将在这种情况被阻塞:


    MOV  mem,   eax  ; 存贮双字到地址"mem"
    MOV  mem+4, ebx  ; 存贮双字到地址"mem+4"
         :
         :
    MOVQ mm0,  mem  ; 在地址"mem" 取四字数据, 阻塞

  MOVQ必须等待它所要求的数据全被写到内存后才执行. 这种阻塞也发生在其它数据类型中(如, 先以字节或字存贮, 然后再对同一内存区按字或双字读). 如按下述所示改变代码顺序, 在处理器访问数据时就不会发生迟延:


    MOVD   mm1, ebx ;在将数据存贮到内存前, 先将它变成四字数据
    MOVD   mm2, eax
    PSLLQ  mm1, 32
    POR    mm1, mm2
    MOVQ   mem, mm1 ; 按4字存贮 SIMD变量到"mem"
           :
           :
    MOVQ   mm0, mem ; 取四字 SIMD变量 "mem", 无阻塞

  在第二种情况中, 在一个大存贮后有一系列对相同内存区的小读取 (开始的内存地址"mem"). 这个"小" 读将在这种情况下被阻塞.


    MOVQ  mem, mm0  ; 在地址 "mem" 中存入四字数据
          :
          :
    MOV   bx, mem+2 ; 在地址 "mem+2" 读取字数据, 阻塞
    MOV   cx, mem+4 ; 在地址 "mem, 4" 读取字数据, 阻塞

  对字数据的读取必须等待四字数据存贮完, 使之可以访问所要求的数据. 这种阻塞也发生在其它类型的数据上 (如, 先按双字或字存贮再按字或字节从同一内存地址中读取). 如按下述所示, 改变代码顺序, 在处理器访问数据时将不产生迟延.


    MOVQ  mem, mm0  ; 在地址 "mem" 存入四字数据
          :
          :
    MOVQ  mm1, mem  ; 在地址 "mem" 读取四字数据
    MOVD  eax, mm1  ; 从 MMXTM 寄存器中转移 "mem+2"
                    ; 非内存
    PSRLQ mm1, 32
    SHR   eax, 16
    MOVQ  ebx, mm1  ; 从 MMXTM 寄存器中转移 "mem+4"
                    ; 非内存
    AND   ebx, 0fffh

  通常这些改变将为所要求的操作增加执行的指令数. 对于动态执行(P6-系列)处理器来说, 增加指令数所造成性能损失大于处理器本身的优越性. 对奔腾处理器来说, 由于上述改变不能带来好处, 所以增加指令数对性能有消极影响. 因此, 小心有效地利用这些转移代码, 能使对奔腾处理器性能的负面影响达到最小.

6.2 增加内存填充和视频填充的带宽

  了解内存是如何被访问或被填充是很有好处的. 一个内存对内存的填充(如一个内存到视频的填充)被定义为: 将32位 (高速缓存线)数据从内存读取后, 立即存贮回内存(如视频帧缓存). 下列准则可使顺序内存填充(视频填充)获得更高的带宽和更短的迟延. 这些建议对所有的具有 MMXTM技术的 Intel体系结构处理器有效, 并适用于读/取操作未命中第二级高速缓存的情况.

6.2.1 内存填充

用 MOVQ指令增加内存带宽

  对任何数值的读取, 都将使整条高速缓存线的数据被调人到在片上高速缓存中. 但用 MOVQ代替32位存贮指令(如MOVD)向内存回存数据, 将使每个内存填写周期减少一半的存贮次数. 对某些基于奔腾处理器的系统, 使用64位存贮指令代替32 位存贮指令将提高30%带宽. 另外, 对于动态执行处理器, 在同时具有用 MOVQ指令进行取和存的操作时, 避免了对部分内存访问.

通过对同一DRAM页读取和存贮来增大内存带宽

  DRAM按页分开(不同于操作系统的页). 一个 DRAM 的页大小是由 DRAM的大小和组成决定的. 通常为几 K字节. 与操作系统的页相似, DRAM页也是顺序安排地址. 对同一 DRAM 页的顺序内存访问, 比对不同 DRAM页的顺序访问迟延短. 在很多系统中, 页未命中(即两次访问不同页)的迟延是内存页命令迟延 (两次访问同一页)的两倍. 因此, 如果内存填充周期中的读取和存贮用同一个 DRAM页, 就可以有效增加内存填充周期的带宽.

用对齐的存贮来增加内存填充的带宽

  未对齐的存贮使对内存的存贮次数增加—倍. Intel强调匹字的存贮要按8字节对齐. 四个对齐的四字数据的存贮, 将导致一整条高速缓存线被写到内存. 如果存贮的四字数据不是按8 字节对齐的, 那么每个 MOVQ存贮指令产生两个32位写操作. 在某些系统中, 未对齐的64位存贮比对齐的64位数据的存贮低20%的带宽.

6.2.2 视频填充

使用64位存贮来增加视频的带宽

  尽管位于处理器与帧缓冲区之间的 PCI总线宽为32位, 但在大多数基于奔腾处理器的系统中, 使用 MOVQ 存贮视频要比用两倍的32位数据存贮视频快. 这种现象的产生, 是由于用四字数据存贮使 PCI写缓冲区的带宽增大造成的.

用对齐的数据存贮来增加视频的带宽

  当发生未对齐数据存贮时, 将使视频带宽急剧下降. 未对齐数据引起两倍的存贮. 另外, 对 PCI总线(对帧缓冲区) 的存贮迟延也将变长. 在 PCI总线上不可能发生淬发的未对齐数据存贮. 在基于奔腾处理器的系统中, 未对齐数据的视频填充带宽比对齐的视频填充带宽低80%.


云风工作室 制作