What Every Programmer Should Know About Memory

标签:无 1857人阅读 评论(0)
分类:

背景介绍:该书作者是Redhat公司的Ulrich Drepper,著于2007年,年代比较久远。虽然今天的计算机体系架构同以前相比,有了很大的变化,但该书对于理解计算机内存系统依然有极大的帮助。需要的可以在附件中下载。


  1. 简介

    该书主要介绍了计算机内存相关的知识,包括以下章节:

    1. Commodity Hardware today

    2. CPU caches

    3. Virtual memory 

    4. NUMA Support 

    5. What Programmers Can do

    6. Memory performance Tools

    7. Upcoming technology

    限于章节有限,这里主要介绍理论部分和最后程序员可有优化的部分以及内存性能工具。

  2. cpu caches

    1. 基本情况

      平常我们看到的内存物理形态如下所示:

      内存可以按照多种方式分类,从技术上比较有意义的分类是SRAM和DRAM,目前SRAM的主要和CPU集成在一起,DRAM则主要是我们现在说到的内存。

       (1) SRAM

            image.png

       (2) DRAM

      image.png


    SRAM使用多个晶体管,DRAM使用单个晶体管。显然SRAM的密度低于DRAM,SRAM只需要持续稳定的电压维持cell的状态,而DRAM电容的电量会泄露。并且,SRAM读写简单,但架构远高于DRAM。多种因素限制了CPU上面的cache一般也就3M-20M之间。

    b DRAM 读写流程

    当我们写代码读取变量的时候,没有多大的感觉,但从内存控制器的角度,读写需要严格的控制。上图是三级缓存处理器架构图。

    上图显示了CPU从内存中读取数据的流程。CPU将向L1/L2/L3逐步查找该地址,如果全部没有找到则内存控制器会读写主存,内存控制器按照既定的策略做好地址转换,然后开始读写SDRAM(详细的访问时序可以查看pdf文档)

    c. DRAM的改进

        上面时序可以看大,SRAM每周期只能传输1个字长,DDR对此了改进,每个周期传输2个字。DDR2精简了时序,再次提升了一倍带宽。DDR3也同样将读写周期延长,带宽再次翻倍。目前最高的DDR4通过提升频率和并行速度来增加带宽。

  3. What programmers can do

    1. Bypass the cache

      当产生的数据不再消费时,内存存储操作读取该缓存线再修改缓存中的数据时,会对性能有很大的影响,因此可以将这些数据push out of cache。

    2. Cache access

      编写多重循环程序,外循环和内循环的顺序关系对性能的影响极大。

      image.png

      以计算上式为例,直接的方式为:

      image.png

      上面代码中对于mul1是顺序访问的,但是对于内循环中的mul2以行号推进,非顺序访问。

      如果将上述式子变换一下:

      image.png

      image.png

      相比前一种方法,该模式需要额外的内存,但是基于顺序访问性能更优。

      此外还可以优化L1指令缓存访问,如使用likely()/unlikely()。

    3. Prefetching

      预取分为硬件预取和软件预取。

      硬件预取:CPU启动硬件预取的触发器通常是一个特定模式下的两个或多个缓存缺失序列。但预取也存在缺陷,无法跨越也边界。

      软件预取:硬件预取的有点是软件不需要调整,其缺点是访问模式必须是琐碎的,而且预抓取不能跨页面边界发生。而

    4. 软件预取确实需要修改源代码插入特殊的指令,如编译器支持自动插入预取指令(如_mm_prefetch)。

    5. 多线程优化

      多线程优化主要包括并行性,原子性和带宽。

      并行性优化:主要是在使用公共数据时需要注意的场景,如“falsr sharing”。

      原子性优化:如果多个线程同时修改相同的内存位置,处理器不会保证任何特定的结果。对此,处理器提供原子性操作。

      同样的指令可以以原子和非原子的方式使用。为了使它们具有原子性,需要为指令使用一个特殊的前缀:锁前缀。这就对于在给定的情况下不需要原子性要求,这就为原子操作打开了方便之门,从而避免了高昂的成本。

      带宽考虑:当使用了许多线程,即使它们不会因为在不同的核上使用相同的缓存线而引起缓存争用时,仍然存在潜在的问题。每个处理器都有一个最大的内存带宽,该内存由该处理器上的所有核和超线程共享,多个处理器可能共享内存或北桥的同一条总线。

    6. NUMA

      NUMA在访问地址空间的不同部分时引入了不同的代价。通过使用统一的内存访问,可以将页面错误最小化,但这并不足够。NUMA 将这个改变了,访问成本取决于所访问的页面。NUMA lib提供了如下接口以访问不同的page:

      image.png

  4. Memroy performance tools

    1. oprofile提供持续分析功能,它使用易于使用的界面执行统计、系统范围的分析。

    2. pfmoo

    3. valgrind框架模拟程序的执行,它允许各种扩展(比如cachegrind)挂接到执行框架中,valgrind还可以测量内存的使用情况。

    4. memusage:只记录堆使用的内存总量(包括对mmap的可能调用等)。

    5. PGO:用于测量分支预测对性能的影响

    6. pagein工具会发出关于页面错误的顺序和时间信息

附件:
查看评论

暂无评论

发表评论
  • 评论内容:
      
首页
团队介绍
发展历史
组织结构
MESA大事记
新闻中心
通知
组内动态
科研成果
专利
论文
项目
获奖
软著
人才培养
MESA毕业生
MESA在读生
MESA员工
招贤纳士
走进MESA
学长分享
招聘通知
招生宣传
知识库
文章
地址:北京市朝阳区华严北里甲22号楼五层 | 邮编:100029
邮箱:nelist@iie.ac.cn
京ICP备15019404号-1