如何打印所有已执行的子例程?

时间:2018-12-16 01:54:41

标签: perl trace call-graph

例如我有以下Perl脚本

{ 
    package A;

    {
        package B;

        sub _y {
            print "Just Another Perl Hacker\n";

        }

    }

    sub _x {
        print "Hello world!\n";
        B::_y();
    }
}


use strict;
use warnings;

_x();

如何将每个带有包限定符的已执行子打印到STDERR或任何日志文件中?

例如从上面的脚本中,我希望看到以下输出:

1 A::_x()
2 B::_y()

我认为可以与Devel :: NYTProf之类的调试器一起使用,但是我没有找到用于此简单任务的特定调试器模块或其参数。

有什么想法吗?

3 个答案:

答案 0 :(得分:4)

考虑调试模块可以使您走上正确的道路。启用调试模式后,Perl会在程序的每个执行步骤中调用函数DB::DB()。在这里,您可以从内置的caller中提取子例程名称(其中将包括程序包名称),并根据需要输出。

Devel/AllSubs.pm路径中某处的名为@INC的文件开始:

package Devel::AllSubs;
my $count = 0;
my $last_sub = '::';
sub DB::DB {
    my ($pkg, $file, $line,$sub) = caller(1);
    if ($sub ne $last_sub) {
        print STDERR ++$count," $sub\n";
        $last_sub = $sub;
    }
}
1;

然后以以下方式运行程序

$ perl -d:AllSubs script.pl

示例输出:

1 A::_x
Hello world!
2 B::_y
Just Another Perl Hacker

答案 1 :(得分:3)

这可以通过标准的perl调试器完成:

$ PERLDB_OPTS="NonStop frame=1" perl -d prog.pl
  entering CODE(0x260cd78)
   entering strict::import
  entering CODE(0x260cd18)
   entering warnings::import
Package try.pl.
  entering DB::Obj::_init
  entering A::_x
Hello world!
   entering B::_y
Just Another Perl Hacker

(请注意,我必须将_x();更改为A::_x();才能运行您的代码。)

如果要将输出放置在文件中,请添加LineInfo=filenamehere。有关详情,请参见perldoc perldebug。 (特别是,如果您将选项更改为frame=2,则还会收到从子例程返回的消息。)

CODE引用用于BEGIN语句周围的隐式use块:

use strict;

真的是

BEGIN {
    require "strict.pm";
    strict->import();
}

答案 2 :(得分:2)

使用已经提到的Devel::NYTProf(更精确地说,是使用探查器而不是调试器)的替代解决方案,它不需要您编写任何其他代码就可以提供更多的信息。

% perl -d:NYTProf yourscript.pl

默认情况下,这将创建一个nytprof.out文件。然后,您可以这样做:

% nytprofcalls nytprof.out

它将为您提供详细的通话信息。一个示例脚本:

use strict;

sub f1 {
  print "hi;\n";
  f2();
}

sub f2 {
  print "hi2\n";
}

f1();

和示例输出:

main::f1;main::f2 30
main::f1;main::CORE:print 124
main::f1;main::f2;main::CORE:print 40
main::BEGIN@1 4262
main::f1 113
main::BEGIN@1;strict::import 39
main::BEGIN@1;strict::BEGIN@7 396
main::BEGIN@1;strict::BEGIN@7;strict::CORE:match 58

您可以看到NYTProf还列出了对核心函数(CORE :: print)的调用。

作为奖励,您可以使用以下命令查看整个配置文件输出:

% nytprofhtml

然后打开报告页面,例如使用:

% firefox nytprof/index.html

您可以看到已执行的子例程(按其运行时间排序),运行了多少次等等。