| 2011年12月18日 07:00 | |
2.5 Thread Profiler线程档案器
Intel(R) 线程档案器可以帮助调整Win32*和OpenMP*线程化软件的性能。该工具通过监控程序的运行来检测线程性能的相关问题,包括线程过载和同步冲突,能够帮助查找负载平衡, 同步开销等线程性能问题。可以进行关键路径分析。线程档案器最后提供图形式的检测结果,由此可以快速查明影响程序运行时间的代码位置,并通过以图象形式生动显示每个线程的实时工作状况从而大大简化了调整程序性能的任务。
Intel(R) 线程档案器支持Intel(R) 64 和 Microsoft Visual Studio环境,通常集成到Intel(R) VTune性能分析器中使用。
2.5.1 线程档案器功能与使用
Win32*线程分析能力:
通过Win32* 线程API对软件线程化后的性能分析;
Win32线程关键路径分析,跟踪显示性能瓶颈——浏览直接影响执行时间的数据;
Microsoft Visual Studio* .NET开发环境集成——运行线程档案器,然后在Visual Studio .NET浏览结果;
如果不用Win32库,可以支持用户定义的同步原件。
OpenMP*线程分析能力:
线程档案器将OpenMP线程分析分成以下几类:
时间花费--并行代码;顺序代码;其他线程等待间隔;等待进入关键部分或锁访问;关键部分和持锁操作;
线程任务量不均衡;
并行过载;
顺序过载。
特性:
自动并行性能分析——提供快速、简单、直接的并行性能分析,不需要其他机制;
图形化显示线程状态和并串转换——揭示了性能优劣的原因,指明优化重点;
决定多处理器系统的可量测性——多个处理器协同工作的性能非常重要,对于OpenMP线程,线程档案器以图形方式显示了多处理器系统下理想的并行性能和程序的实际性能;
线程化设计确认——利用线程档案器检测线程化软件设计的效率。并行编程的好处体现在高效率和低负载上,线程档案器能以图形方式揭示程序的效率和过载情况。
Intel(R) 线程档案器同时显示并发视图和时间轴视图,这有助于理解哪部分代码适合并行处理以及应用性能问题源于何处,如图2.15所示:
图2.13 同时查看并发和时间轴
通过双击时间轴视图上的转换进入源代码视图,从而准确查看线程在源代码中进行转换工作的位置,如图2.16所示。这是理解线程应用行为的关键。
图2.14 查看源代码以发现线程问题
Intel(R) 线程档案器 3.0 Windows 版兼容现今的行业标准开发工具:
Microsoft Visual Studio .NET* 开发环境
Microsoft Visual C++* .NET 编译器 2005、2003、2002 版或 Visual C++ 6.0
Intel(R) VTune性能分析器 7.2 或 8.0
Intel(R) Fortran 和 C++ 编译器
Windows 线程和 POSIX* 线程
支持OpenMP
2.5.2 线程档案器实验
本实验通过Intel(R) 线程档案器来检测Win32线程程序中的性能问题。
(1)入门指南
打开\code\ThreadProfiler\potential lab 1\文件夹,双击Potential Lab 1.sln文件;
在Build菜单里选择Configuration Manager,然后选择Release模式;
按如下方式配置项目属性:
选中Debug模式 (/Zi)
链接时保留Debug信息 (/DEBUG)
使用线程安全系统库 (/MD)
使用二进制文件可重定位功能 (/fixed:no)
在Build菜单里选择Build Solution,编译相关文件;
运行Intel(R) VTune性能分析器;
点击New Project;
在Category栏选择Threading Wizards,在下拉框中选择Intel Thread Profiler Wizard;
选择刚才编译好的可执行文件路径(\code\Thread Profiler\Potential lab 1\Release\potential.exe),点击Finish按钮,开始运行线程档案器;
运行结束后,可看到双重视图,如图2.15所示:
图2.15 并发级别和时间轴双重视图
双击Profile栏可打开Concurrency Level视图。如果默认不是Concurrency Level视图,可点击图标进入;
点击其它分组图标,如grouping to thread图标和grouping to object图标
,观察各自属性;
双击Timeline栏视图可打开时间轴视图,观察性能数据,用鼠标在小范围拖拽可微观查看线程细节。
问题:
从刚才观察到的图表、数据分析,程序里有比较明显的性能问题吗?
(2)分析程序
返回到Profile栏的Concurrency Level视图,有多少时间消耗在串行(只有一个线程)执行程序?多少时间消耗在完全的并行执行?从这能得到什么启发?
点击图标,打开grouping to thread视图,该视图显示了程序中所有线程在关键路径上的活跃程度。该程序一共运行过多少个线程?有什么性能问题?
点击图标,打开grouping to object视图,是否有同步对象在关键路径占了相当大比例,而它又是串行执行的?如果有,是哪一个?
双击Timeline栏,打开时间轴视图。从这些数据中所发现最明显的特征是什么?如果有性能问题,应该从哪方面去解决它?
(3)负载平衡问题
编译和运行Potential多线程程序
打开\code\ThreadProfiler\Potential Lab 2\文件夹,双击Potential Lab 2.sln文件;
注意到源代码中两个事件变量bSignal和eSignal的定义和初始化,以及tPoolComputePot函数中done变量的使用,它控制模拟完成时线程的终结;
选择Release模式编译,并像前一小节设置好项目属性,编译程序;
打开VTune性能分析器,创建一个新的Thread Profiler活动,装入刚才编译生成的可执行文件,开始分析。
根据线程档案器的分析数据诊断程序性能问题
观察关键路径视图,注意到大部分时间都消耗在Serial impact time,即串行执行时间。并行级视图进一步确认了大部分时间都只有一个线程在执行。
打开grouping to object视图,哪个对象占用了串行执行时间?这个对象限制了其它对象对数据进行访问吗?如果是这样的话,能否改变程序和数据访问的模式,以减少线程占有同步对象的时间?
注:同步对象eSignal是用来标识线程何时完成,而非用来保护数据,主线程是惟一一个串行执行的。为了保证程序运行的正确性,主线程串行执行很有必要。因此,修改数据不会影响到状况。
若问题不是由数据保护这些同步对象引起的,那可能是因为线程自身引起的。打开grouping to thread视图,是否有一个或多个线程占用了关键路径中的串行执行时间?如果有,是哪几个?
比较每个tpoolComuptePot (worker)线程的生存时间和活跃时间,有哪些启发?
解决性能问题
注:两个worker线程活跃时间的差异表明两个线程的计算负载不平衡。需要重新分配每个线程完成的任务,使任务分配更为平衡。
回到Microsoft Visual Studio界面,观察源代码:在computePot函数中,每个线程用它分配的标识符(tid)来划分它要完成的任务块。然而,在内部的循环需要用到外部循环的索引作为结束条件。因此,外部循环的索引越大时,内部循环的迭代次数也越多,而相应划分到的线程所要完成的任务也越重。
有一个很好的方法能解决这种负载不平衡问题,即采用更灵活的任务分配机制。例如,不采用将连续的迭代分配给一个线程,而交叉分配给多个线程,比如只有两个线程时,可将奇数次的迭代分配给一个线程,而将偶数次的迭代分配给另一个线程。
按照上面提示的方法,修改源代码的任务分配机制,结合线程档案器,使程序的线程负载趋于平衡。

