BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

内存与本机代码的性能

| 作者 Jonathan Allen 关注 615 他的粉丝 ,译者 臧秀涛 关注 4 他的粉丝 发布于 2013年7月3日. 估计阅读时间: 6 分钟 | ArchSummit北京2018 共同探讨机器学习、信息安全、微服务治理的关键点

在关于深入挖掘性能的演讲中,Eric Brumer解释了为什么内存往往是最关键的部件。尽管他探讨的是C++开发,但是很多建议都可以应用于托管代码。

高速缓存概观

在Intel的Sandy Bridge架构中,在4核心的CPU上,一个核心有6条流水线,也就是每个周期内可以处理多达6条指令。每个核心内还有64kB的L1-cache和256 kB的L2-cache,用作指令和/或数据的高速缓存。L3-cache为4个核心共享,根据模型的不同,大小从8MB到20MB不等。

从L1-cache中读取1个32位长的整数需要4个指令周期,从L2-cache中读取则需要12个指令周期,计算一个数的平方根也需要这么多时间。L3-cache则需要两倍多的时间——26个指令周期。从内存中读取更是相当相当长了。

数据访问模式

在开始讨论数据访问模式之前,Eric先拿出了这个空间局部性(spatial locality)很差的矩阵乘法的经典例子,并给出了其解决方案:

在比较强大的系统上,交换循环变量j和k就能带来10倍的性能改进。在低功率的桌面计算机上,性能改进高达18倍。需要重申的是,实际上主体代码并未改变,我们只不过修改了一下循环变量的顺序。

另请注意,Visual Studio 2013的发布版本有望识别并修正这类例子。这需要改进数据依赖分析引擎,不过前几天发布的预览版本还没有做好准备。

多核的影响

假设有两个数组,每个数组中都保存着400万个float值,然后将它们按元素相加,保存到第3个数组中(即c[i] = a[i] + b[i]; i = 0..3 999 999)。Eric在搭载了40个核心的处理器上进行了测试。理论上,该计算很容易扩展,可以并行地将其放到5个核心上,速度就能提升到原来的5倍。但是Eric发现速度只提升到了原来的1.6倍(扩展率是32%)。当所用核心数增加到10个时,速度是原来的2.4倍,扩展率只有24%了。

回顾实验结果,他发现所有的时间都花在了内存装载上。三个数组总共有48MB,超过了10核心CPU所提供的30 MB的L3-cache。将负载放到两个CPU上,并将计算并行地放到20个核心上,L3-cache达到了60MB。这次速度提升到原来的18倍,扩展率为90%。

Eric继续说道,实际上核心的数目无关紧要,起作用的其实是高速缓存的大小。他解释说,这个例子有点极端。对大多数程序而言,当相关的线程运行在同一CPU上时速度会更快,这是因为它们更容易共享高速缓存。但是这个例子和我们的想象完全相反,标准并行库带来了不利的影响。

向量代码

在下面的例子中,Eric演示了一个粒子物理问题,该问题中有4096个元素相互作用,粒子之间的引力可以按照万有引力公式计算。使用标准的循环程序来计算,每秒可以运行8帧。利用Visual C++的自动向量化和128位SSE2指令,循环迭代次数从4096减少到1024,帧率提升到18。256位的AVK指令则可将迭代次数减少到512,但帧率只提升到23。

后来发现,原来是数据组织的问题。对每个粒子而言,其位置数据在给定的一帧内不会变化,还与要计算的加速数据混到了一起。要装载保存了8个粒子的X坐标的 256位YMM寄存器,需要执行9条独立指令。装载Y坐标和Z坐标还需要18条指令。

重写这段代码使X、Y和Z三个坐标分别保存到一个单独的连续数组中,这超出了我们的研究范围。因此Eric进行了简化,他把它们复制到3个临时数组中,运行主循环的一个修改版本,然后将数据复制了回去。

仍然使用256位的AVK指令,这些额外的内存复制实际上改进了性能,帧率达到42。应该注意的是,这一改进——即帧率从8提升到42——是在一台搭载单核处理器的笔记本上实现的。

内存对齐

下一个问题是内存对齐。在L1-cache中,每一行长64字节。如果数据结构的长度都是缓存行长度的因子(比如长32、16、8或4字节),那就可以直接将其放入缓存行中,而不会浪费空间。不过这要求数据结构按照64字节对齐。

回到前面的例子,Eric修改了一下代码,跳过数组的第一个元素,强制进行非对齐访问。结果与j从0开始相比,性能损失了8%。

按照C语言标准,malloc返回的数据只需要按8字节对齐。可以使用_aligned_malloc获得按32字节或64字节对齐的内存。我们正在进行相关开发工作,希望数据用于循环体之内时,编译器自动调用_aligned_malloc,但是这也存在增加内存碎片的风险。我们希望在VS 2013 Update 1版本中提供些相关的新特性。

如果要更详细地了解这些内容,并要学习与内存有关的其他性能问题,可以观看Build 2013的视频:“Native Code Performance and Memory: The Elephant in the CPU”。

查看英文原文:Memory and Native Code Performance

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

核心是怎么计算的。。。 by z l

"Eric在搭载了40个核心的处理器上进行了测试。理论上,该计算很容易扩展,可以并行地将其放到5个核心上,速度就能提升到原来的5倍。"

这的这么快?? by 黄 海平

"从L2-cache中读取则需要12个指令周期,计算一个数的平方根也需要这么多时间"


cpu真的这么快吗?

Re: 这的这么快?? by 臧 秀涛

可以参考intel的架构相关手册。

Re: 核心是怎么计算的。。。 by 臧 秀涛

看Eric Brumer的ppt上,是4个cpu,40个核心的处理器。这里应该是把任务指派到指定核心上进行计算的吧。

Re: 核心是怎么计算的。。。 by 臧 秀涛

感觉是4个cpu的服务器,每个cpu都是10核xeon。具体可以结合视频和ppt看一下。

2个物理CPU之间的通讯速度是最可怕的 by Shichao Liu

多核机器,负载分配设计的错误,或者没有足够的优化,效率很容易就渣了。 2个物理CPU之间的通讯速度是最可怕的,奇慢。

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

6 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT