18|极致优化(上):如何实现高性能的 C 程序?
该思维导图由 AI 生成,仅供参考
如何衡量程序的运行性能?
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了优化 C 代码以实现高性能程序的技巧。首先,文章介绍了衡量程序性能的指标,包括内存使用率和运行时间,并对其进行了细分。接着,作者提出了四个优化 C 代码的技巧,分别是利用高速缓存、代码内联、`restrict` 关键字以及消除不必要内存引用。文章重点强调了高速缓存的重要性,以及如何通过满足局部性原理来优化代码,同时也介绍了代码内联的概念和对程序运行的影响。总的来说,本文为读者提供了一些实用的技术指导,帮助他们了解如何编写高性能的 C 代码。文章还提到了`restrict` 关键字的作用,以及消除不必要内存引用的优化方式。通过这些技巧,读者可以更好地理解如何优化 C 代码以提升程序性能。
《深入 C 语言和程序运行原理》,新⼈⾸单¥59
全部留言(7)
- 最新
- 精选
- Geek_98aed8高速缓存的抖动: https://www.jianshu.com/p/3607c0f94526 函数中,因为CPU取块时,不同变量总不在同一个块中,导致每次都不命中,一直需要重新取;且反复取的块总是固定的几个,称为抖动 (本质是变量在内存中存放的方式不科学,这样理解?)
作者回复: 这个理解是没错的,本质上是由于程序设计正好与所在平台的高速缓存策略(包括物理特性)产生冲突导致的。比如 CSAPP 中的一个例子: float foo(float x[8], float y[8]) { float sum = 0.0; int i; for (i = 0; i < 8; i++) sum += x[i] * y[i]; return sum; } 通常情况下,一个缓存行的大小即一个块大小。简单来看,假设在一共拥有 2 个高速缓存行(比如分在两个组),且每个缓存行大小为 16 字节的计算机中,上述代码逻辑在每一次交替访问数组 x 与 y 中的元素时,便可能会产生缓存抖动。但总的来看,缓存抖动在采用了“直接映射高速缓存”的体系中较为常见,而在“全相联高速缓存”及其他缓存策略中则相对较少发生。
2022-02-1222 - 猪小擎void foo1(int *x, int *y, int *restrict z) { *x += *z; *z += 1; *y += *z; } int main(void) { int x = 10, y = 20, z = 30; foo1(&x, &y, &z); printf("%d %d %d", x, y, z); return 0; } O几都是 40,51,31.-Wall没有任何警告。如果编译器都不支持restrict的检查,这东西有意义吗?
作者回复: 这段代码在 -O1 及以上的优化等级下应该就能看到,foo1 函数在使用与不使用 restrict 关键字时的区别。需要知道的是,若一个指针已被标记为 restrict ,但在实际使用时却发生了 aliasing,此时的行为是未定义的,编译器不保证会给出提示。
2022-06-201 - qwerboo有没有一种可能,技巧四里dest因为总被访问,也会被cpu缓存。导致它其实并不是每次都会访问内存。
作者回复: 是有这种优化可能的,但通常访问寄存器是快于访问高级缓存的。
2022-06-07 - 白凤凰(当从缓存行中间开始存放数据时,字段 y 可能需要占用三个缓存行)。上面那段代码便是如此。请问老师,上面这段代码是指 struct data { char x; alignas(64) char y[118]; }; 如果没有align(64),怎么就知道y是从缓存行中间开始存放的呢?不一定占用三个缓存行啊。
作者回复: 是的,所以这里只是“可能”。因为对于这个 data 结构来说,由于它可以对齐到任意地址,因此编译器实际会如何布局,完全视程序整体实现而定。可以说是存在不确定的性能损耗风险。
2022-01-24 - i Love 3🍀请问一下,高速缓存的“抖动”和false-sharing是一回事吗?是不是都可以使用数据填充的方法来解决?
作者回复: 看了一下你提到的 “False Sharing”,是的,两者的问题和解决方案实际上都是类似的,只不过是目标主体不同。一个是同个程序的不同代码,另一个是同个程序的不同线程。
2022-01-24 - Luke其实只要记住老师教的思路就行了,不一定每个关键字都要用起来,反而导致阅读代码的人费解。。。现代编译器挺强大了,时刻在脑海里记住局部性的原则,短平的循环体这些,优秀的习惯就会是很自然的事情了😁2022-09-22归属地:江苏3
- ZR2021666,减少内存引用还是我头一次见到的优化方法,多谢老师!!!2022-01-251