【问题标题】:Analyzing spikes in performance measurement分析性能测量中的峰值
【发布时间】:2018-05-19 23:38:25
【问题描述】:

我有一组 C++ 函数,它们执行一些与图像处理相关的操作。一般来说,我看到最终输出在 5-6 毫秒的时间范围内交付。我正在测量使用QueryPerformanceCounter Win32 API 所花费的时间。但是当以 100 张图像连续循环运行时,我发现某些图像的性能峰值高达 20 毫秒。我的问题是我该如何分析这些问题。基本上我想确定峰值是否是由于此代码中的一些延迟引起的,或者是否其他一些任务开始在 CPU 内运行,因为此操作需要时间。我尝试使用GetThreadTimes API 来查看我的线程在 CPU 中花费了多少时间,但无法根据这些数字得出结论。解决此类问题的标准方法是什么?

【问题讨论】:

    标签: c++ performance performance-testing benchmarking


    【解决方案1】:

    解决此类问题的标准方法是什么?

    有实时操作系统 (RTOS) 可以保证这种延迟。它是与 Windows 或 Linux 完全不同的操作系统。

    但是,即使在通用操作系统上,您也可以对延迟采取一些措施。

    1。避免系统调用

    一旦您要求操作系统在磁盘上读取或写入某些内容,就无法保证延迟。因此,请避免关键路径上的任何系统功能:

    • 即使是 gettimeofday() 之类的函数也可能会导致无法预料的延迟,因此您应该真正避免在时间关键型代码中进行任何系统调用;
    • 使用另一个线程执行 IO 并通过共享缓冲区将数据传递给您的关键代码。

    如果您的代码库很大,可以使用诸如 Linux 上的 strace 或 Windows 上的 Dr Memory 之类的工具来跟踪系统调用。

    2。避免上下文切换

    Windows 上的多线程是抢占式的。这意味着,有一个系统调度程序,它可能随时停止你的线程并在你的 CPU 上调度另一个线程。如前所述,有一些 RTOS 可以避免此类上下文切换,但您可以做一些事情:

    • 确保至少有一个 CPU 内核可供系统和其他任务使用;
    • 使用SetThreadAffinityMask() (Windows) 或sched_setaffinity() (Linux) 将您的每个线程绑定到专用 CPU —— 这有效地提示系统调度程序避免在该 CPU 上调度其他线程;
    • 确保硬件中断转到另一个 CPU;通常中断会转到 CPU 0,因此最简单的方法是将线程绑定到 CPU 1+;
    • 提高您的线程优先级,因此调度程序不太可能将您的线程切换到另一个线程。

    有像 perf (Linux) 和 Intel VTune (Windows) 这样的工具来确认有上下文切换。

    3。避免其他非确定性特征

    更多意外延迟的来源:

    • 禁用交换,这样您就可以确定您的线程内存不会在缓慢且不可预测的磁盘驱动器上进行交换;
    • 禁用 CPU turbo boost -- 在高性能 CPU 加速之后,总是会变慢,因此 CPU 保持在其热功率 (TDP) 范围内;
    • 禁用超线程 - 从调度程序的角度来看,它们是独立的 CPU,但实际上每个超线程 CPU 的性能取决于其他线程当前正在做什么。

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      处理过程中突然出现峰值的原因可能是 IO、中断、计划进程等。

      考虑到如此低的延迟/处理时间操作,看到这样的峰值是很常见的。由于上述任何原因,您都可以考虑 IMO(可能还有更多)。最简单的解决方案是多次使用更多输入运行相同的实验,然后取平均值作为最终考虑。

      要回答有关检查/确认尖峰来源的问题,您可以尝试关注,

      1. 检查图片中的变化 - 已根据您的评论排除
      2. 在处理过程中监控资源利用率。检查是否有任何资源阻塞(% util 是最简单的检查方法,Linux 上的 SAR/NMON 实用程序最好以最小的开销)
      3. 为您的实验保留少量系统上的 CPU(CPU 关联性),这些 CPU 仅专用于您的程序,不会在其上运行任何操作系统任务。 Taskset 是最简单的试用工具。更多细节是here

      使用此设置运行实验并检查行为。

      【讨论】:

      • 禁用超线程也很有用;即使您的线程从未中断,另一个与您竞争缓存和其他共享资源的进程也会减慢您的速度。 (当然,如果您的代码对 L3 缓存污染/干扰敏感,那么任何其他活动都会受到影响)。
      【解决方案3】:

      这是你想要弄清楚的一件令人讨厌的事情,我什至不会尝试,因为很难得出具体的结论。

      一般来说,应该运行 许多 次迭代的循环(我认为 100 次似乎太小了),然后计算处理图像的平均时间。

      这将排除任何可能影响程序性能的意外外部事件。


      检查“其他任务是否开始在 CPU 内运行”的典型方法是运行一次程序并标记产生该峰值的图像。例如,图像 2、4、5 和 67 处理时间过长。再次运行您的程序几次,并再次标记哪些图像会产生尖峰。

      如果相同的图像产生这些尖峰,那么这不是由另一个外部任务引起的。

      【讨论】:

      • 感谢您的回答。为了排除特定图像引起的问题,我在同一张图像上运行了 100 次算法。即便如此,我也看到了尖峰。
      猜你喜欢
      • 1970-01-01
      • 2011-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-04
      • 2011-07-23
      • 1970-01-01
      相关资源
      最近更新 更多