http://software.intel.com/zh-cn/articles/intel-performance-counter-monitor
下载代码示例
IntelPerformanceCounterMonitorV1.6.zip
过去几十年内,计算系统的复杂性显著增加。层次化高速缓存子系统、非一致性内存、同步多线程和乱序执行等技术均为现代处理器的性能和计算能力带来了巨大的影响。
图 1:“CPU 利用率”仅测量了线程在内核上预定的时间
通常,能够理解并自动适应现代处理器资源利用率的软件具备出色的性能和功耗优势。英特尔® Performance Counter Monitor 可提供范例 C++ 例程和实用程序,用于估算最新英特尔® 至强® 和英特尔® 酷睿™ 处理器的内部资源利用率,进而实现大幅度的性能提升。
当 CPU 利用率数据无法体现 CPU 利用率时
从操作系统(OS)获得的 CPU 利用率数字是一项重要的衡量指标,一直以来被用作多种目的,例如产品尺寸选择、计算能力规划和任务调度等。该指标的当前实施(UNIX*“top”实用程序和 Windows* 任务管理器报告的数字)显示了操作系统中的 CPU 调度程序可分配给运行程序或操作系统执行的时隙比例;剩余的时间则处于空闲状态。对于受计算量限制的工作负载,采用上述方法计算的 CPU 利用率指标预测了剩余的 CPU 计算能力,非常适合性能相较现代系统而言更统一、可预测性更强的八十年代架构。但是,计算架构领域的改进使得该算法不再可靠,因为当前的计算架构引入了多内核和多 CPU 系统、多层高速缓存、非一致性内存、同步多线程(SMT)、流水线、乱序执行等先进技术。
图 2:现代化多处理器、多内核系统的复杂性
一个极具代表性的示例是采用英特尔® 超线程技术(英特尔® HT 技术)的处理器上的非线性 CPU 利用率。英特尔® HT 技术是一项卓越的性能特性,能够将性能提升多至 30%。然而,不了解超线程技术的最终用户很容易会被报告的 CPU 利用率搞得晕头转向:假设某款应用在每枚物理内核上运行一条线程。虽然应用会占用 70%-100% 的执行单元,而报告的 CPU 利用率只有 50%。关于详细信息请参见注释 [1]。
另一个不同示例是多核系统上“内存吞吐量”密集型工作负载的 CPU 利用率。带宽测试“流”已经使内存控制器的容量达到饱和,线程数量要少于内核数量。
性能监视单元(PMU)的抽象层
值得高兴的是,英特尔处理器已经集成相关技术,能够监视处理器内部的性能事件。为了获得更精确的 CPU 资源利用率信息,我们将希望寄托于在英特尔处理器内部实施的性能监视单元(PMU)所提供的动态数据。我们特别关注随当前英特尔® 至强® 5500、5600、7500、E7 和酷睿™ i7 系列处理器提供的高级特性集[2-4]。
我们实施了一系列采用高级接口的基本例程,这些例程可通过用户的 C++ 应用进行调用,能够实时提供各种 CPU 性能指标。与其它现有框架如 PAPI* 和 Linux*“perf”不同,我们不仅支持内核 PMU,还支持英特尔处理器(包括最近推出的英特尔® 至强® E7 系列处理器)的非内核。非内核是处理器的一部分,包括集成内存控制器以及到其它处理器和 I/O 中枢的英特尔® 快速通道互联(QPI)链路。总得来说,支持的衡量指标如下:
英特尔® Performance Counter Monitor(PCM)版本1.5(和更高版本)还支持英特尔® 凌动TM 处理器,但内存带宽、英特尔® QPI 带宽和三级高速缓存未命中等计数器将持续显示“0”,因为英特尔® 凌动TM 处理器没有三级高速缓存和集成内存控制器或英特尔® QPI 链路。
英特尔® PCM 版本 1.6 支持第二代英特尔® 酷睿TM 处理器家族(英特尔® 微架构 Sandy Bridge)的内核性能指标(如每时钟周期执行的指令数、三级高速缓存未命中次数),此外还尝试支持部分较早的英特尔® 微架构(如 Penryn):可通过在 cpucounter.cpp 中定义 PCM_TEST_FALLBACK_TO_ATOM 来启用该支持。
我希望看看这些计数器!
PCM 软件包属于额外赠品,其中包括易于使用的命令行和基于这些例程的图形实用程序。它们支持即购即用,特别适合不能或不想在代码中集成例程但却希望能够实时监视和了解 CPU 计算能力极限的用户。
图 3 是 Windows* 平台上命令行实用程序的截屏。虽然 Linux* 版本能够依赖随 Linux 内核提供的 MSR 内核模块,但 Windows 上没有此类工具。在 Windows 操作环境中,Windows 驱动程序的范例实施能够提供相似的界面。
图 3:英特尔 Performance Counter Monitor 命令行版本
但是,未来将有更多新技术推出。对于 Linux 操作系统,软件包中含有一个可插入 KDE* utility ksysguard 中的适配器。使用该后台程序,能够实时获得不同指标的曲线图。图 4 也是一个截屏,展示了工作负载运行过程中显示的部分指标。
图 4:Linux 上的 KDE utility ksysguard 可以使用插件绘制性能计数器的曲线图。
鉴于这些实用程序能够提供连接系统内部的直接通道,甚至可以使用它们迅速地实时查找和了解基本的性能瓶颈。(与英特尔® VTuneTM 可视化性能分析器不同,它们不会告诉您导致性能问题的是应用的哪些部分。)
自 1.5 版本开始,英特尔® Performance Counter Monitor 软件包集成了一项基于 Microsoft .Net* 2.0 或更高版本的 Windows* 服务,该服务能够创建性能计数器,并显示在随 Microsoft Windows* 操作系统附带提供的 Perfmon 程序中。微软的 perfmon 程序能够在 Windows* 操作系统上显示大量有用的性能计数器,例如磁盘活动、内存使用、CPU 负载等。请点击此处,了解与面向 Windows* 7 和 Windows* 2008/R2 的 perfmon 程序有关的更多信息(现多个 Windows 版本均配有 perfmon)。请阅读 Windows_howto.rtf 文件,了解如何安装和卸载针对英特尔® PCM 的服务。
针对上述所有面向 Nehalem 和 Westmere 架构平台的硬件计数器,我们创建了一个相应的 perfmon 计数器,这样一来,perfmon 支持的所有特性将全部适用于这些计数器,如在文件或数据库中持续记录日志等。对于英特尔® 凌动TM 处理器,出于我们之前已提及的原因,关于内存带宽、英特尔® QPI 带宽和三级高速缓存未命中的 perfmon 计数器将持续显示“0”。在未来的英特尔® Performance Counter Monitor 更新版本中,服务将只显示可用的计数器。
集成于您的程序之内的英特尔® Performance Counter Monitor
借助库提供的抽象层,您能够非常轻松地监控应用中的处理器性能指标。使用性能计数器之前,应首先对它们进行初始化。完成初始化后,可在相关代码段之前和之后捕获计数器状态。不同例程会捕获面向内核、插槽或整个系统的计数器,并将它们的状态存储于相应的数据结构中。其它例程则可基于这些状态计算性能指标。下方的代码片段展示了一个具体的使用示例:
01 |
PCM * m = Monitor::getInstance(); |
02 |
if (m->program() != PCM::Success) // program counters |
03 |
return -1; // error occured during programming |
04 |
SystemCounterState before_sstate = getSystemCounterState(); |
05 |
[run your code here] |
06 |
SystemCounterState after_sstate = getSystemCounterState(); |
07 |
cout << “Instructions per clock :“ << getIPC(before_sstate,after_sstate) |
08 |
<< “L3 cache hit ratio:” << getL3CacheHitRatio(before_sstate,after_sstate) |
09 |
<< “Bytes read:”<< getBytesReadFromMC(before_sstate,after_sstate) |
10 |
<< [and so on]… |
“CPU 资源”感知型调度
为了评估掌握精确的资源利用率可能带来的影响,我们实施了一个简单的调度程序,在单条线程中执行 1000 个计算密集型和 1000 个内存带宽密集型任务。我们所面临的难题是,系统上存在无法预测的后台负载,这是当前采用大量第三方组件的多组件系统经常出现的典型情形。图 5 显示了不清楚后台活动的调度程序可能做出的调度安排。