优化程序性能(USTC).ppt.ppt
文本预览下载声明
优化程序性能 张 琦 (Qi Zhang) CS, USTC xiaoga@mail.ustc.edu.cn Dec. 2007 提纲 优化程序基本方法 优化编译器的能力和局限性 程序示例 消除循环的低效率 减少过程调用 消除不必要的存储器引用 降低循环开销 转换到指针代码 提高并行性 优化效果小结 确认和消除性能瓶颈 基本方法 编写高效的程序 选择一组最好的算法和数据结构 编写出编译器能够有效优化以转换成高效可执行程序的源代码 基本策略 在实现和维护的简单性与运行速度之间做出权衡折衷 只运行少数几次的程序 减少编程工作量 需要反复执行的程序 仔细的优化 提纲 优化程序基本方法 优化编译器的能力和局限性 程序示例 消除循环的低效率 减少过程调用 消除不必要的存储器引用 降低循环开销 转换到指针代码 提高并行性 优化效果小结 确认和消除性能瓶颈 优化编译器的能力和局限性 编译器会帮助我们做一些优化 命令行选项 –O –O2 –O3 编译器优化的局限性 不能改变正确的程序行为 对程序行为、环境的了解有限 需要很快完成编译工作 编译器优化的局限性 – 指针 void twiddle1(int *xp, int *yp) { *xp += *yp; *xp += *yp; } //访存6次 void twiddle2(int *xp, int *yp) { *xp += 2 * (*yp); } //访存3次 twiddle1与twiddle2是等价的么? 编译器优化的局限性 – 指针 考虑 xp==yp 的情况 *xp += *xp; *xp += *xp; = *xp增加为以前的4倍 *xp += 2 * (*xp); = *xp增加为以前的3倍 妨碍优化的因素 编译器必须假设不同的指针可能会指向存储器中的同一个位置(memory aliasing) 编译器优化的局限性 – 函数调用 int f ( int ); int func1( int x ) { return f(x) + f(x) + f(x) + f(x); } int func2( int x ) { return 4*f(x); } 编译器优化的局限性 – 函数调用 int counter = 0; int f(int x) { return counter++; } - 改变调用f的次数会改变程序的行为 - 通常编译器会保持所有的函数调用不变 提纲 优化程序基本方法 优化编译器的能力和局限性 程序示例 消除循环的低效率 减少过程调用 消除不必要的存储器引用 降低循环开销 转换到指针代码 提高并行性 优化效果小结 确认和消除性能瓶颈 程序示例 typedef struct { int len; data_t *data; } vec_rec, *vec_ptr; vec_ptr new_vec (int len); int get_vec_element(vec_ptr v, int index, data_t *dest); int vec_length(vec_ptr v); 程序示例 void combine1(vec_ptr v, data_t *dest) { *dest = 0; for(int i=0; i vec_length ( v ) ; i++) { data_t val; get_vec_element(v, i, val); *dest = *dest + val; } } 提纲 优化程序基本方法 优化编译器的能力和局限性 程序示例 消除循环的低效率 减少过程调用 消除不必要的存储器引用 降低循环开销 转换到指针代码 提高并行性 优化效果小结 确认和消除性能瓶颈 消除循环的低效率 for(int i=0; i vec_length(v); i++) Void combine2(vec_ptr v, data_t *dest) { int length = vec_length(v); *dest = 0; for(int i=0;ilength;i++) { data_t val; get_vec_element(v, i, val); *dest = *dest + val; } } 代码移动 (code motion) 识别出要执行多次但是计算结果不会改变的计算 把计算移动到代码前面的、不会被多次求值的部分 循环内部 - 循环外部 练习1 size_t strlen(const char *s); void lower1(char *s) { for(int i=0;istrlen(s);i++) if(s[i]=‘A
显示全部