C#:这是标杆级准确吗?(C#: Is this benchmarking class accura

2019-07-20 11:56发布

我创建了一个简单的类,以基准我的一些方法。 但它是准确的? 我有点新标杆,定时,等等,所以以为我可以问一些反馈在这里。 另外,如果是好的,也许别人可以利用它,以及:)

public static class Benchmark
{
    public static IEnumerable<long> This(Action subject)
    {
        var watch = new Stopwatch();
        while (true)
        {
            watch.Reset();
            watch.Start();
            subject();
            watch.Stop();
            yield return watch.ElapsedTicks;
        }
    }
}

您可以使用它像这样:

var avg = Benchmark.This(() => SomeMethod()).Take(500).Average();

任何反馈? 它看起来是相当稳定的,准确的,或有我错过了什么?

Answer 1:

这大约是准确的,因为你可以得到一个简单的基准。 但也有一些因素不是你的控制之下:

  • 从其他过程的系统上的负载
  • 基准期间/前堆的状态

你可以做一些关于最后一点,基准是在哪里调用罕见的情形之一GC.Collect可辩护。 你可以称之为subject一次事先以消除任何JIT的问题。 但是,这需要调用subject独立。

public static IEnumerable<TimeSpan> This(Action subject)
{
    subject();     // warm up
    GC.Collect();  // compact Heap
    GC.WaitForPendingFinalizers(); // and wait for the finalizer queue to empty

    var watch = new Stopwatch();
    while (true)
    {
        watch.Reset();
        watch.Start();
        subject();
        watch.Stop();
        yield return watch.Elapsed;  // TimeSpan
    }
}

对于奖金,你的类应该检查System.Diagnostics.Stopwatch.IsHighResolution领域 。 如果它是关闭的,你只有一个很粗的(20毫秒)的分辨率。

但是,一个普通的PC机,并在后台运行许多服务,它是永远不会是非常准确的。



Answer 2:

这里夫妇的问题。

首先,记住你运行该代码的第一次,其方法调用的传递闭包将被实时编译。 这意味着,在第一次运行可能比以后每运行成本较高。 根据您是否标杆“冷”定时或“热”的时序,这可能有所作为。 我所看到的方法,其中jitting方法的成本比所有其他调用它放在一起更高!

二,请记住,垃圾收集器在另一个线程上运行。 如果你是在一个运行制作垃圾,然后清理垃圾的费用可能无法实现,直到suebsequent运行。 因此,你没有能够占一个运行的总成本,通过关闭它强加给后上运行。

这两者都是指示所有标杆的弱点:基准测试是不现实的性质,因此价值有限。 在现实世界中的代码时,GC将要运行的抖动将是运行的,等等。 这是经常的是基准性能一点也不像真实世界的性能,因为基准并没有考虑到现实世界的变化成本在一个大系统中固有的情况。 而不是分析孤立PERF的特点,我喜欢看的由真正的客户真正面对现实的设想PERF特性。



Answer 3:

你一定要返回ElapsedMilliseconds而不是ElapsedTicks。 通过ElapsedTicks返回的值是依赖于频率秒表,其可以是在不同的系统不同。 它不一定会对应一个时间跨度或DateTime对象的蜱财产。

见http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.elapsedticks.aspx 。

如果想蜱的额外的分辨率,你应该返回watch.Elapsed.Ticks (即Timestamp.Ticks),而不是watch.ElapsedTicks (这可能是在.NET中的微妙的潜在错误之一)。 从MSDN:

秒表蜱从DateTime.Ticks不同。 在DateTime.Ticks值每个刻度表示一个100毫微秒的时间间隔。 在ElapsedTicks值每刻度表示的时间间隔等于1秒除以频率。

除此之外,我想你的代码是好的,但我认为你会包括一些对您的测量方法,调用开销,如果方法本身需要很少的时间来执行,这可能是显著的。 此外,你可能会想从你计算的平均排除的方法的第一个电话,但我不知道你会怎么做,在你的类。

最后一点,这很可能是不相关的这一类的多数用途:秒表运行有点快比系统时间。 在我的电脑,它在24小时后获得约5秒(这是 ,而不是毫秒)进取,在其他机器上这种漂移可能更大。 所以这是一个有点误导,说这是高度准确的 ,当它实际上只是非常精细 。 对于时序持续时间短的方法,这显然不会是一个显著的问题。

还有一点最后一点,这肯定相关的:我经常注意到标杆的同时,我会得到一堆的运行时间被所有狭窄的范围值内聚集(如80,80,79,82等) ,但偶尔别的东西将在Windows发生(如打开另一个程序或我对什么抗病毒踢),我会疯狂地得到一个值不与他人(如80,80,79,271,80等走出低谷)。 我认为,一个简单的解决这个问题的异常是用您的测量 ,而不是平均的。 我不知道LINQ的自动或不支持此功能。



Answer 4:

由于我不是一个C#程序员,我不能准确的任何协议,类是用于计数功能的执行需要多长时间合适的实现说。 然而,有一些事情要记住的重复性和准确性。

我不起来在.NET Framework的各种来龙去脉,而是取决于它如何编译为本地代码,它可能是可能的,任何编译会影响测试结果。 此外,功能是否在高速缓存中能够有所作为,太。 所以你要循环的功能,以确保没有从编译命中,一切都被加载并准备就绪。 一旦这样做了,你也许就能上手。

其他人可能会有.NET更好的信息和知识比我好。



文章来源: C#: Is this benchmarking class accurate?