代码之家  ›  专栏  ›  技术社区  ›  Zaid

如何在不使用模块的情况下分析子例程?

  •  3
  • Zaid  · 技术社区  · 15 年前

    我很想把这个问题重新贴上“看这块砖”。它属于什么类型的房子?

    情况是这样的:我实际上被要求对一些既不能访问两个概要文件的子例程进行概要分析(甚至 Devel::DProf 也不 Time::HiRes . 这个练习的目的是“定位”瓶颈。

    现在,我将在记录条目并退出到文件的每个子元素的开始和结束处喷洒print语句,以及 time 功能。不太理想,但在这种情况下,这是我能做的最好的选择。至少它能让我知道每个Sub被调用了多少次。

    代码在Unix下运行。我最需要的就是 perlfaq8 但这似乎没有帮助(我不知道如何 syscall ,我想知道它是否会不可预知地影响代码计时)。

    不是你每天的典型问题…

    4 回复  |  直到 15 年前
        1
  •  7
  •   Community CDub    8 年前

    This technique should work.

    基本上,如果使用 -d 标记,它将进入调试器。然后,当您运行程序时,ctrl-break或ctrl-c应该会使它在执行任何操作的过程中暂停。然后你可以打字 T 显示堆栈,并在继续之前检查任何其他变量(如果愿意)。

    做10到20次。花费大量时间的任何代码行(或者任何函数,如果您愿意的话)将大致出现在堆栈示例的百分比上,因此您不会错过它。

    例如,如果一行代码(通常是函数调用)花费20%的时间,并且您暂停程序20次,那么您将在4个堆栈样本上看到该行,给出或获取1.8个样本。如果可以避免执行该行,或者执行的时间少得多,则可以节省20%的时间。

    然后你可以重复它来发现更多的问题。

    你说目的是“定位”瓶颈。这个方法就是这样做的。测量函数执行时间只是一种非常间接的方法。

        2
  •  1
  •   DVK    15 年前
    1. 到目前为止 syscall 在这篇文章中有一个很好的例子: http://www.cpan.org/scripts/date_and_time/gettimeofday

      我认为这对以前从未使用过SysCall的人(比如我自己)来说已经足够清楚了。

    2. 我可以问一下“不能进入”的具体情况吗?

      通常可以访问CPAN模块,即使在卡上没有中央位置安装它们的情况下也是如此。下载模块有问题吗?在您的主目录中安装它?使用包含模块的软件?

      如果其中一个是挂断,它可能会被修复…如果这是公司的政策,那是无价的:(

        3
  •  0
  •   Joe McMahon    15 年前

    好吧,您可以编写自己的分析器。没有听起来那么糟。分析器只是一个非常特殊的案例调试器。你想看看 perldebguts 如果你想找到一些好的第一步代码 必须 自己写。

    你什么 希望 而你的老板想要的,尽管他或她可能不知道,是利用 Devel::NYTProf 要做好代码的分析工作,并完成任务,而不是等待您在学习如何完成代码的同时部分地复制代码的函数。

    你对“个人使用”的评论没有意义。你在为工作而工作,工作需要完成,你需要(或你的经理需要)资源来完成这项工作。”“个人使用”似乎没有进入其中。

    是否有人拒绝在模块上签字,将其安装在运行待测软件的机器上?这是许可证问题吗?是否不允许在生产机器上安装任意软件(可以理解,但在软件投入使用前必须有某种方式进行测试——我希望——在那里进行分析)?

    为什么来自可靠来源的知名模块不能使用?你有没有向你的经理说明从零开始编写一个新的、功能性较低的分析器要花更多的钱,而不是找到一种既好又可用的方法?

        4
  •  0
  •   MkV    15 年前

    对于每个子例程,在其周围创建一个包装器,它以某种格式报告时间,您可以将时间导出到R、数据库、Excel或类似的格式(csv将是一个不错的选择)。在代码中添加类似的内容。如果您使用的Perl小于5.7(当time::hires首次添加到核心时),请使用上面提到的syscall,而不是下面的time::hires函数。

    INIT {
        sub wrap_sub {
            no strict 'refs';
            my $sub = shift;
            my $subref = *{$sub}{CODE};
            return sub {
                local *__ANON__ = "wrapped_$sub";
                my $fsecs = Time::HiRes::gettimeofday();
                print STDERR "$sub,$fsecs,";
                if (wantarray) {
                   @return = eval { $subref->(@_) } or die $@;
                } else {
                   $return[0] = eval { $subref->(@_) } or die $@;
                }
    
                $fsecs = Time::HiRes::gettimeofday();
                print STDERR "$fsecs\n";
                return wantarray ? @return : $return[0];
            };
        }
        require Time::HiRes;
        my @subs = qw{the subs you want to profile};
        no strict 'refs';
        no warnings 'redefine';
        foreach my $sub (@subs) {
            *{$sub} = wrap_sub($sub);
        }    
    }
    

    将'subs you want to profile'替换为需要分析的subs,并在需要时使用open()ed文件句柄而不是stderr,记住,您可以将运行结果与脚本输出(在UNIX上,使用bourne、korn和bash shell)分开,如下所示

    perl ./myscript.pl 2>myscript.profile