5

我有一个基准测试应用程序来测试我编写的一些 API 的性能。在这个基准测试应用程序中,我基本上使用 QueryPerformanceCounter 并通过将调用 API 前后 QPC 值的差异除以频率来获取时间。但是如果我从不同的驱动器运行应用程序(在同一组 Dll 上运行的相同可执行文件),基准测试结果似乎会有所不同。此外,在特定驱动器上,第一次运行应用程序、关闭应用程序并再次运行它会产生不同的基准测试结果。谁能解释这种行为?我在这里错过了什么吗?

一些更有用的信息:

行为是这样的:运行应用程序,关闭它并再次运行它,基准测试结果似乎在第二次运行时有所改善,此后保持不变。这种行为在从 C 盘运行的情况下更加突出。我还想提一下,我的基准应用程序可以选择重新运行/重新测试特定的 API,而无需关闭应用程序。我确实知道这涉及到 jitting,但我不明白的是,在第一次运行应用程序时,当您在不关闭应用程序的情况下多次重新运行 API 时,性能在运行几次后稳定下来,然后当您关闭并重新运行时同样的测试,性能似乎有所提高。

此外,您如何考虑从不同驱动器运行时的性能变化?

[信息更新]

我做了一个ngen,现在来自同一位置的不同运行之间的性能差异消失了。即如果我打开基准应用程序,运行一次,关闭它并从同一位置重新运行它,它会显示相同的值。

但是我现在遇到了另一个问题。当我从 D 驱动器启动应用程序并运行它几次(在同一启动基准程序中的 API 迭代几次),然后从第 3 次迭代开始,所有 API 的性能似乎下降了 20% 左右. 然后,如果您关闭并重新启动应用程序并运行它,对于前 2 次迭代,它会给出正确的值(与从 C 获得的值相同),然后性能再次超出该值。从 C 盘运行时看不到此行为。从 C 盘开始,无论您运行多少次,它都非常一致。

我正在使用大型双数组来测试我的 API 性能。我担心 GC 会在测试之间启动,所以我在每次测试之前和之后都明确地调用 GC.Collect() 和 GC.WaitForPendingFinalizers()。所以我认为这与GC无关。

我尝试使用 AQ 时间来了解从第 3 次迭代开始发生了什么,但有趣的是,当我使用 AQ 时间分析它运行应用程序时,性能根本没有下降。

性能计数器 as 不建议任何有趣的 IO 活动。

谢谢尼兰詹

4

4 回答 4

4

运行应用程序会将其可执行文件和其他文件从硬盘驱动器带入操作系统的磁盘缓存(在 RAM 中)。如果稍后再次运行,这些文件中的许多很可能仍在缓存中。RAM 比磁盘快得多。

当然,一个磁盘可能比另一个更快。

于 2009-01-23T09:21:40.483 回答
3

是的。它被称为即时编译。基本上,您的应用程序被部署为 MSIL(Microsoft 中间语言),并且在第一次运行时它会被转换为本机代码。

您始终可以运行 NGen(请参阅上面的文章),或者在性能测试脚本中设置一个预热期,在实际对性能进行基准测试之前,它会在场景中运行几次。

于 2009-01-23T06:10:57.667 回答
1

我认为这里有多种效果:

首先,在测试工具中多次运行相同的功能,每次使用相同的数据,可能会有所改善,因为:

  • JIT 编译将优化最频繁运行的代码以提高性能(正如Cory Foy已经提到的)
  • 程序代码将在磁盘缓存中(正如Crashwork已经提到的)
  • 一些程序代码如果足够小并且足够频繁地执行,它将在 CPU 缓存中

如果测试工具中函数每次运行的数据都不同,这可以解释为什么再次关闭并运行测试工具会改善结果:数据现在将在磁盘缓存中,这不是第一次。

最后,是的,即使两个“驱动器”在同一个物理磁盘上,它们也会有不同的性能:从磁盘外部读取数据的速度比内部读取速度快。如果它们是不同的物理磁盘,那么性能差异似乎很可能。此外,一个磁盘可能比另一个磁盘碎片更多,从而导致更长的寻道时间和更慢的数据传输速率。

于 2009-01-23T17:31:11.540 回答
1

此外,其他因素可能正在发挥作用。机器上的文件系统缓存,最近使用的数据的缓冲等。

最好运行多个测试(或数百个!)并在整个集合中取平均值,除非您专门测量冷启动时间。

于 2009-01-23T18:04:21.067 回答