从stream的多线程协同效率说起

似乎每次开头都要讲述一下计算机或者说x86架构的演进历史,这似乎成了站长Litrin的一种习惯。现在的x86架构CPU频率以及最大IPC已经接近极限,厂商倾向于将越来越多的核心通过SMP技术多线程负载。不妨做一个思想实验:将计算机的任务想象为搬砖,CPU核心则是搬砖的工人。根据我们的常识,工人越多则任务完成的越快,也就是意味着核心数和性能是成正比的。然而事实真的如此吗?

对于这类的问题,大家的第一反应肯定是否定的。但究竟多线程的协同效率是如何体现的呢?前些日子,我们针对stream的测试结果做了一个分析,几组有意思的数据。

Stream是一个很简单的大向量压力测试软件,它会在内存中生成一个足够长(1G位)的向量,然后分别对它经行拷贝copy,加法Add,除法scale,三元triad操作并根据执行的时间间接评价系统的计算性能。由于其“每个数值只做一次简单操作”的特性,对于CPU的缓存,特别是数据缓存的大小非常不敏感。对于stream的多线程实现是采用标准的OpenMP。

stream算法简介


测试中我们采用的是一套24核心的CPU,关闭了HT、CPU turbo等干扰性因素。6根DDR4-2666内存。

stream core scaling测试数据

从上面的图表中我们可以看出,当我们简单的通过增加核心数量的方式试图提升stream的性能时,在12个核心之前性能的提升还是很明显的,但从12核心之后,没有发现较大的性能提升。很明显的一点就是,随着核心数量的逐渐增加,提升的幅度(微分)逐渐减少,最终趋于0.

如果你之前有过类似的经验,你肯定会说:“有系统瓶颈阻碍了性能的进一步提升。”通过我之前对于stream这个应用的描述,你甚至可以直接脱口而出:“CPU有余量,内存带宽用满了!”然后就是我们对内存带宽的统计。

stream core scaling内存带宽数据

上图可见在不同的线程下内存带宽的消耗情况,可见大致的趋势与stream的跑分是一致的,不过图中最大值刚刚超出80GB/s,这个结果跟6根DDR4 2666内存的理论极限带宽120GB/s还是差了很远。

我们已经证实了memory bandwidth的占用越高,stream跑分越好。同样采集到了从数值上看内存带宽没有达到瓶颈,但绝对值不再增长的问题。问题究竟是出在哪里呢?

stream core scaling RPQ 时延(纳秒)

我们直接获取系统的RPQ(read pending queue)时延数据。RPQ之前在本站的其他帖子上也多次提到过,系统需要维护一个队列用以解决内存访问的一致性问题。而RPD时延这个数值则表达的是一个内存访问请求从进入队列到返回的时长。显而易见,这个值越小说明内存的访问越健康。
stream是一个极度依赖内存请求的应用,而且大多数的内存请求返回都不大,这导致了内存的请求数非常多。当同一个任务通过OpenMP划分成多个线程在多个物理核心上运行时,由于并发度不断提升,内存的请求数正比提升,导致了RPQ时延同样正比提升。这个过程导致的结果是内存带宽的提升率逐步下降。

stream并不是一个特例,受制于内存控制器和内存带宽的影响,即便是stream这种纯CPU+内存的benchmark的工具同样存在多线程效率下降的问题。这种情况下适当的减少系统的线程数反而成为一个更加经济的做法。

推荐阅读:
继续在NUMA和性能差异的路上
5月中旬,我参加了在加利福尼亚
长久以来,我们对计算机资源的理

发表评论

电子邮件地址不会被公开。 必填项已用*标注

请补全下列算式: *

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据