您使用什么编码技术来优化C程序?

您使用什么编码技术来优化C程序?,c,optimization,C,Optimization,几年前,我参加了一个面试小组,面试一个相对高级的嵌入式C程序员职位的候选人 我问的一个标准问题是关于优化技术。我很惊讶有些候选人没有答案 那么,为了给子孙后代列出一份清单,在优化C程序时,您通常使用哪些技术和结构 速度和大小优化的答案都被接受。收集代码执行的配置文件可以让您实现50%的目标。另外50%负责分析这些报告 此外,如果您使用GCC或VisualC++,您可以使用“配置文件引导优化”,编译器将从以前的执行中获取信息,并重新调度指令,以使CPU更愉快。我最喜欢的技术是使用好的配置文件器。如

几年前,我参加了一个面试小组,面试一个相对高级的嵌入式C程序员职位的候选人

我问的一个标准问题是关于优化技术。我很惊讶有些候选人没有答案

那么,为了给子孙后代列出一份清单,在优化C程序时,您通常使用哪些技术和结构


速度和大小优化的答案都被接受。

收集代码执行的配置文件可以让您实现50%的目标。另外50%负责分析这些报告


此外,如果您使用GCC或VisualC++,您可以使用“配置文件引导优化”,编译器将从以前的执行中获取信息,并重新调度指令,以使CPU更愉快。

我最喜欢的技术是使用好的配置文件器。如果没有一个好的配置文件告诉你瓶颈在哪里,就没有任何技巧和技巧可以帮助你。

我遇到的最常见的技巧是:

  • 循环展开
  • 循环优化以实现更好的缓存预取 (即,在M个循环中进行N次操作,而不是NxM次奇异操作)
  • 数据对齐
  • 内联函数
  • 手工制作的asm片段
至于一般性建议,其中大部分已经提出:

  • 选择更好的算法
  • 使用分析器
  • 如果不能提供20-30%的性能提升,则不要进行优化
      • 首先,使用更好/更快的算法。优化设计缓慢的代码是没有意义的
      • 优化速度时,以内存换取速度:查找预计算值表、二叉树、编写更快的系统调用自定义实现
      • 当以速度换取内存时:使用内存压缩

        • 避免使用堆。对大小相同的对象使用obstack或池分配器。将寿命短的小东西放在堆栈上。alloca仍然存在。

          对于低级优化:

        • ffmpeg中的START_TIMER/STOP_TIMER宏(任何代码测量的时钟级精度)
        • 当然,用于分析的Oprofile
        • 大量手工编码的程序集(只需在x264的/common/x86目录下执行wc-l,然后记住大部分代码都是模板化的)
        • 一般而言,仔细编码;代码越短越好
        • 智能低级算法,比如我编写的64位位位流编写器,它只使用一个if,不使用else
        • 考虑到处理器的重要方面,比如
        • 发现可以无损或接近无损地提前终止的情况,其中提前终止检查的成本远低于从中获得的速度
        • 实际上,内联汇编用于更适合x86 SIMD单元的任务,例如中值计算(需要对MMX支持进行编译时检查)

        • 早熟优化是万恶之源!
          ;)

          由于我的应用程序在设计上通常不需要太多CPU时间,所以我将重点放在磁盘和内存中二进制文件的大小上。我主要做的是寻找静态大小的数组,并用动态分配的内存替换它们,以后释放内存是值得的。为了减少二进制文件的大小,我寻找在编译时初始化的大数组,并将初始化放到运行时

          char buf[1024] = { 0, };
          /* becomes: */
          char buf[1024];
          memset(buf, 0, sizeof(buf));
          
          这将从binaries.DATA节中删除1024个零字节,并在运行时在堆栈上创建缓冲区,然后用零填充

          编辑:哦,是的,我喜欢缓存东西。它不是特定于C的,但取决于缓存的内容,它可以极大地提高性能


          附言:请在你的名单完成后告诉我们,我很好奇

          还有一件事没有提到:

          • 了解你的需求:不要针对不太可能发生或永远不会发生的情况进行优化,而是专注于最划算的事情

            • 内联函数!受分析迷的启发,我分析了我的一个应用程序,发现了一个小功能,可以在MP3帧上进行一些位移位。在我的应用程序中,大约90%的函数调用都是由它来完成的,所以我把它做成了内联的,瞧,这个程序现在占用的CPU时间是以前的一半。

              首先要做的事情-不要过早优化。花时间仔细优化一段代码,却发现它并不是您认为的瓶颈,这种情况并不少见。或者,换一种方式说,“在你让它快起来之前,让它工作起来”

              在优化代码之前,调查是否有优化算法的选项。通过优化一个糟糕的算法比优化代码更容易找到性能上的改进,只有在你改变算法的时候才抛弃它

              并找出你首先需要优化的原因。你想达到什么目标?例如,如果您试图提高对某些事件的响应时间,请确定是否有机会改变执行顺序以最小化时间关键区域。例如,当试图改善对某些外部中断的响应时,您可以在事件之间的死区时间内做任何准备吗

              一旦您决定需要优化代码,您将优化哪一位?使用分析器。将注意力(首先)集中在最常使用的领域

              那么你能对这些领域做些什么呢

              • 尽量减少状况检查。检查条件(例如循环的终止条件)是指没有花费在实际处理上的时间。使用循环展开等技术可以最大限度地减少条件检查
              • 在某些情况下,条件检查也可以通过使用函数指针来消除。例如,如果您正在实现一个状态机,您可能会发现实现
                for (i=n; i!=0; --i) { ... }
                
                for (i=0; i!=n; ++i) { ... }
                
                struct Customer
                {
                    int ID;
                    int AccountNumber;
                    char Name[128];
                    char Address[256];
                };
                
                Customer customers[1000];
                
                struct CustomerAccount
                {
                    int ID;
                    int AccountNumber;
                    CustomerData *pData;
                };
                
                struct CustomerData
                {
                    char Name[128];
                    char Address[256];
                };
                
                CustomerAccount customers[1000];