代码之家  ›  专栏  ›  技术社区  ›  user877329

对单个功能进行基准测试

  •  -2
  • user877329  · 技术社区  · 10 年前

    如何对函数进行基准测试?查看callgrind的结果,我发现我的程序在 pow 。由于我不需要完全的工作精度,我想我可以创建一个查找表,并在表中的点之间使用线性插值。为了能够评估查找表方法,我需要测量时间。所以我这样做了:

    #ifdef __WAND__
    target[name[test2.exe] type[application] platform[;Windows]]
    target[name[test2] type[application]]
    #endif
    
    #include <herbs/main/main.h>
    #include <herbs/tictoc/tictoc.h>
    #include <herbs/array_fixedsize/array_fixedsize.h>
    #include <random>
    #include <cstdio>
    #include <cmath>
    
    class GetRand
        {
        public:
            GetRand(double min,double max):U(min,max){}
    
            bool operator()(double* val,size_t n,size_t N)
                {
                *val=U(randsource);
                return 1;
                }
    
        private:
            std::mt19937 randsource;
            std::uniform_real_distribution<double> U;
        };
    
    int MAIN(int argc,charsys_t* argv[])
        {
        Herbs::ArrayFixedsize<double> vals(1024*1024*128,GetRand(-4,4));
    
        const size_t N=16;
        auto n=N;
        while(n)
            {
            double start=0;
            auto ptr=vals.begin();
                {
                Herbs::TicToc timestamp(start);
                while(ptr!=vals.end())
                    {
                    pow(2,*ptr);
                    ++ptr;
                    }
                }
        //  I have set cpu-freq to 1.6 GHz using cpufreq-set
            printf("%.15g\t",1.6e9*start/vals.length());
            --n;
            }
        return 0;
        }
    

    运行该程序时,每次迭代的输出约为2.25个循环。这似乎很低,因为 功率,功率 似乎是 callgrind 给了我 __ieee754_pow ).

    在x86-64上为GNU/Linux编译时,汇编中的基准循环如下所示:

        call    _ZN5Herbs6TicTocC1ERd@PLT
        movq    %r14, %rbx
        .p2align 4,,10
        .p2align 3
    .L28:
        vmovsd  (%rbx), %xmm1
        vucomisd    .LC6(%rip), %xmm1
        jb  .L25
        vmovsd  .LC7(%rip), %xmm0
        call    pow@PLT
    .L25:
        addq    $8, %rbx
        cmpq    %r12, %rbx
        jne .L28
        movq    %rbp, %rdi
        call    _ZN5Herbs6TicTocD1Ev@PLT
    

    至少 功率,功率 被调用。我能相信输出吗?或者有什么黑魔法可以消除一切。

    1 回复  |  直到 10 年前
        1
  •  1
  •   JarkkoL    10 年前

    在对功能进行基准测试时,您需要考虑的事情很少。

    1) 确保缓存未命中不会显著影响结果。在您的案例中,您遍历了大量的数据,在那里您会得到大量的缓存未命中。使用一个较小的数组,它可以很容易地放在一级缓存中,并循环多次。

    2) 确保您分析的函数调用有副作用,编译器无法优化这些调用。在您的情况下,编译器不能很好地进行优化,因为 pow() 即使没有副作用,调用也不会被优化。首选使用整数副作用来避免浮点性能的异常(例如,将浮点转换为uint32并将其相加,而不是使用浮点进行相加)。

    3) 展开循环几次以减少循环开销。目前,每个循环只执行一次pow,其中循环为这个简单的函数调用增加了相对较大的开销。

    4) 启用了完全优化和内联的配置文件。

    5) 多次运行分析以确保其他过程不会影响您的结果。选择最佳结果进行比较(即来自其他过程的干扰最小)。