C++ 如何找到C++;代码

C++ 如何找到C++;代码,c++,algorithm,performance,chrono,C++,Algorithm,Performance,Chrono,我试图找到一个程序的效率,我最近在stackoverflow上发布了这个程序 为了比较我的代码与其他答案的效率,我使用了chronoobject 这是检查运行时效率的正确方法吗 如果没有,那么请用一个例子提出一种方法 这是检查运行时效率的正确方法吗 看来这不是最好的办法。我发现您的方法存在以下缺陷: 对值进行排序。使用相同的算法测试排序值与未排序值时,可能会暴露荒谬的效果。可能的修复方法:对已排序和未排序的结果进行测试并比较结果 值是硬编码的。CPU缓存是一个非常复杂的问题,它可能会在硬编码

我试图找到一个程序的效率,我最近在stackoverflow上发布了这个程序

为了比较我的代码与其他答案的效率,我使用了
chrono
object

这是检查运行时效率的正确方法吗

如果没有,那么请用一个例子提出一种方法

这是检查运行时效率的正确方法吗

看来这不是最好的办法。我发现您的方法存在以下缺陷:

  • 对值进行排序。使用相同的算法测试排序值与未排序值时,可能会暴露荒谬的效果。可能的修复方法:对已排序和未排序的结果进行测试并比较结果
  • 值是硬编码的。CPU缓存是一个非常复杂的问题,它可能会在硬编码值测试和实际值测试之间引入细微的差异。在现实世界中,您不太可能对硬编码值执行这些操作,因此您可以从文件中读取这些值,也可以生成随机值
  • 值太少。代码的执行时间比计时器精度小得多
  • 您只运行代码一次。如果修复了所有其他问题并运行了两次代码,则由于缓存预热,第二次运行可能比第一次快得多:后续运行的速度往往比第一次运行的速度要小
  • 在固定大小的数据上运行一次代码。最好至少运行四次正确的测试,以覆盖以下参数的笛卡尔积:
    • 已排序与未排序的数据
    • v3
      适合CPU缓存,而
      v3
      大小超过CPU缓存。还可以考虑当<代码>(V1.LINTHORE)+V3.LINGHOTH()INTIZEOF(INT)适合缓存时,<代码>(V1.LINTHOTE)+V2.LINTHOST(+)+V3.LINTHOST()> SIZEOF(INT)适合缓存或不适合所有组合。

  • 您的方法的最大问题是:

    1)您正在测试的代码太短,无法预测。您需要至少运行它几千次,以便在测量之间至少有几百毫秒。您需要使数据集更大,更不可预测。一般来说,CPU缓存确实能够根据PITA中的合成输入数据进行精确的测量

    2)编译器可以自由地对代码重新排序。一般来说,很难确保正在计时的代码在两次调用之间执行以检查时间(除此之外,没有其他事情)。一方面,您可以进行向下优化,但另一方面,您希望度量优化的代码

    一种解决方案是关闭整个程序优化,并将计时调用放在另一个编译单元中

    另一个可能的解决方案是在测试周围使用内存围栏,例如

        std::atomic_thread_fence(std::memory_order_seq_cst);
    
    (需要
    #包括
    和一个支持C++11的编译器)


    此外,您可能希望使用探查器数据补充测量数据,以查看L1/2/3缓存的使用效率、内存瓶颈、指令失效率等。不幸的是,英特尔x86的最佳工具是商用(vtune),但在AMD x86上,类似的工具是免费的(codeXL)

    您可以考虑使用基准测试库来为您量度测量值,并处理性能测量的棘手部分,而您仍然专注于试图优化的代码。更复杂的示例可以在我在前面问题()的答案中链接的代码中找到,但是一个简单的用例如下所示:

    BENCHMARK(VectorRemoval, OriginalQuestion, 100, 1000)
    {
        std::vector destination(10000);
        std::generate(destination.begin(), destination.end(), std::rand);
        std::sample(destination.begin(), destination.end(), std::back_inserter(source), 
            100, std::mt19937{std::random_device{}()})    
    
        for (auto i: source)
            destination.erase(std::remove(destination.begin(), destination.end(), i), 
                destination.end());    
    }
    

    阅读这篇文章,了解如何对
    chrono
    调用重新排序,从而使测量结果无效。我认为多次执行同一代码会得到更好的结果,然后得到平均值。要进行正确的度量,至少需要做三件事:1)预热(在度量之前做许多类似的操作),2)找到多次调用的平均结果,3)避免编译器的过度优化(如果它可以检测到您不使用计算结果,它可以跳过它)性能测量并不容易。考虑使用一个库,这样就可以很容易地得到正确的结果。侵入性测量框架在实际测量性能方面是行不通的。你应该使用一种非侵入性的工具,如Linux PiF或英特尔VTUNE来实际测量实际性能,而不可能妨碍编译。你关于笛卡尔积使用的注释非常好。一个很好的链接可能是。请记住,一个CPU中有多个缓存。一级缓存大约为128kb,需要32000多个元素来填充缓存。二级CPU缓存的大小为1MB,您需要列表中超过25万个元素来打破缓存大小。打破8MB大小的三级缓存,看看外挂到RAM对性能的影响,这可能也很有趣。
        std::atomic_thread_fence(std::memory_order_seq_cst);
    
    BENCHMARK(VectorRemoval, OriginalQuestion, 100, 1000)
    {
        std::vector destination(10000);
        std::generate(destination.begin(), destination.end(), std::rand);
        std::sample(destination.begin(), destination.end(), std::back_inserter(source), 
            100, std::mt19937{std::random_device{}()})    
    
        for (auto i: source)
            destination.erase(std::remove(destination.begin(), destination.end(), i), 
                destination.end());    
    }