5章 优化程序性能

来源:互联网 发布:淘宝的收入来源 编辑:程序博客网 时间:2024/06/10 19:18

主要探讨如何使用几种不同类型的程序优化技术,使程序运行更加快。

主要结合硬件解释了如何优化,这章不必深入追究,追究也不会明白。
必须写出清晰简洁的代码,这样左不仅为了程序员能够看懂代码,也是为了在检查代码时,别人能够读懂和理解代码。

不依赖于目标机器特性的优化

选择合适的算法和数据结构是前提,然后再进行1、2、3的基本优化。
1、消除循环的低效率

消除循环的条件测试中一些计算结果不会改变的计算。这种很简单的方法称为代码移动。编译器自己也会尽可能代码移动,但是可能调用函数具有副作用那么优化移动失败,这种情况下必须显示地帮助编译器完成代码移动,增加程序性能

2、消除不必要的过程调用

过程调用,创建栈帧会造成不小的开销,所以可以不用过程调用的地方尽量不用过程调用,直接内联即可。

3、消除不必要的存储器引用

引入临时变量(编译器会分配寄存器存储,寄存器访问快速)来存储结果,最后计算结果放回数组或全全局变量或传入地址操作,可以加速程序性能。

int strlen(const char *s)//只需要一个const,表示s不能改变s指向的数值,后面一个const不需要,因为s是形参,是实参的压栈,在这里没必要保护形参{    int len;    while(*s++ != '\0')        len++;    return len;}//大写字母比小写字母数字小32void lower(char *s){    int i;    for(i = 0 ; i < strlen(s) ; i++ ){        if(s[i] >= 'A' && s[i] <= 'Z')            s[i] += ('a' - 'A');    }}void lower1(char *s){    int i;    int len = strlen(s);//这句话就是简单的代码移动,对于大字符串,这相当有用,    //写代码就应该时刻记住这种代码移动,增加性能。时刻记住大数据。    for(i = 0 ; i < len ; i++ ){        if(s[i] >= 'A' && s[i] <= 'Z')            s[i] += ('a' - 'A');    }}
#define IDENT 1//向量操作初始值#define OP  *//乘typedef struct {    long int len;    data_t *data;}vec_rec, *vec_ptr;vec_ptr new_vec(long int len)//返回长度为len的向量{    vec_ptr result = (vec_ptr) malloc(sizeof(vec_rec));//分配一个结构体头,指向存储向量的一维数组    if (!result)        return NULL;  /*  */    result->len = len;    result->allocated_len = len;    if (len > 0) {        data_t *data = (data_t *)calloc(len, sizeof(data_t));//分配一维数组    if (!data) {        free((void *) result);        return NULL; /*  */    }    result->data = data;    }    else    result->data = NULL;    return result;//返回头指针,头指针和存储向量的地方,全部动态分配.}int get_vec_element(vec_ptr v, long int index, data_t *dest)//通过索引获取向量元素{    if (index < 0 || index >= v->len)//防止越界    return 0;    *dest = v->data[index];    return 1;}long int vec_length(vec_ptr v){    return v->len;}data_t *get_vec_start(vec_ptr v)//返回向量首地址{    return v->data;}void combine1(vec_ptr v, data_t *dest)//最原始操作,没有经过任何软件优化{    long int i;    *dest = IDENT;    for (i = 0; i < vec_length(v); i++) {        data_t val;        get_vec_element(v, i, &val);        *dest = *dest OP val;    }}void combine2(vec_ptr v, data_t *dest)//消除了循环中的低效率部分,减少了条件判断中函数的调用{    long int i;    long int length = vec_length(v);    *dest = IDENT;    for (i = 0; i < length; i++) {    data_t val;    get_vec_element(v, i, &val);    *dest = *dest OP val;    }}void combine3(vec_ptr v, data_t *dest)//消除了循环中的低效率部分,较少了循环内部的过程调用,直接通过数组索引数值{    long int i;    long int length = vec_length(v);    data_t *data = get_vec_start(v);    *dest = IDENT;    for (i = 0; i < length; i++) {        *dest = *dest OP data[i];    }}void combine4(vec_ptr v, data_t *dest)//消除了循环中不必要的内器读写(dest)。通过分配局部变量acc(此时必定分配在寄存器)。最后仅仅一次写搞定{    long int i;    long int length = vec_length(v);    data_t *data = get_vec_start(v);    data_t acc = IDENT;    for (i = 0; i < length; i++) {        acc = acc OP data[i];    }    *dest = acc;}

对于上述combine3和combine4,编译器不会自动将combine3优化为combine4,因为由于存储器的别名,将导致二者函数调用计算的结果不一样。

combine3(v , get_vec_start(v));//目的地址是第一个元素combine4(v , get_vec_start(v));//目的地址是第一个元素//二者产生结果明显不一样

依赖于目标机器特性的优化

这里主要涉及循环展开(减少循环迭代次数)等,一些操作依赖于处理器体系结构,相对比较复杂,暂时不用考虑。

小结

明白一些程序的优化,更复杂和体系结构有关的暂时先不用考虑。优化的优先原则就是选择好的数据结构和算法。

原创粉丝点击