一种生成运行时递归调用树的工具

时间:2011-03-03 12:39:55

标签: c++ c algorithm

是否有一个简单的工具来为递归算法生成运行时调用树?如下面的计算Fibonacci数:

call tree for computing Fibonacci number

更具体地说,如果算法是用C / C ++实现的呢?

编辑:我想让这棵树分析递归算法的复杂性。我知道如何生成树。以前我只是在soure文件中添加一些“cout”并生成一个点文件并使用graphviz生成树。但我想知道是否有一些好的工具,这样我就可以节省编写代码的时间。

编辑:Fibonacci编号的示例代码是

//fib.cpp
#include<iostream>
typedef int Int;

Int fib(Int n)
{
  if (n==0)
    return 1;
  else if (n==1)
    return 1;
  else
    return fib(n-2)+fib(n-1);
}

int main()
{
  std::cout<<fib(5)<<std::endl;
  return 0;
}

我已经为这个简单的代码尝试了valgrind但是找不到如何获取图形。我使用的命令如下:

g++ fib.cpp
valgrind --tool=callgrind ./a.out
kcachegrind callgrind.out.4343

我是否错过了一些选项或什么?

4 个答案:

答案 0 :(得分:6)

使用callgrind(cmdline)然后使用kcachegrind(gui)可视化调用树。它是'valgrind'套件中的工具之一。

Callgrind是一个分析工具,它还允许您查看完整的调用树。您通过在程序上运行它来收集性能分析信息,然后使用kcachegrind分析callgrind信息的输出。

其他编辑:不幸的是,我刚刚发现这只会对部分进行递归调用,在这种情况下看起来就像一个存根调用自身多次。即使callgrind将执行动态调用图,它也会在此处显示传递和返回的值。静态调用图工具将具有相同的输出(没有调用的次数)。

这将是这样,而不是你想要的:

enter image description here

我想找出哪个序列以及调用递归函数的参数和返回值的唯一方法是执行回溯(gdb或backtrace()函数)并可视化该输出(通过graphviz)。有这方面的工具,但据我所知,不是免费提供/开源。

答案 1 :(得分:1)

我认为没有这样的工具,但您可以手动创建树(然后根据您的喜好打印它。对于该特定算法,树节点将类似于:

struct node {
   int value;
   int result;
   node *left;
   node *right;
   node( int value ) : value(value), result(), left(), right() {}
};

然后你可以修改函数以允许它构造树:

int fibo( int value, node*& ptr )
{
   ptr = new node( value );
   ptr->result = fibo( value-1, ptr->left ) + fibo( value-2, ptr->right );
   return ptr->result;
}

最初称之为:

node* tree;
fibo( 5, tree );

然后处理你构建的树。

答案 2 :(得分:0)

您可以实现树并存储对活动叶的引用。

答案 3 :(得分:0)

“获取运行时调用树”是什么意思? 您想获取某个数组中的调用列表吗?

如果你想在运行时获得所有调用的列表,你可以简单地创建这些函数并在每个函数中打印一些东西(或添加到矢量或其他内容),例如:

int fib(int i) {
  int ret;
  printf("fib(%d)\n",i);
  if (i>2) ret=fib(i-2)+fib(i-1);
  else ret=i;
  printf("fib-end(%d)\n",i);
}

如果您想在编译时获得类似的东西,可以尝试以下方法:

template <int i>
inline int fib() {
  //do something
  return fib<i-2>()+fib<i-1>();
}

template <>
inline int fib<0>() {return 0;}

tempalte <>
inline int fib<1>() {return 1;}

在后一种情况下,fibonacci数将在编译时计算,因此所有函数调用都将被扩展并且常量会崩溃,从而导致代码将在恒定时间内进行评估。