gpt4 book ai didi

haskell - 如何获得一致的标准基准,或跨运行解释结果?

转载 作者:行者123 更新时间:2023-12-03 23:36:44 26 4
gpt4 key购买 nike

我正在尝试优化一些代码,使用标准来尝试比较,例如添加INLINE的效果一个函数的编译指示。但我发现重新编译/运行的结果不一致。

我需要知道如何使结果在运行中保持一致以便我可以比较它们,或者如何评估基准是否可靠,即(我猜)如何解释有关方差的细节,“时钟调用”等。

我的特殊情况的详细信息

这与我上面的主要问题是正交的,但在我的特定情况下,有几件事可能会导致不一致:

  • 我正在尝试进行基准测试 IO使用 whnfIO 的操作因为使用 whnf 的方法在 this example没有用。
  • 我的代码使用并发
  • 我有很多标签和废话打开

  • 示例输出

    两者都来自相同的代码,以完全相同的方式编译。我直接在下面进行了第一次运行,进行了更改并进行了另一个基准测试,然后恢复并再次运行了第一个代码,编译为:
    ghc --make -fforce-recomp -threaded -O2 Benchmark.hs

    第一次运行:
    estimating clock resolution...                                      
    mean is 16.97297 us (40001 iterations)
    found 6222 outliers among 39999 samples (15.6%)
    6055 (15.1%) high severe
    estimating cost of a clock call...
    mean is 1.838749 us (49 iterations)
    found 8 outliers among 49 samples (16.3%)
    3 (6.1%) high mild
    5 (10.2%) high severe

    benchmarking actors/insert 1000, query 1000
    collecting 100 samples, 1 iterations each, in estimated 12.66122 s
    mean: 110.8566 ms, lb 108.4353 ms, ub 113.6627 ms, ci 0.950
    std dev: 13.41726 ms, lb 11.58487 ms, ub 16.25262 ms, ci 0.950
    found 2 outliers among 100 samples (2.0%)
    2 (2.0%) high mild
    variance introduced by outliers: 85.211%
    variance is severely inflated by outliers

    benchmarking actors/insert 1000, query 100000
    collecting 100 samples, 1 iterations each, in estimated 945.5325 s
    mean: 9.319406 s, lb 9.152310 s, ub 9.412688 s, ci 0.950
    std dev: 624.8493 ms, lb 385.4364 ms, ub 956.7049 ms, ci 0.950
    found 6 outliers among 100 samples (6.0%)
    3 (3.0%) low severe
    1 (1.0%) high severe
    variance introduced by outliers: 62.576%
    variance is severely inflated by outliers

    第二次运行,慢 3 倍:
    estimating clock resolution...
    mean is 51.46815 us (10001 iterations)
    found 203 outliers among 9999 samples (2.0%)
    117 (1.2%) high severe
    estimating cost of a clock call...
    mean is 4.615408 us (18 iterations)
    found 4 outliers among 18 samples (22.2%)
    4 (22.2%) high severe

    benchmarking actors/insert 1000, query 1000
    collecting 100 samples, 1 iterations each, in estimated 38.39478 s
    mean: 302.4651 ms, lb 295.9046 ms, ub 309.5958 ms, ci 0.950
    std dev: 35.12913 ms, lb 31.35431 ms, ub 42.20590 ms, ci 0.950
    found 1 outliers among 100 samples (1.0%)
    variance introduced by outliers: 84.163%
    variance is severely inflated by outliers

    benchmarking actors/insert 1000, query 100000
    collecting 100 samples, 1 iterations each, in estimated 2644.987 s
    mean: 27.71277 s, lb 26.95914 s, ub 28.97871 s, ci 0.950
    std dev: 4.893489 s, lb 3.373838 s, ub 7.302145 s, ci 0.950
    found 21 outliers among 100 samples (21.0%)
    4 (4.0%) low severe
    3 (3.0%) low mild
    3 (3.0%) high mild
    11 (11.0%) high severe
    variance introduced by outliers: 92.567%
    variance is severely inflated by outliers

    我注意到,如果我按“时钟调用的估计成本”进行缩放,这两个基准非常接近。这是我应该做的来获得比较的实数吗?

    最佳答案

    虽然这里肯定没有足够的信息来查明每个问题,但我有一些建议可能会有所帮助。

    解释标准结果

    被识别为异常值的样本的问题在于,该标准无法真正判断它们是否是异常值,因为它们是垃圾数据,或者它们是否是由于某种合法原因而不同的有效数据。它可以强烈暗示它们是垃圾(“方差严重膨胀”这一行),但这真正意味着您需要调查您的测试环境、您的测试或您的应用程序本身,以确定异常值的来源。在这种情况下,它几乎肯定是由系统负载引起的(基于您提供的其他信息)。

    您可能有兴趣阅读 BOS 的 announcement of criterion ,它更详细地解释了它的工作原理,并通过一些示例来说明系统负载如何影响基准测试过程。

    我非常怀疑“时钟调用的估计成本”的差异。请注意,异常值的比例很高(在两次运行中),并且这些异常值具有“高度严重”的影响。我将这解释为意味着所选择的时钟计时标准是垃圾(可能在两次运行中),使其他一切也不可靠。正如@DanielFischer 所建议的那样,关闭其他应用程序可能有助于解决这个问题。最坏的情况可能是硬件问题。如果您关闭所有其他应用程序并且时钟计时仍然不可靠,您可能需要在另一个系统上进行测试。

    如果您在同一系统上运行多个测试,则每次运行的时钟时序和成本应该相当一致。如果不是,则说明时间会受到影响,从而导致数据不可靠。

    除此之外,这里有两个随机的想法可能是一个因素。

    CPU负载

    线程运行时可能对 CPU 负载很敏感。默认 RTS 值适用于许多应用程序,除非您的系统负载很重。问题是垃圾收集器中有一些临界区,所以如果 Haskell 运行时资源匮乏(因为它与其他应用程序竞争 CPU 或内存),所有进程都可能被阻塞,等待这些部分。我已经看到这对性能的影响是 2.5 倍,这或多或少与您看到的三倍差异一致。

    即使垃圾收集器没有问题,来自其他应用程序的高 CPU 负载也会影响您的结果,应尽可能消除。

    如何诊断

  • 使用 top或其他系统实用程序来检查 CPU 负载。
  • 运行 +RTS -s .在静态的底部,寻找这些行

  • -RTS -s 输出
    gc_alloc_block_sync: 0
    whitehole_spin: 0
    gen[0].sync: 0
    gen[1].sync: 0

    非零值表示垃圾收集器中的资源争用。此处的大值表示存在严重问题。

    怎么修
  • 关闭其他应用程序
  • 指定您的可执行文件应该使用少于所有内核(例如 +RTS -N6+RTS -N7 在 8 核机器上)
  • 禁用并行垃圾收集(使用 +RTS -qg )。与禁用并行收集器相比,我通常通过保留空闲内核获得更好的结果,但是 YMMV。

  • 输入/输出

    如果您进行基准测试的函数正在执行任何类型的 I/O(磁盘、网络等),则您需要非常小心地解释结果。磁盘 I/O 会导致性能的巨大差异。如果您对 100 个样本运行相同的函数,则在第一次运行后, Controller 可能会缓存任何 I/O。或者,如果在两次运行之间访问了另一个文件,您可能必须进行头部搜索。其他 I/O 通常也好不到哪里去。

    如何诊断
  • 您可能已经知道您的函数是否在执行 I/O。
  • 工具,如 lsof可以帮助追踪神秘的 I/O 性能

  • 怎么修
  • 模拟 I/O。创建一个虚拟磁盘。除了实际访问硬盘驱动器等之外的任何其他内容。
  • 如果您确实必须对实际 I/O 操作进行基准测试,请尽量减少来自其他应用程序的干扰。也许使用专用驱动器。关闭其他应用程序。一定要采集多个样本,注意它们之间的差异。
  • 关于haskell - 如何获得一致的标准基准,或跨运行解释结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11712234/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com