您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 利用Oprofile对多核多线程进行性能分析
利用Oprofile对多核多线程进行性能分析在对应用程序不断调优的过程中,除了制定完备的测试基准(Benchmark)外,还需要一把直中要害的利器——性能分析工具。根据工具的复杂度和所提供的功能,可以将性能工具分为两个层次:1.基本的计时工具在普通生活中,秒表是最简单的计时工具。根据该思想,可以将计时函数放在代码的任意位置并多次调用,这样就可以测量出整个应用或者某一部分的运行时间。这种分析方法不够精细,误差大。1.软件分析工具目前,主要有两种不同类型的软件分析工具:采样和插桩。采样型分析工具主要通过周期性中断,来纪录相关的性能信息,如处理器指令指针、线程id、处理器id和事件计数器等。这种方法开销小,精确度高。在Linux系统中,比较常见的有Oprofile和IntelVTune性能分析器等。插桩型分析工具即可以使用直接的二进制插桩,也可以通过编译器在应用中插入分析代码。这种方式与自己在应用中增加计时函数类似,同时带来的开销大,但提供了更多的功能,如调用树,调用次数和函数开销等。在Linux系统中,比较常见的有gprof和IntelVTune性能分析器等。本文将利用采样型工具Oprofile,对多核多线程程序进行性能分析,起一个抛砖引玉的作用。衡量性能收益的方法随着科学技术的不断发展,计算机系统结构朝着多核的方向发展,从而将并发编程推到了聚光灯下,但如何去衡量并行程序设计所带来的性能收益呢?不得不想起1967年GeneAmdahl所做出的杰出贡献,他提出的Amdahl定律能够计算出并行程序相对于最优串行算法在性能提升上的理论最大值。Amdahl定律1加速比=————————S+(1-S)/n+H(n)其中,S表示执行程序中串行部分的比例,n表示处理器核的数量,H(n)表示系统开销。由于Amdahl定律本身做出了几个假设,但这些假设在现实世界中又不一定是正确的,因此使计算机界心灰意冷了很多年,认为根据Amdahl定律,开发更大的并行性所带来的性能收益可能是微不足道的,一直到Gustafson定律的出现,才改变了现状。在Sandia实验室工作的基础上,E.Barsis提出了Gustafson定律:扩展加速比=N+(1-N)*S其中,S表示执行程序中串行部分的比例,N表示处理器核的数量。幸运的是,Shi于1996年证明Gustafson定律和Amdahl定律是等效的。Oprofile工作原理简介根据CPU系统结构的不同,Oprofile支持两种采样方式:基于事件(EventBased)的采样和基于时间(TimeBased)的采样。如果CPU内部存在性能计数寄存器,则Oprofile基于事件采样,记录特定事件(如分支预测事件)发生的次数,当达到设定的定值时就采样一次。反之,则基于时间采样,主要是借助于操作系统的时钟中断机制,每当时钟中断发生时就采样一次。不难看出,基于时间的采样方式,要求被测程序不能屏蔽中断,其精度也低于事件采样。对于x86体系结构,不同型号的CPU,采样方式也不同,具体细节如下表所示:处理器CPU_TYPE采样方式Athloni386/athlonEventBasedPentiumProi386/pproEventBasedPentiumIIi386/piiEventBasedPentiumIIIi386/piiiEventBasedPentiumM(P6core)i386/p6_mobileEventBasedPentium4(non-HT)i386/p4EventBasedPentium4(HT)i386/p4-htEventBasedDualCoretimerTimeBasedCore2DuotimerTimeBased表一x86各处理器采样方式Oprofile主要分为两部分,其中一部分是内核模块(oprofile.ko),另外一部分是用户空间的守护进程(oprofiled)。前者主要负责访问性能计数寄存器或者注册基于时间采样的函数,并将采样结果置于内核的缓冲区中。后者在后台运行,负责从内核空间收集数据,并写入采样文件中,其交互流程如图1所示:图1oprofile交互流程图安装Oprofileoprofile.ko内核模块已经被集成到linux2.6内核中,所以只需要安装前端工具,可以从oprofile官方网站下载源码来进行安装,当前最新版本为0.9.4。该源码包是通过automake和autoconf生成的makefile,所以只需要以root用户进入oprofile目录,运行./configure、make及makeinstall来完成所有的安装。在目前大部分发行版中,安装时可能缺少popt库,请另行下载安装。Oprofile工具链提供了6大工具,供用户控制oprofile和分析样本。其中opcontrol是一个bash脚本程序,主要用来控制oprofile的启动、暂停及设置,其他工具主要是对采样数据进行分析。样例程序程序功能:求从1一直到APPLE_MAX_VALUE(100000000)相加累计的和,并赋值给apple的a和b;求orange数据结构中的a[i]+b[i]的和,循环ORANGE_MAX_VALUE次。#defineORANGE_MAX_VALUE1000000#defineAPPLE_MAX_VALUE100000000#defineMSECOND1000000structapple{unsignedlonglonga;unsignedlonglongb;};structorange{inta[ORANGE_MAX_VALUE];intb[ORANGE_MAX_VALUE];};intmain(intargc,constchar*argv[]){//insertcodehere...structappletest;structorangetest1;for(sum=0;sumAPPLE_MAX_VALUE;sum++){test.a+=sum;test.b+=sum;}for(index=0;indexORANGE_MAX_VALUE;index++){sum+=test1.a[index]+test1.b[index];}return0;}观察上述样例程序,S(串行部分的比例)所占比例非常小,基本为0,根据Amdahl定律,在双核系统(n=2)上,则加速比为:加速比=1/(0+1/2+1%)=1.96,也就是说效率可以提高96%。样例程序运行时间为:1.049046s,那么经过优化后,能不能达到理论值呢?请随着本文开始。追踪热点既然要充分利用双核的特性,则不得不对样例程序进行改造,进行并行程序设计。可以将应用程序看成是众多相互依赖的任务的集合。将应用程序划分成多个独立的任务,并确定这些任务之间的相互依赖关系,这个过程称为分解(Decomosition)。分解问题的方式主要有三种:任务分解、数据分解和数据流分解。运用任务分解的方法,不难发现计算apple的值和计算orange的值,属于完全不相关的两个操作,因此可以并行。改造后的两线程程序:void*add(void*x){for(sum=0;sumAPPLE_MAX_VALUE;sum++){((structapple*)x)-a+=sum;((structapple*)x)-b+=sum;}returnNULL;}intmain(intargc,constchar*argv[]){//insertcodehere...structappletest;structorangetest1={{0},{0}};pthread_tThreadA;pthread_create(&ThreadA,NULL,add,&test);for(index=0;indexORANGE_MAX_VALUE;index++){sum+=test1.a[index]+test1.b[index];}pthread_join(ThreadA,NULL);return0;}现在通过oprofile来对多线程程序进行性能分析,收集热点信息。oprofile的功能非常强大,可以对每个线程进行单独采样,也可以对每个CPU单独采样,这些都是通过opcontrol的--separate选项来完成的。separate选项值含义如下:separate选项值含义none默认值lib对每个应用程序的所有lib进行采样kernel对每个应用程序的内核及内核模块采样thread对每个线程或任务采样cpu对每个CPU进行采样all以上所有选项的功能表2separate选项值含义操作步骤如下:#opcontrol--init#opcontrol--separate=thread--no-vmlinux#opcontrol--startUsing2.6+OProfilekernelinterface.Usinglogfile/var/lib/oprofile/samples/oprofiled.logDaemonstarted.Profilerrunning.#./twothreadprocessaddthread:b7dc7b90,UsedTime:1.225483mainthread:b7dc8ad0,UsedTime:1.230151a=4999999950000000,b=4999999950000000,sum=0#opcontrol--shutdownStoppingprofiling.Killingdaemon.识别出并行程序中的重载运行opreporte,查看采样结果:#opreport-l./twothreadprocessCPU:CPUwithtimerinterrupt,speed0MHz(estimated)ProfilingthroughtimerinterruptProcesseswithathreadIDof5237ProcesseswithathreadIDof5238samples%samples%symbolname30100.00000main00343100.000add运行时间为:1.230151s,与理论值相差甚远,反而运行时间越来越长,原因何在呢?通过分析结果,不难看出add线程负载非常重,而main负载较轻,负载不均衡,因此重点分析对象为add线程。根据多线程数据分解的原理,将计算apple值的过程一分为二,main线程也参与部分计算。由于都是循环,为了使负载均衡,则add线程里面应该循环(ORANGE_MAX_VALUE+APPLE_MAX_VALUE)/2次。修改后的程序如下:#defineORANGE_MAX_VALUE1000000#defineAPPLE_MAX_VALUE100000000#defineMSECOND1000000#defineMIDLLE_VALUE49500000structapple{unsignedlonglonga;unsignedlonglongb;};structorange{inta[ORANGE_MAX_VALUE];intb[ORANGE_MAX_VALUE];};unsignedlonglongvalue[2][2];void*add(void*x){temp1=((structapple*)x)-a;temp2=((structapple*)x)-b;for(sum=MIDLLE_VALUE;sumAPPLE_MAX_VALUE;sum++){temp1+=sum;temp2+=sum;}value[0][0]=temp1;value[1][0]=temp2;returnNULL;}intmain(intargc,constchar*argv[]){//insertcodehere...structappletest;structorangetest1={{0},{0}};pthread_tThreadA;test.a=0;test.b=0;temp1=t
本文标题:利用Oprofile对多核多线程进行性能分析
链接地址:https://www.777doc.com/doc-3161891 .html