尾部调用优化(TCO)后的性能测量

时间:2008-11-22 13:13:45

标签: optimization

我知道它是什么。我的问题是: -

1。)如果我编写了适合Tail Call优化的代码(函数[递归函数]中的Last语句只是一个函数调用,那里没有其他操作)那么我需要设置任何优化级别,以便编译器做TCO。在什么样的优化模式下,编译器会为空间或时间执行TCO,优化器。

2.。)我如何找出所有编译器(MSVC,gcc,ARM-RVCT)确实支持TCO

3.)假设某些编译器执行TCO,我们启用它,那么有什么方法可以找出compielr实际上已经完成了TCO?代码大小,告诉它或循环执行它会告诉它或两者吗?

-AD

4 个答案:

答案 0 :(得分:2)

大多数编译器都支持TCO,这是一种相对古老的技术。至于如何使用特定编译器启用它,请查看编译器的文档。 gcc将在除-O1之外的每个优化级别启用优化,我认为具体的选项是-foptimize-sibling-calls。至于如何判断编译器如何进行TCO,请查看汇编器输出(例如gcc -S)或反汇编目标代码。

答案 1 :(得分:1)

  1. 优化是编译器特定的。有关它们的各种优化标志,请参阅文档
  2. 您也会在Compilers文档中找到它。如果你很好奇,你可以编写一个尾递归函数并传递一个大的参数,并留意堆栈溢出。 (如果您了解生成的代码,那么检查生成的汇编程序可能是更好的选择。)
  3. 您只需使用调试器,并查看函数参数/局部变量的地址。如果它们在调试器显示的每个逻辑帧上增加/减少(或者如果它实际上只显示一个帧,即使你进行了几次调用),你就会知道TCO是否已完成或未完成。

答案 2 :(得分:0)

如果您希望编译器进行尾调用优化,只需选中

即可

a)编译器的文档,在该文档中将执行优化级别或

b)检查asm,如果函数会调用自己(你甚至不需要大的asm知识来再次发现函数的符号)

如果你真的想要尾递归我的问题是:

为什么不自己执行尾部呼叫删除?除了删除递归之外别无其他,如果它是可移动的,那么它不仅可以由低级别的编译器实现,而且可以由算法级别实现,您可以将其直接编程到代码中(这意味着除了循环而不是给自己打电话。)

答案 3 :(得分:0)

确定是否发生尾调用的一种方法是查看是否可以强制堆栈溢出。下面的程序不会使用VC ++ 2005 Express Edition产生堆栈溢出,即使它的结果超过了long double的容量,也可以告诉你在TCO发生时正在处理所有的迭代:

    /* FibTail.c 0.00               UTF-8                    dh:2008-11-23
    * --|----1----|----2----|----3----|----4----|----5----|----6----|----*
    *
    * Demonstrate Fibonacci computation by tail call to see whether it is 
    * is eliminated through compiler optimization.
    */

    #include <stdio.h>


    long double fibcycle(long double f0, long double f1, unsigned i)
    {  /* accumulate successive fib(n-i) values by tail calls */

       if (i == 0) return f1;
       return fibcycle(f1, f0+f1, --i);
       }


    long double fib(unsigned n)
    {  /* the basic fib(n) setup and return. */
       return fibcycle(1.0, 0.0, n);
       }

    int main(int argc, char* argv[ ])
    {  /* compute some fibs until something breaks */

       int i;

       printf("\n           i                         fib(i)\n\n");

       for (i = 1; i > 0; i+=i)
       {  /* Do for powers of 2 until i flips negative 
             or stack overflow, whichever comes first */
          printf("%12d %30.20LG \n", i, fib((unsigned) i) );
          }


      printf("\n\n");
      return 0;
      }

但是,请注意,在fibcycle中进行纯尾调用的简化等同于计算出根本不执行尾调用的交互式版本(并且在编译器中可以使用或不使用TCO)。

实验可能会很有趣,以便了解TCO如何能够找到尚未接近最优且易于被迭代替换的优化。