一、内存理论带宽的计算

内存带宽计算公式:带宽=内存核心频率×内存总线位数×倍增系数。 

    先容我从DDR的技术说起,DDR采用时钟脉冲上升、下降沿各传一次数据,1个时钟信号可以传输2倍于SDRAM的数据,所以又称为双倍速率SDRAM。它的倍增系数就是2。

    DDR2仍然采用时钟脉冲上升、下降支各传一次数据的技术(不是传2次),但是一次预读4bit数据,是DDR一次预读2bit的2倍,因此,它的倍增系数是2X2=4。

    DDR3作为DDR2的升级版,最重要的改变是一次预读8bit,是DDR2的2倍,DDR的4倍,所以,它的倍增系数是2X2X2=8。

    需要补充的一点是,内存有三种不同的频率指标,它们分别是核心频率、时钟频率和有效数据传输频率。

  • 核心频率即为内存Cell阵列(Memory Cell Array)的工作频率,它是内存的真实运行频率;
  • 时钟频率即I/O Buffer(输入/输出缓存)的传输频率;
  • 有效数据传输频率则是指数据传送的频率。

    DDR3内存一次从存储单元预取8Bit的数据,在I/OBuffer(输入/输出缓存)上升和下降中同时传输,因此有效的数据传输频率达到了存储单元核心频率的8倍。同时DDR3内存的时钟频率提高到了存储单元核心的4倍。也就是说DDR3-800内存的核心频率只有100MHz,其I/O频率为400MHz,有效数据传输频率则为800MHz。

    从SDRAM-DDR时代,数据总线位宽时钟没有改变,都为64bit,但是采用双通道技术,可以获得64X2=128bit的位宽。

    下面计算一条标称DDR3 1066的内存条在默认频率下的带宽:

    1066是指有效数据传输频率,除以8才是核心频率。一条内存只用采用单通道模式,位宽为64bit。

    所以内存带宽=(1066/8)×64×8=68224Mbit。

    由此可知,如果内存工作在标称频率的时候,可以直接用标称频率×位宽,简化公式。 再根据8bit(位)=1Byte(字节),得68224/8=8528MByte=8.328125GB。 

    再以两条标称1066超频到1200的DDR3内存,组成双通道后的带宽:超频到1200后,内存核心频率应为1200/8=150MHz,而双通道的位宽=128bit:带宽=150×128×8=153600Mbit=18.75GB

参考:http://blog.chinaunix.net/uid-14214482-id-3220464.html

 

二、各种内存测试方式的对比

下文分别介绍了使用dd命令、mbw命令、sysbench、AVX指令进行测试。

《设备性能测试 : 内存带宽的测试》

《关于如何读写达到内存最大带宽的网站》

 

三、Bandwidth内存测试工具

详细可查看官网:https://zsmith.co/bandwidth.php

关于Bandwidth工具使用博客:《Bandwidth内存带宽测试工具》

 

四、STREAM内存测试工具

《内存带宽测试-STREAM的使用》

 

五、AVX/AVX2指令编程

《Intel 内部指令 --- AVX和AVX2学习笔记》

《Intel Intrinsics — AVX & AVX2 Learning Notes》

《AVX指令编写的快速拷贝FastMemcpy_Avx》

 

《AVX指令编写的另一个快速拷贝fastMemcpy,并给出了相应的测试结果》

其代码如下,相对来说,是比较靠谱的。

#include <immintrin.h>
#include <cstdint>
/* ... */
void fastMemcpy(void *pvDest, void *pvSrc, size_t nBytes) {
  assert(nBytes % 32 == 0);
  assert((intptr_t(pvDest) & 31) == 0);
  assert((intptr_t(pvSrc) & 31) == 0);
  const __m256i *pSrc = reinterpret_cast<const __m256i*>(pvSrc);
  __m256i *pDest = reinterpret_cast<__m256i*>(pvDest);
  int64_t nVects = nBytes / sizeof(*pSrc);
  for (; nVects > 0; nVects--, pSrc++, pDest++) {
    const __m256i loaded = _mm256_stream_load_si256(pSrc);
    _mm256_stream_si256(pDest, loaded);
  }
  _mm_sfence();
}

 

六、关于使用AVX指令实现memcpy的总结

AVX指令集功能很强,但是应该只是对于计算类,使用后会得到性能的显著提升。

而对于内存读写类的指令,如:

_mm256_stream_load_si256
_mm256_stream_si256

等类似函数,其实对内存读写速度与读写的数据大小有关系,

有时候比memcpy快,有时候更慢,哪怕AVX256bit同时操作的数据是32字节。

关于读写速率的优化,感觉涉及的地方蛮多的,这个可能需要花点时间对指令集、Cache、地址对齐等知识进行一些了解和学习。