C的性能或代码大小编码实践-超出编译器的功能

C的性能或代码大小编码实践-超出编译器的功能,c,optimization,gcc,micro-optimization,C,Optimization,Gcc,Micro Optimization,我想看看程序员在C语言中能做些什么,这可以决定生成的对象文件的性能和/或大小 例如, 1.将简单的get/set函数声明为inline可能会提高性能(代价是占用更大的空间) 2.对于不使用循环变量本身的值的循环,请向下计数到零,而不是向上计数到某个值 等等 看起来编译器现在已经发展到一个完全不需要“简单”技巧(如上面两点)的水平。编译期间的适当选项仍然可以执行此任务。见鬼,我在这里也看到了关于编译器如何处理递归的帖子——这非常有趣!那么,在C级我们还剩下什么呢?:) 我的具体环境是:GCC4.3

我想看看程序员在C语言中能做些什么,这可以决定生成的对象文件的性能和/或大小

例如,
1.将简单的get/set函数声明为inline可能会提高性能(代价是占用更大的空间)
2.对于不使用循环变量本身的值的循环,请向下计数到零,而不是向上计数到某个值 等等

看起来编译器现在已经发展到一个完全不需要“简单”技巧(如上面两点)的水平。编译期间的适当选项仍然可以执行此任务。见鬼,我在这里也看到了关于编译器如何处理递归的帖子——这非常有趣!那么,在C级我们还剩下什么呢?:)

我的具体环境是:GCC4.3.3针对ARM体系结构(v4)重新定向。但其他编译器/处理器上的响应也很受欢迎,并将被大嚼一顿

PS:我的这种方法违背了通常的“先编写代码,然后进行基准测试,最后进行优化”的方法


编辑:正如所发生的那样,我在发布问题后发现了一篇类似的帖子:

我能想到的一件事是编译器可能不会优化“缓存友好性”:如果你按行的主要顺序迭代二维数组,比如,确保内部循环穿过列索引以避免缓存抖动。让内部循环运行在错误的索引上可能会导致巨大的性能损失


这适用于所有编程语言,但如果您使用C语言编程,性能可能对您至关重要,因此这一点尤其重要。

“始终”了解算法的时间和空间复杂性。编译器将永远无法像您那样出色地完成这项工作。:)

在可能的情况下进行预计算。。。(抱歉,这并不总是可能的……我在我的国际象棋引擎上做了大量的预计算。)将这些结果存储在内存中,记住缓存。。内存中预计算数据的大小越大,进行缓存命中的机会就越小。由于大多数最新的硬件都是多核的,您可以设计应用程序来瞄准它


如果您使用多个大型阵列,请确保将它们紧密地分组在使用它们的位置,提高缓存命中率。现在的编译器仍然不太擅长对代码进行矢量化,因此您仍然希望自己执行大多数算法的SIMD实现

为您的具体问题选择正确的数据结构可以显著提高性能(我见过从Kd树移动到BVH的情况,在这种特定情况下)

编译器可能会填充一些结构/变量以适合缓存,但其他缓存优化(如数据的位置)仍取决于您


编译器仍然不会自动将代码变为多线程,根据我的经验,使用openmp并没有多大帮助。(无论如何,您都必须了解openmp才能显著提高性能)。因此,目前,您正在自己进行多线程处理。

要补充Martin在上面所说的关于缓存友好性的内容:

  • 对结构进行重新排序,使通常一起访问的字段位于同一缓存线中会有所帮助(例如,只加载一条缓存线而不是两条缓存线)。这样做实际上是在增加数据缓存中有用数据的密度。有一个linux工具可以帮助你做到这一点:矮人

  • 您可以使用类似的策略来增加代码的密度。在gcc中,您可以使用可能/不可能标记来标记热分支和冷分支。这使得gcc能够单独保持冷分支,这有助于增加icache密度

现在来看看完全不同的东西:

  • 对于可能通过CPU访问(读写)的字段,相反的策略是有意义的。问题在于,出于一致性目的,只能允许一个CPU写入相同的地址(实际上是相同的缓存线)。这可能导致一种称为缓存线乒乓的情况。这非常糟糕,如果缓存线包含其他不相关的数据,情况可能会更糟。在这里,将争用数据填充到缓存线长度是有意义的

注意:这些显然是微优化,只有在您试图从代码中挤出最后一点性能时,才可以在以后的阶段进行。

许多人没有意识到这一点:定义一个内联标签(因编译器而异),这意味着内联,在其意图中,许多编译器将关键字置于与原始含义完全不同的上下文中。还有一些方法可以在编译器开始将一些琐碎的事情抛出行外之前增加内联大小限制。人工引导的内联可以生成更快的代码(编译器通常比较保守,或者没有考虑到足够的程序),但是您需要学习如何正确使用它,因为它可能(很容易)产生反效果。是的,这绝对适用于代码大小和速度。

AFAIK ARM v4处理器没有缓存。具体取决于。。。有些家庭成员这样做,有些不这样做。()通常的“先编写代码,然后进行基准测试,最后进行优化”的方法有什么错?没有错——这应该是优化的方式。我的动机是检查我是否可以实现一个重构代码的工具(在完成评测之后),以帮助开发人员快速更改性能和/或面积。想象一下一个Eclipse插件(或vim脚本),它突出显示循环,并提供选项,如展开循环或切换内部和外部循环。我应该在帖子里澄清这一点,很抱歉。谢谢你的链接!