深入了解计算机系统——利用循环展开对程序的优化

本文详细介绍了如何从算法、数据结构、函数调用、内存引用等角度优化程序运行速度,包括CPE的概念、消除无谓的函数调用、内存访问优化、基于处理器机制的深度优化,以及吞吐量和循环展开策略,同时讨论了寄存器溢出和分支预测对优化的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

系列文章:
操作系统详解(1)——操作系统的作用
操作系统详解(2)——异常处理(Exception)
操作系统详解(3)——进程、并发和并行
操作系统详解(4)——进程控制(fork, waitpid, sleep, execve)
操作系统详解(5)——信号(Signal)

如何优化一个程序的运行速度?可以从以下几个方面着手:

  • 算法
  • 数据结构
  • 执行的步骤
  • 循环

本文将主要从计算机系统底层方面,探讨如何降低运行时间。

一些概念

CPE

即Cycles Per Element, 运行每一个操作需要的时钟周期

T = CPE*n + Overhead
n: 操作数量
overhead: 其它操作时延

初步优化

以下是一个粗糙的c程序代码:

 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;
	}
}
/*
v: 一个向量
dest: 存储执行结果
OP: 运算符, 可以是+, *等
vec_length: 返回向量长度
get_vec_element: 范围下标为i的元素, 存放在val中
IDENT: 单位元, 加法就是0, 乘法就是1
*/

CPE如下:(Element为执行一次循环)
image.png

可见gcc自带的优化也能对性能起到很大影响.本例中是O1优化.

消除不必要的函数调用

void combine2(vec_ptr v, data_t *dest)
{
   
    long i;
    long 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;
  }
}

由于v的长度是定长的, 不会被循环改变, 所以可以在循环前面先得到, 这样就不用每次循环都调用一次了.

image.png

在本例中优化幅度很小.但是由于length()的时间复杂度是O(n), 当v的长度很大的时候, 循环执行n次, 时间复杂度为O(n^2), 增长速度远远大于O(n)

消除不必要的内存引用

假设v结构体中存储数据的部分是一个数组, 我们用get_vec_start函数能够获取v的指向数组开头的指针, 那么可以得到一下代码:

void combine3(vec_ptr v, data_t *dest)
{
   
    long i;
    long length = vec_length(v);
    data_t *data = get_vec_start
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值