程序性能分析《一》
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//程序优化示例
//待优化程序:
//定义一个抽象类型data_t,这里data_t可以被声明为int float double; typedef int data_t ;
typedef struct
{
int len;
data_t *data;
}vec_rec ,*vec_ptr;
#define IDENT 0
#define OPER +
#define IDENT 1
#define OPER *
//创建向量组
vec_rec new_vec(int len)
{
vec_ptr result=(vec_ptr) malloc(sizeof(vec_rec));
if(!result)
return NULL;
result->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,int index, data_t * dest) {
if(index<0 || index>=v-len)
return 0;
*dest = v->data[index];
return 1;
}
int vec_length(vec_ptr v)
{
return v->len;
}
//初始版本
void combine1(vec_ptr v,data_t * dest)
{
int i;
*dest=IDENT;
for(i=0;i data_t val; get_vec_element(v,i,&val); *dest=*dest OPER val; } } /*过程combine1调用vec_length(v)作为for循环的测试条件,影响了程序的性能对于整数加法的CPE(每元素周期数)为31.25,乘法的CPE为 33.25。所以我们对其进行优化。 */ /*对于我们只是将vec_length过程移出循环,这个过程成为代码移动的优化 而这样的移动能将每个元素消除了10个时钟周期,加法的CPE变为20.66 乘法的 CPE变为21.25。这种移动在处理大型数据时尤为重要,会严重影响程序的性能。 */ //改进版本1 消除循环低效率 void combine2(vec_ptr v,data_t * dest) { int i; int length=vec_length(v); *dest=IDENT; for(i=0;i data_t val; get_vec_element(v,i,&val); *dest=*dest OPER val; } } /*从combine2 的代码中可以看出,每次循环都会调用get_vec_element 来获得一个元素,这个过程开销特别大,因为它要进行边界检查 所以我们对其进行优化,我们增加一个函数 get_vec_start 这个函数返回数组的起始地址.*/ data_t * get_vec_start(vec_ptr v) { return v->data; } //改进版 2 减少过程调用 void combine3(vec_ptr v,data_t * dest) { int i; int length=vec_length(v); data_t * data=get_vec_start(v); *dest=IDENT; for(i=0;i *dest=*dest OPER data[i]; } } /*通过改进后的combine3的加法CPE降到6.00 ,乘法降到9.0 达到了将近3.5倍的性能.*/ /*我们继续对combine3进行汇编分析)(假设为乘法): %ecx指向data,%edx指向i,%edi指向dest 1: .L18: 2 mov1 (%edi),%eax //读取 *dest 3 imull (%ecx,%edx,4),%eax //*dest *data[i] 4 movl %eax,(%edi) 5 incl %edx 6 cmpl %esi,%edx 7 jl .L18 指令2读取存放在dest中的值,指令4写回这个位置。 这正是降低性能的原因,因为下一次迭代时指令2 读取的值会是刚刚写回得那个值。 所以在优化过程中引入一个临时变量x,它用在循环中存放 计算出来的值,只有在完成循环后才存放在*dest中。 */ //改进版本3 减少存储器引用 void combine4(vec_ptr v,data_t * dest) { int i; int length=vec_length(v); data_t * data=get_vec_start(v); data_t x=IDENT; *dest=IDENT; for(i=0;i x=x OPER data[i]; } *dest=x; } /* 改进后我们发现汇编代码为: 1 L.24: