从一个计算 数组累加和 的小程序看 程序性能优化 的小技巧

        最近在图书馆随便翻翻的的时候,看到一本因特尔Intel出的《多核多线程技术》,冲着名字,也得拿起来看看啊。翻过之后,内容泛泛,感觉是一门入门读物。但就是这本薄薄的一本小书,定价愣是为49.5元,可能就是因为被惯了intel的名字吧。如果希望看,还是到读书馆去看吧。

        在里面看到了一个小例子,说的是有关“性能调优方法”的,还是有点意思的。

数组累加和问题描述

已知:有一个结构体,保存两个变量:一个是指向整型数组的指针,一个该数组的长度

问题:求这个数组中所有元素的累加和,就是所有项的和

数据定义和相关方法: 如下所示

#include 
#include 

typedef struct {
    int len;
    int *data;
} vec_rec, *vec_ptr;

//分配内存,参数len表示结构体中的数组长度
vec_ptr new_vec( int len ) {
    //动态分配结构体内存
    vec_ptr result = (vec_ptr)malloc( sizeof(vec_rec) );
    if(!result) {
        return NULL;
    }
    if(len>0) {
        //动态分配数组内存
        int *data = (int *) calloc(len, sizeof(int));
        if(!data) {
            free( result );
            return NULL;
        }
        result->len = len;
        result->data = data;
    } else { //len小于0
        result->data = NULL;
        result->len = 0;
    }
    return result;
}

//获得数组指定下标的元素,在参数dest中返回,函数的结果表示是否成功获得元素值
int get_vec_element( vec_ptr v, int index, int *dest ){
    if( index < 0 || index >= v->len ){
        return 0;
    }
    *dest = v->data[index];
    return 1;
}

//获得结构体中的数组长度
int vec_length(vec_ptr v){
    return v->len;
}

//获得数组的起始位置
int * get_vec_start(vec_ptr v){
    return v->data;
}

初步解答代码如下:

 

初步解法

程序很简单,写出的计算代码和测试代码如下所示:

//第一次实现
void combine1(vec_ptr v, int* dest){
    int i;
    *dest = 0;
    for(i=0; idata[i] = i+1;
    }
    //计算累加和
    int result=0;
    combine1(p, &result);
    printf("result:  %d /n", result);//打印结果为15
    return 0;
}

优化一:消除循环不变量

在combine方法的for循环中,验证条件 i

如果验证条件里有函数调用,编译器是没有办法进行优化的。

既然vec_length的返回值是不变的,将其提取出来,代码可以修改成下面的形式:

//优化一:消除循环不变量
void combine2(vec_ptr v, int* dest){
    int i;
    *dest = 0;
    int length = vec_length(v); //提取vec_length(v)
    for(i=0; i

优化二:减少不必要的函数调用

在combine方法中,每次都要调用get_vec_element()函数,在该函数内部首先判断下标是否合法。这里包含两个开销:一个是函数调用(涉及到上下会转换,指令跳转等);一个是函数内部的条件判断;条件判断检查牵扯到条件转移指令,进而牵扯到操作系统的流水线机制中“猜测式执行”,可能会造成指令流水线停顿或回溯。

可以利用数组元素每个元素都连续存放的特点,对程序进行下面优化:

//优化二:消除不必要的函数调用
void combine3(vec_ptr v, int* dest){
    int i;
    *dest = 0;
    int length = vec_length(v); 
    int * data = get_vec_start(v);//获取开始位置
    for(i=0; i

优化三:消除不必要的内存读取

在combine方法中,循环体内每次都要对*dest执行读取操作,由于  *dest += data[i]  相当于 *dest += *dest +data[i] ,所以每次循环要进行2次内存读、1次内存写,代价比较昂贵。

如果你知道,函数中的 局部变量 一般会放到寄存器中,你就可以进行下面优化:

//优化三:消除不必要的内存读取
void combine4(vec_ptr v, int* dest){
    int i;
    //*dest = 0;  //该行可以去掉
    int result = 0; //利用局部变量保存结果
    
    int length = vec_length(v); 
    int * data = get_vec_start(v);
    for(i=0; i

总结

在你确定了程序使用的数据结构、算法、以及整体结构之后,还有几个小技巧可以继续优化你的程序:

1. 避免多余的函数调用;

2. 避免多余的条件判断和边界检查;

3. 利用局部变量保存中间计算结果;

 

本文链接:http://blog.csdn.net/daheiantian/archive/2011/02/23/6452199.aspx

你可能感兴趣的:(algorithm)