示例5:伪共享分析
简介
在 SMP(Symmetric multiprocessing)架构中,每个CPU拥有一个cache,用来存储当前访问以及预测接下来会访问到的数据。Cache Line是一次加载到cache中的数据单元。通常是64 byte,但在鲲鹏920上的L3 cacheline是128byte。多个CPU上的多个线程同时修改自己的变量,这些变量表面上是不同的变量,但是实际上却存储在同一条Cache Line里。在这种情况下,由于Cache一致性协议,两个处理器都存储有相同的Cache Line拷贝的前提下,本地CPU变量的修改会导致本地Cache Line变成Modified状态,然后在其它共享此Cache Line的CPU上,引发Cache Line的Invalidate操作,导致Cache Line变为Invalidate状态,因此必须得从memory加载,这种现象就叫做伪共享false sharing。
解决伪共享的方式有很多,例如:
- 使用编译器优化选项。
- 通过对内存填充(padding),保证不同线程使用的变量在不同的Cache Line中。
- 定义变量时,进行内存对齐。
- 用thread local变量。将同一个Cache Line上的变量拷贝一份到本地,进行使用。
本示例中使用第三种方法用alignas进行强制以128byte对齐。
环境准备
伪共享分析检测
- 程序准备。
- 编译falsesharing.c并赋予执行文件所有用户可读、可写和可执行权限。
gcc falsesharing.c -lpthread -D _GNU_SOURCE -o falsesharing -g && chmod 777 falsesharing
- 使用后台启动脚本循环运行falsesharing 100次,同时nohup命令使得即使退出账户之后会继续运行相应的进程,防止任务中断。
nohup bash falsesharing_start.sh >>falsesharing.out 2>&1 &
程序运行的输出(标准输出(1))将会保存到falsesharing.out文件,错误信息(2)会重定向到falsesharing.out文件。
其中falsesharing_start.sh脚本内容如下。如果falsesharing_start.sh程序没有正常运行,可以通过falsesharing.out文件检查错误信息,注意检查是否是window-style line endings问题,如果是,可以通过vi -b falsesharing_start.sh进行删除。
- 编译falsesharing.c并赋予执行文件所有用户可读、可写和可执行权限。
- 采用进程/线程性能分析,查看造成的CPU消耗的进程。
创建进程/线程性能分析任务,并启动分析。
表1 任务配置参数说明 参数
说明
分析对象
系统
分析类型
进程/线程性能分析
采样时长
10秒
采样类型
全选
采集线程信息
开启
- 查看采集分析结果。图1 进程/线程性能分析结果总览
- 查看CPU页签。在“CPU”页签下,点击筛选按钮选择falsesharing程序所对应的PID,如图2所示,显示falsesharing进程下有线程的CPU利用率达到100%。发现falsesharing程序在消耗大量的CPU,同时全部消耗在用户态中,可推测是代码实现算法差或Cache Miss问题。
在此步骤中,因本示例是循环运行falsesharing程序,若采集时间过长可能采集到多个falsesharing程序进程。
- 结束程序。
通过jobs -l查看falsesharing程序运行pid(如果程序尚未结束,可以看到后台运行的程序),通过kill -9结束进程。
jobs -l kill -9 <falsesharing程序pid>
- 采用热点函数分析功能分析该程序,找到热点函数和指令。
创建热点函数分析任务,并启动分析。
表2 任务配置参数说明 参数
说明
分析对象
应用。本示例分析热点函数为已确定程序,所以不需要在服务器上运行程序,直接在工具中选择falsesharing程序。
模式
Launch application
应用路径
输入程序所在的绝对路径,本示例将代码样例放在服务器上“/opt/testdemo/falsesharing/falsesharing”目录下。示例路径里面第一个falsesharing为文件夹,第二个falsesharing为可执行程序。
分析类型
热点函数分析
采样时长
10秒
采样范围
用户态。采样范围分用户态、内核态、所有。示例中所有的CPU消耗都在用户态,所以只采集用户态的数据。
C/C++ 源文件目录
用于采集过程当中,获取函数名。本示例使用/opt/testdemo/falsesharing。
其他参数
默认
- 查看采集分析结果。图3 热点函数分析结果总览
从“总览”页面可查看程序的运行时长、周期和指令数,以及热点函数inc_b1, inc_b, sum_a, sum_a1,但未明确具体原因。
- 采用 ,进一步确认是否为Cache Miss造成。
创建访存分析任务,并启动分析。
表3 任务配置参数说明 参数
说明
分析对象
应用。本示例分析热点函数为已确定程序,所以不需要在服务器上运行程序,直接在工具中选择falsesharing程序。
模式
Launch application
应用路径
输入程序所在的绝对路径,本示例将代码样例放在服务器上“/opt/testdemo/falsesharing/falsesharing”目录下。示例路径里面第一个falsesharing为文件夹,第二个falsesharing为可执行程序。
分析类型
访存分析
访存分析类型
Miss事件分析
采样时长
5秒
其他参数
默认
- 查看采集分析结果。图4 Miss事件统计分析结果
“时序视图”页签显示CPU 0,1,2,3核的Miss事件很多,总的LLC Miss事件个数很大。由于sampling的采集方式,并非每次能采集到相同的数值,相差数值可能较大。
- 查看“详细视图”页签。
从下拉菜单中选择“模块/函数/调用栈”,显示程序falsesharing中有四个函数的Miss次数很高。
图5 Miss事件分析详细视图
这一步可确认Cache Miss为主因,但暂时无法确优化点。
- 针对Cache Miss造成的问题,但无法确认具体原因时,可考虑继续采用伪共享分析。
创建伪共享分析任务,并启动分析。
表4 任务配置参数说明 参数
说明
分析对象
应用。本示例分析热点函数为已确定程序,所以不需要在服务器上运行程序,直接在工具中选择falsesharing程序。
模式
Launch application
应用路径
输入程序所在的绝对路径,本示例将代码样例放在服务器上“/opt/testdemo/falsesharing/falsesharing”目录下。示例路径里面第一个falsesharing为文件夹,第二个falsesharing为可执行程序。
分析类型
访存分析
访存分析类型
伪共享分析。如果服务器操作系统不是openEuler,则此处无法选择。
采样时长
3秒。数值不宜过大,因为伪共享采集数据量大。
待采样CPU核
0,1,2,3 。因Miss事件分析中显示CPU0,1,2,3核Miss事件发生的次数最多。
C/C++ 源文件目录
用于采集过程当中,获取源文件代码。本示例使用/opt/testdemo/falsesharing/。
其他参数
默认
- 查看采集分析结果。图6 伪共享分析结果总览
“总览”页签中显示某一缓存行中伪共享发生总次数,在目标文件名中发现有应用程序falsesharing,点击相应的符号名,进入函数对应的代码页面。从“代码流”模块,找到伪共享数目占比高的Basic Block(颜色越深说明占比越高),单击Basic Block后,在源代码模块和汇编代码模块浅蓝色高亮显示对应伪共享发生次数高的代码行。
优化方案
使用alignas强制以128byte对齐解决伪共享问题。
- 程序准备。编译falsesharing_mod.c并赋予执行文件所有用户可读、可写、可执行权限。
gcc falsesharing_mod.c -lpthread -D _GNU_SOURCE -o falsesharing_mod -g && chmod 777 falsesharing_mod
- 采用热点函数分析功能分析该程序。
创建热点函数分析任务,并启动分析。
表5 任务配置参数说明 参数
说明
分析对象
应用。本示例分析热点函数为已确定程序,所以不需要在服务器上运行程序,直接在工具中选择falsesharing_mod程序。
模式
Launch application
应用路径
输入程序所在的绝对路径,本示例将代码样例放在服务器上“/opt/testdemo/falsesharing/falsesharing_mod”目录下。示例路径里面第一个falsesharing为文件夹,第二个falsesharing_mod为可执行程序。
分析类型
热点函数分析
采样时长
10秒
采样范围
用户态。采样范围分用户态、内核态、所有。示例中所有的CPU消耗都在用户态,所以只采集用户态的数据。
C/C++ 源文件目录
用于采集过程当中,获取源文件代码。本示例使用/opt/testdemo/falsesharing/。
其他参数
默认
- 查看采集分析结果。
此处结果与之前falsesharing程序的热点函数分析相比,sum_a和sum_a1周期占比减少。
图7 热点函数分析结果总览
- 采用 功能进一步分析。
创建Miss事件分析任务,并启动分析。
表6 任务配置参数说明 参数
说明
分析对象
应用。本示例分析热点函数为已确定程序,所以不需要在服务器上运行程序,直接在工具中选择falsesharing_mod程序。
模式
Launch application
应用路径
输入程序所在的绝对路径,本示例将代码样例放在服务器上“/opt/testdemo/falsesharing/falsesharing_mod”目录下。示例路径里面第一个falsesharing为文件夹,第二个falsesharing_mod为可执行程序。
分析类型
访存分析
访存分析类型
Miss事件分析
采样时长
5秒
其他参数
默认
- 查看采集分析结果。图8 Miss事件分析结果(时序视图)
图9 Miss事件分析结果(详细视图)
优化后的程序分析结果显示,Miss事件数目大幅减少,falsesharing_mod程序模块不再产生Miss事件。
- 采用 功能进一步分析。
创建伪共享分析任务,并启动分析。
表7 任务配置参数说明 参数
说明
分析对象
应用。本示例分析热点函数为已确定程序,所以不需要在服务器上运行程序,直接在工具中选择falsesharing_mod程序。
模式
Launch application
应用路径
输入程序所在的绝对路径,本示例将代码样例放在服务器上“/opt/testdemo/falsesharing/falsesharing_mod”目录下。示例路径里面第一个falsesharing为文件夹,第二个falsesharing_mod为可执行程序。
分析类型
访存分析
访存分析类型
伪共享分析。如果服务器操作系统不是openEuler,则此处无法选择。
采样时长
3秒。数值不宜过大,因为伪共享采集数据量大。
待采样CPU核
0,1,2,3 。因Miss事件分析中显示CPU0,1,2,3核Miss事件发生的次数最多,且全景分析中显示CPU0,1,2,3核利用率高。
C/C++ 源文件目录
用于采集过程当中,获取源文件代码。本示例使用/opt/testdemo/falsesharing/。
其他参数
默认
- 查看采样分析结果。
结果页面未发现falsesharing事件。
图10 伪共享分析结果总览