性能测量中的尖峰分析 我有一套C++函数,可以进行一些图像处理相关的操作。通常我看到最终输出在5-6ms的时间范围内交付。我正在使用QueryPerformanceCounterWin32 API测量所用的时间。但是,当连续循环运行100个图像时,我看到一些图像的性能峰值高达20毫秒。我的问题是我如何着手分析这些问题。基本上,我想确定这些尖峰是由于代码中的一些延迟引起的,还是因为这个操作花费了时间,CPU内部开始运行其他任务。我曾尝试使用GetThreadTimesAPI查看我的线程在CPU内花费了多少时间,但无法根据这些数字得出结论。解决这类问题的标准方法是什么?

性能测量中的尖峰分析 我有一套C++函数,可以进行一些图像处理相关的操作。通常我看到最终输出在5-6ms的时间范围内交付。我正在使用QueryPerformanceCounterWin32 API测量所用的时间。但是,当连续循环运行100个图像时,我看到一些图像的性能峰值高达20毫秒。我的问题是我如何着手分析这些问题。基本上,我想确定这些尖峰是由于代码中的一些延迟引起的,还是因为这个操作花费了时间,CPU内部开始运行其他任务。我曾尝试使用GetThreadTimesAPI查看我的线程在CPU内花费了多少时间,但无法根据这些数字得出结论。解决这类问题的标准方法是什么?,c++,performance,performance-testing,benchmarking,C++,Performance,Performance Testing,Benchmarking,这是一件令人讨厌的事情,你想弄清楚,我甚至不想弄清楚,因为达成具体结论很难 通常,应该运行多次迭代的循环(我认为100次似乎太小),然后计算图像处理的平均时间 这将排除任何可能影响程序性能的意外外部事件 检查“CPU中是否有其他任务开始运行”的典型方法是运行一次程序并标记产生该峰值的图像。例如,图像2、4、5和67处理时间过长。再次运行程序几次,并再次标记哪些图像产生尖峰 如果相同的图像产生这些尖峰,那么它不是由另一个外部任务引起的。处理过程中突然尖峰背后的原因可能是IO、中断、计划进程等 考

这是一件令人讨厌的事情,你想弄清楚,我甚至不想弄清楚,因为达成具体结论很难

通常,应该运行多次迭代的循环(我认为100次似乎太小),然后计算图像处理的平均时间

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


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


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

处理过程中突然尖峰背后的原因可能是IO、中断、计划进程等

考虑到这种低延迟/处理时间的操作,这种峰值是很常见的。IMO你可以考虑他们因为上述任何原因(可能会更多)。最简单的解决方案是用更多的输入多次运行相同的实验,并取平均值作为最终考虑

要回答您关于检查/确认尖峰来源的问题,您可以尝试以下内容:

  • 检查图像中的变化-根据您的评论已排除
  • 在处理过程中监视资源利用率。检查是否有任何资源阻塞(%util是最简单的检查方法,linux上的SAR/NMON实用程序是最好的,开销最小)
  • 在系统上保留一些CPU(CPU亲和力)用于您的实验,这些CPU只用于您的程序,不会在它们上运行操作系统任务。任务集是最简单的实用工具。更多详情请参阅 使用此设置运行实验并检查行为

    解决这些问题的标准方法是什么

    实时操作系统(RTO)保证了这种延迟。它是与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涡轮增压——在高性能CPU增压后,总是有一个减速,因此CPU保持其热功率(TDP)
    • 禁用超线程——从调度程序的角度来看,这些是独立的CPU,但实际上每个超线程CPU的性能取决于另一个线程目前正在执行的操作

    希望这能有所帮助。

    谢谢你的回答。。为了排除导致问题的特定图像,我在同一图像上运行了100次该算法。即使这样,我也看到了尖峰。禁用超读功能也可能有用;另一个与您的进程竞争缓存和其他共享资源的进程可能会降低您的速度,即使您的线程从未中断。(当然,如果您的代码对三级缓存污染/干扰很敏感,则任何其他活动都会受到影响)。