提高C代码的性能

时间:2009-11-24 02:47:07

标签: c performance

提高C代码性能的最不正统的方法是什么?这是无保留的!一切都包括将循环结构改为gotos,硬编码任何东西,以奇怪的方式使用案例陈述等。不要担心可维护性,可读性等。

P.S。这个 实用......而且我很清楚如何以合理的方式提高代码的性能(在优化之前改进算法,配置文件等)

15 个答案:

答案 0 :(得分:18)

根据我的经验,优化C代码的最不正统的方法是分析应用程序,识别缓慢执行的结构和/或db命中,然后使用Big O分析设计合理的解决方案。

答案 1 :(得分:6)

Duff's Device是规范的例子。 Tom Duff承认,“这个代码在[关于案件陈述中的堕落的辩论]中形成某种论点,这很奇怪,但我不确定它是赞成还是反对”。

答案 2 :(得分:5)

快速计算逆平方根的

Abusing the constant 0x5f3759df必须排名很高......

答案 3 :(得分:4)

配置代码,查找慢点,并使用内联汇编来优化它们。

答案 4 :(得分:4)

使用内联汇编?

但是说真的,如果只是通过改变C代码就可以提高性能,那么你可以干净利落地完成它。

一些例外:

1)如果依赖于不同类型指针的对齐语义,通常可以对技术上将应用程序暴露于边界超限条件的指针执行块操作,但实际上并不是因为系统的对齐特性。因此,可以通过对齐初始char来执行内存复制,然后可以使用long *指针完成内部块。

2)如果您知道编译器分配局部变量的内存顺序,则可以巧妙地复制堆栈帧。这可能允许您实现该语言不支持的协同例程。协同程序通常是实现某种循环控制的更简单,更快捷的方法。

3)工会总是有点“hacky”但是你使用它们。它是一种用相当宽松的类型检查实现多态的方法。

4)使用C预处理器作为自动生成代码的方式通常很难调试和读取。因此,人们往往会避免这种情况。

答案 5 :(得分:3)

您是在寻找一种非正统的,没有限制但通用的优化C解决方案?

用汇编语言重写它。

答案 6 :(得分:3)

1)循环展开。如果实际上没有循环,则保存每次迭代的跳转,比较和递增 2)避免双重间接。执行检索算法通常更快,因此[y * height + x]通常比[y] [x]快。另外,与尺寸为MxN的矩形矩阵相比,大小为MxN的一维数组可以节省M(或N)个指针值。
3)尽可能使用荒谬的装配优化。例如,在x86架构上,您可以使用BSWAP指令在一个操作中交换字节,而不是普通的temp=a; a=b; b=temp;模式。

当然,不要忘记:
4)不要进行边界检查或错误处理。

有人说过,除了(2)在实践中,我会避​​免所有这些。

答案 7 :(得分:2)

我听到很多答案形式为“尝试做X,Y或Z”,但这就像是说“听,有一条鱼,一天吃得好”。

我宁愿教你如何钓鱼 - 因为性能问题。说“Profile First”的人在正确的轨道上,但(恕我直言)太胆小了。

Here's an example of aggressive performance tuning.

Here's a short explanation of why it works.

Here's a long explanation of why it works.

通过向您展示如何找到鱼的位置以及它们的大小,这将教您钓鱼。一旦找到它们,你就可以用许多美妙的方式烹饪它们(修复它们)。 最棒的是,一旦你找到并丢弃一条鱼(性能问题),其他鱼就会变大并且更容易捕获。

答案 8 :(得分:2)

对于Dathan的回答中的第3点,另一种交换方式,您可以使用xor以非常规方式交换变量。

int = 3, y = 4;
x = x ^ y; 
y = y ^ x; 
x = x ^ y; 

现在交换x和y! :)

另一方面,当你用2分割东西时,最好使用右移操作符。同样可以说乘以2,左移。

在旧的Borland C编译器中,有一个_stklen属性可以分配,以减少堆栈大小和代码。我现在还没有看到类似的东西,因为编译器技术已经发展起来了。

当使用malloc时,最好是calloc,而不是将内存初始化为零。

使用三元运算符而不是if / else语句显然更快,我想编译器编写器在机器代码生成方面变得更加智能。在这方面,我根本无法提供相关的证据,但当时Borland C 3.01统治了这一点时,它就是真实的。

使用汇编例程内联代码。

我喜欢这个问题主题,因为它让我想起过去的记忆很珍贵并且不得不将一品脱挤入夸脱罐并使用x86代码的hocus pocus技巧。感谢您发布此问题Mr.Database。

保重, 汤姆。

答案 9 :(得分:1)

答案 10 :(得分:1)

你的编译器在优化方面几乎肯定比你丑陋的尝试更好。大多数历史性的小技巧现在毫无意义。忽视可读性和可维护性的人倾向于编写代码效率最低的代码,因为真正的优化变得更加困难。

当代码以各种可能的方式进行优化并仍然需要性能提升时,在ASM中重写关键部分是最好的希望。

答案 11 :(得分:1)

在DSP应用程序中,仍然需要使用汇编语言来获得C编译器不能很好地处理的SIMD指令的最佳性能。但这不是一个真正的“C”解决方案。

我经常做的事情是使用曲线拟合软件来替换具有更快计算的近似值的函数。有时LUT仍然比进行一堆计算更快,但不像过去那样频繁。

答案 12 :(得分:1)

请参阅本章,Abrash的It’s a plain Wonderful Life(大约5页:点击每个屏幕底部的“下一步”)。

摘要(文章中的一些引言):

  • 表驱动的魔法(巨大的查找表和令人难以置信的状态机)
  • 一种性能编程方法,可以在比您可能再次看到的更高效,更紧密集成的级别上运行
  • 令人惊讶的努力经济

答案 13 :(得分:1)

对于C代码性能,没有任何非正统的做法。所有有效的技术都是“正统的”。

我发现最好的是使用可以访问CPU性能计数器的分析器,并特别注意缓存和分支未命中。尽可能添加缓存预取,并尽可能删除不可预测的分支。

不要打扰循环展开。如果分支是可预测的,那么它几乎是免费的。让编译器担心它。

在一些非常并行的体系结构(如IA64)上,将循环展开到最后都会更快。这方面的一个例子是避免C字符串函数。使用memset将字符串数组归零,使用memcpy设置字符串,使用memcmp将整个数组与另一个类似的数组进行比较。这可以使用64位加载,不必检查零终止符,如果使用64或128的“小”数组大小,可以优化为不循环或分支.memxxx()函数通常是编译器构建的 - ins和非常优化。

答案 14 :(得分:1)