深入理解计算机系统_第5章 优化程序性能

编写高效程序需要做到以下几点:
1) 选择适当的算法和数据结构;
2) 编写出编译器能够有效优化的代码;(需要理解编译器优化的能力和局限性)
3) 将一个任务拆分为多个任务,执行并行计算;
编译器可能受到妨碍优化的因素的影响,从而不能很好地执行优化;妨碍优化的因素就是程序中那些严重依赖于执行环境的方面,程序员应该避免产生妨碍优化的因素,写出简洁的代码,支撑编译器优化;

编译器优化的第一步(不依赖于目标机器):消除不必要的工作,包括消除函数调用条件测试内存引用
编译器优化的第二部(依赖于目标机器):利用处理器的特性,利用指令级并行的能力,同时执行多条指令。降低一个计算不同部分之间的数据相关,增加并行度,就可以同时执行这些部分;
研究汇编代码, 通过确认关键路径来决定执行一个循环所需要的时间(时间下界);关键路径是在循环的反复执行过程中形成的数据相关链;

5.1 优化编译器的能力和局限性

-Og:表示基本的优化;
编译器必须很小心地只对程序使用安全的优化,编译器必须保证在任何情况下,优化前端程序和优化后的程序具有一样的行为;
1) 内存引用导致潜在的内存别名
一般而言,编译器会进行优化以降低内存引用;
两个指针同时指向一个内存位置的情况称为:内存别名使用;由于编译器必须执行安全的优化,编译器必须假设不同的指针可能指向同一个位置。但是一些函数,其两个参数都是指针,这两个指针都指向同一内存地址时候,其运算结果会有不同,基于这种情况, 编译器不会进行优化;
2) 函数调用
一般而言,编译器会进行优化以减少函数调用;
如果一个函数中改变了全局变量的值,优化函数调用次数后,全局变量改变的次数就会不一样。编译器不能假设这个函数不改变全局变量, 所以编译器不会优化函数调用;
编译器会将简单的函数调用优化为内联函数;

gcc 编译器只尝试在单个文件中定义的函数优化成内联;
一些情况下需要阻止编译器执行内联替换:
1) 使用符号调试器来执行评估代码;
2) 使用代码剖析方式评估程序性能,使用内联替换消除的函数调用时无法被正确剖析的;
gcc并不能进行比较激进的优化功能,因此需要程序员自己编译效率高的代码;

5.2 表示程序性能

度量程序性能的指标:每元素的周期数CPE, CPE帮助我们理解迭代程序的循环性能;

5.3 程序示例

typedef long data_t;
typedef struct{
   
	long len;
	data_t *data;
}vec_rec, *vec_ptr;

vec_ptr new_vec(lonng len)
{
   
	vec_ptr result = (vec_ptr)malloc(sizeof(vec+rec));
	data_t *data = NULL;
	if(!result)
		return NULL;
	result->len = len;
	if(len > 0){
   
		data = (data_t *)calloc(len, sizeof(data_t));
		if(!data){
   
			free((void *)result);
			return NULL;
		}
	}
	result->data = data;
	return result;
}

int get_vec_element(vec_ptr v, long index, data_t u&dest)
{
   
	if(index < 0 || index >= v->len)
		return 0;
	*dest = v->data[index];
	return 1;
}

long vec_length(vec_ptr v)
{
   
	return v->len;
}

combine 函数将数组data中的所有数据经过OP运算累积到一个数

void combine1(vec_ptr v, data_t *dest)
{
   
	long i;
	*dest = IDENT;
	for(i = 0; i < vec_length(v); i++){
   
		data_t val;
		get_vec_element(v, i, &val);
		*dest = *dest OP val;
	}
}

5.4 消除循环中的低效率

原则:尽量减少在循环中的计算、函数调用等消耗资源的代码;
这种优化方式称为代码移动,识别循环中需要多次执行但是计算结果不会改变的计算,将代码移动到循坏外部;
一般的编译器都会优化,进行代码移动。但是对于在哪里调用函数或是调用多少次变换,编译器都会很小心(就是说编译器可能优化,可能不优化);

//combine 减少了函数调用vec_length(v)

void combine2(vec_ptr v, data_t *dest)
{
   
	long i
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值