# 第05章：优化程序性能

## [视频解说](https://www.bilibili.com/video/BV1RK4y1R7Kf?p=5)

## 导读

程序优化涉及的范围实在是太广了，几乎每个层面都可以进行优化，比如撰写<编译器友好型>以及<缓存友好型>的程序，针对不同的目标硬件平台还可能进行特定的优化，等等，优化的难点在于你需要对系统有充分理解，当然了在你做优化之前**首先要保证原始程序功能正确（并且有回归测试）**，否则一切都是徒劳。

{% hint style="info" %}
首先需要理解，哪些因素会影响程序的性能
{% endhint %}

![](/files/-MW3-YvMvttjaQymhCZf)

**温馨提醒：**&#x4E;othing can fix a dumb algorithm!  == 没有什么能修正一个愚蠢的算法 !

**历史**：第一个编译器是由美国女性计算机科学家葛丽丝·霍普（Grace Hopper）于1952年为A-0 系统编写的。但是1957年由任职于IBM的美国计算机科学家约翰·巴科斯（John Warner Backus）领导的FORTRAN则是第一个被实现出具备完整功能的编译器。1960年，COBOL成为一种较早的能在多种架构下被编译的语言。首个能编译自己源程序的LISP编译器是在1962年由麻省理工学院的Hart和Levin制作的。

![](/files/-MVpRctEbtdAxWKF_Oef)

题外话：1947年9月9日，葛丽丝·霍普（Grace Hopper）还发现了第一个电脑上的bug。当在Mark II计算机上工作时，整个团队都搞不清楚为什么电脑不能正常运作了。经过大家的深度挖掘，发现原来是一只飞蛾意外飞入了一台电脑内部而引起的故障。这个团队把错误解除了，并在日记本中记录下了这一事件。也因此，人们逐渐开始用“Bug”（原意为“虫子”）来称呼计算机中隐藏的错误。

**编译器领域最早成名的教材**： *Compilers: Principles,Techniques,and Tools，*&#x4E2D;文名（龙书）：*编译原理*

本书的一大特点就是抽象难懂，主要讨论了编译器设计的重要主题，包括词法分析、语法分析、语义分析、中间代码生成、代码优化、代码生成等过程。

![](/files/-MVt07nkwuQI_FXvP0i7)

2020年图灵奖宣布授予哥伦比亚大学计算机科学名誉教授 Alfred Vaino Aho 和斯坦福大学计算机科学名誉教授 Jeffrey David Ullman，以表彰他们在编程语言实现（programming language implementation）领域基础算法和理论方面的成就。

![](/files/-M_ugEhl2vBOk-9hayT_)

**从教科书回到现实世界（工业强度的现代编译器）**：[GCC](https://gcc.gnu.org/)，[LLVM](https://llvm.org/)

![](/files/-M_umJNUDWeMPXdpWw96)

例如，GCC实现的时候做了两层的中间码，分别是GIMPLE中间码，RTL中间码。代码生成阶段要考虑对应的指令集架构的寄存器使用，以及考虑流水线的调度。

![](/files/-M_uTav6aNVXfEf46IWC)

![](/files/-M_pZppOMGOcPG42B-yt)

## **学习方式**

[CMU教授的视频教程 - Lecture10：程序性能优化 (Program Optimization)](https://www.bilibili.com/video/BV1a54y1k7YE?p=13)

<div align="center"><img src="/files/-Ma6IS3tlQ8Szu1aW9-O" alt="系统性能优化的诸多着眼点"></div>

![编译器优化思路以及它的局限性](/files/-Ma6KgoEFTAGrKG4eOfJ)

## **重点示例**

例1：编译器聪明但保守，有时候你写的程序会阻止编译器做优化（precedure side-effects）

![](/files/-Ma6Sb-bxAgH7QWW4T_b)

![](/files/-Ma6SxSp_c4dpZpWcDFN)

例2：编译器聪明但保守，有时候你写的程序会阻止编译器做优化（memory alising）

```c
int fn (int *a, int *b)
{
    *a = 3;
    *b = 4;
    return (*a + 5);
}

// 编译器会把以上代码优化成下面的样子么？不会！谁知道程序员会不会这么调用 f(&x,&x);
int fn (int *a, int *b)
{
    *a = 3;
    *b = 4;
    return (3 + 5);
}

// 但是你可以帮助编译器，使用C99的restrict类型限定符，但还是需要开发者确保两个指针不指向同一数据
// https://gcc.gnu.org/onlinedocs/gcc/Restricted-Pointers.html
int fn (int *__restrict__ a, int *__restrict__ b)
{
    *a = 3;
    *b = 4;
    return (*a + 5); // 这里会被优化为 return (3 + 5)
}
```

例3：善用编译器的特定选项或者开关（当然也需要处理器支持），利用有限的资源创造出最大的价值。

{% hint style="info" %}
请参考教学投影片（p22\~）以及CMU教授的视频讲解，与原始程序相比，性能达到了数十倍（甚至百倍）的提升，其中使用到了许多优化方面的技巧，比如 code motion，loop unrolling，auto vectorization，etc，相信会对你有所启发。
{% endhint %}

## 作业解答

（无）

## 实验解读

（无）


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fengmuzi2003.gitbook.io/csapp3e/di-5-zhang-cheng-xu-de-you-hua.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
