cpp程序性能优化

41 篇文章 1 订阅

1.        重中之重 - 算法优化:
       程序性能优化最显著的优化方法是算法上的优化,算法的优化对性能的提升往往是一个数量级的,例如排序,冒泡的时间复杂度为O(N^2),而快速排序的时间复杂度为O(Nlog(N)),这种性能的提供是非常明显的。
      
2.       消除冗余的循环:
       我们先看一下for循环生成的汇编代码for (int N = 4, i = 0; i < N;  ++i){}
        15     movl    $4, -4(%ebp) // N = 4
        16     movl    $0, -8(%ebp) // i = 0
        17     jmp .L2
        18 .L3:
        19     addl    $1, -8(%ebp) // ++i
        20 .L2:
        21     movl    -8(%ebp), %eax
        22     cmpl    -4(%ebp), %eax // i - N
        23     setl    %al                           
        24     testb   %al, %al       
        25     jne .L3             
        
        从上面的汇编代码中可以看出每次执行循环的时候都要执行1925行这6汇编指令,因此减少循环可以提高程序性能。
        
        例如上面的代码可以写成如下开形式:
        for(int N = 4, i = 0; i < N; i += 2)
        {
              operate (i);
              operate (i + 1);
        }
        
3.        减少过程函数调用:
       我们知道程序中函数调用的开销是非常大的,我们看一下简单的函数调用的开销:
       int add ( int a , int b)
       {
              return a + b;
       }
       其汇编代码如下:
         5 _Z3addii:
         6 .LFB0:
         7     .cfi_startproc
         8     .cfi_personality 0x0,__gxx_personality_v0
         9     pushl   %ebp
        10     .cfi_def_cfa_offset 8
        11     movl    %esp, %ebp
        12     .cfi_offset 5, -8
        13     .cfi_def_cfa_register 5
        14     movl    12(%ebp), %eax //取b 
        15     addl    %eax, 8(%ebp) // a += b
        16     popl    %ebp
        17     ret
       从汇编代码中可以看出函数调用的开销是非常大的。
      
       假设有一个程序
      
       const int NUM = 100;
       int GetNum()
       {
              return NUM;
       }
       for (int i = 0; i < GetNum(); ++i)
       {
              //TODO...
       }
      
       最优化的写法是
       int iNum = GetNum();
       for (int i = 0; i < iNum; ++i)
       {
              //TODO...
       }
       当然这种写法的前提是GetNum()的数值在执行for的时候是没有变化的。
      
      
4. 消除不必要的存储器引用 : 
       void add(int * array , int len , int * res)
       {
              * res = 0;
              for (int i = 0; i < len; ++i)
              {
                     *res += array[i];
              }
       }
       其汇编代码(去掉for)
        19     movl    12(%ebp), %ebx // %ebx,存len的地址
        20     movl    16(%ebp), %edx // %edx, 存*res的地址
        21     movl    $0, (%edx)     // 写mem
        22     testl   %ebx, %ebx          
        23     jle .L4
        24     movl    $0, %eax      // i = 0;
        25 .L3:
        26     movl    (%esi,%eax,4), %ecx // 取array[i]
        27     addl    %ecx, (%edx)             // +=,写mem
        28     addl    $1, %eax                    // 
        29     cmpl    %ebx, %eax
        30     jne .L3
        
        从上面的汇编代码分析中可以看出,每次for循环都进行了写内存。我们知道读写内存是非常耗时的,因此可以对其进行优化。
        
        void add(int * array , int len , int * res)
       {
              int sum = 0;
              for (int i = 0; i < len; ++i)
              {
                     sum += array[i];
              }
              *res = sum;
       }
       //汇编
        53     movl    12(%ebp), %ecx
        54     movl    $0, %eax
        55     movl    $0, %edx // sum = 0
        56     testl   %ecx, %ecx
        57     jle .L8
        58 .L11:
        59     addl    (%ebx,%eax,4), %edx // sum += array[i];, 只写寄存器
        60     addl    $1, %eax
        61     cmpl    %ecx, %eax
        62     jne .L11
        63 .L8:
        64     movl    16(%ebp), %eax
        
        优化后的代码在循环中少了一次寄存器的读写。
        
        注意上面的代码是经过了-O选项优化的。
        
5.        增强流水线处理能力。
       现在的处理器,每个核心在会有多个执行单元,相互之间采用流水线的执行方式,如果前后两个操作没有依赖关系,可以并行执行。
       考虑一个求和的for循环
       int Array[N]; 假设N为偶数
       int sum = 0
       for (int i = 0; i < N; ++i)
       {
              sum += Array[i];
       }
      
       将其流水线化可以表示如下:
       int sum1 = 0;
       int sum2 = 0;
       for (int i = 0; i < N; i += 2)
       {
              sum1 += Array[i];
              sum2 += Array[i + 1];
       }
       sum1 += sum2;
      
       由于 
       sum1 += Array[i];
       sum2 += Array[i + 1];
       是没有相互依赖的,因此可以流水线执行。 
      
6. cache对程序性能的影响
       参看本人关于“矩阵乘积的并行”算法的讨论
      
7.       性能调试工具:
       gprof .
       $ g++ program.cpp -o program -pg
       $ ./program
       $ gprof program;
       注意一定要带-pg参数 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值