优化程序性能

优化程序技能

  • 1.优化编译器的能力和局限
    • 2.消除循环的低效率
      • 3.消除不必要的内存引用

1.优化编译器的能力和局限

大多数编译器,包括GCC,向用户提供了一些对它们所使用的优化的控制。最简单的控制就是指定优化级别,例如,以命令行选项"-og"调用GCC是让GCC使用一组基本的优化,以选项"-o1"或更高(如"-o2"或"-o3")调用GCC会让它使用更大化的优化,这样做可以进一步提高程序的性能,但是也有可能增加程序的规模,也可能使标准的调试工具更难对程序进行调试。

2.消除循环的低效率

combine1代码

1 /*Implenentation with maximum use of data abstraction */
2 void combine1(vec-ptr v, data_t *dest)
3 {
     
4      long i;
5
6      *dest = IDENT;
7      for (i= 0; i< vec_length(v);i++) [
8           data_t val;
9           get_vec_element(v, i, &val);
10          *dest = *dest OP val;
11      }
12 }

combine2代码

1 /*Move call to vec_length out of loop*/
2 void combine2(vec_ptr v, data_t *dest)
3 {
     
4      long i;
5      long length = vec_length(v);
6
7      *dest = IDENT;
8       for (i=0;i< length;i++){
     
9            data_t val;
10           get_vec_element(v, i, &val);
11           *dest = *dest OP val;
12       }
13 }

combine2代码是在combine1代码的基础上修改的代码,它在开始时调用vec_length,并将结果赋值给局部变量length。对于某些数据类型和操作,这个变换明显地影响了某些数据类型和操作的整体性能,对于其他的则只有很小甚至没有影响。
这个优化称为代码移动(code motion)。这类优化包括识别要执行多次(例如在循环里)但是计算结果不会改变的计算。因而可以将计算移动到代码前面不会被多次求值的部分。在本例中,我们将对vec_length的调用从循环内部移动到循环的前面。

3.消除不必要的内存引用

combine3代码

1 /* Direct access to vector data */ 
2 void combine3(vec_ptr v, data_t *dest)
3{
     
4       long i;
5       long length = vec_length(v);
6       data_t *data = get_vec_start(v);
7
8       *dest = IDENT;
9       for (i= 0;i < length; i++){
     
10           *dest = *dest OP data[i];
11        }
12 }

combine4代码

1 /* Accumulate result in local variable*/
2 void combine4(vec_ptr v, data_t *dest)
3 {
     
4      long i;
5      long length = vec_length(v);
6      data_t *data = get_vec_start(v);
7      data_t acc = IDENT;
8
9      for (i=0;i< length;i++){
     
10        acc = acc OP data[i];
11     }
12     *dest= acc;
13}

在combine3代码中,我们看到,指针dest的地址存放在寄存器%rbx中,它还改变了代码,将第i个数据元素的指针保存在寄存器%rdx中,注释中显示为data+i。每次迭代,这个指针都加8。循环终止操作通过比较这个指针与保存在寄存器%rax中的数值来判断。我们可以看到每次迭代时,累积变量的数值都要从内存读出再写入到内存。这样写很浪费,因为每次迭代开始时从dest读出的值就是上次迭代最后写入的值。
我们能够消除这种不必要的内存读写,按照combine4 所示的方式重写代码。引入一个临时变量acc,它在循环中用来累积计算出来的值。只有在循环完成之后结果才存放在dest中。这样我们每次迭代的内存操作从两次读和一次写减少到只需一次读。

你可能感兴趣的:(优化程序性能)