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

发布于 2024-08-30 08:25:35 字数 506 浏览 2 评论 0原文

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

情况是这样的:我实际上被要求分析一些既不能访问分析器(甚至是 Devel::DProf)也不能访问 Time::HiRes 的子例程。此练习的目的是“定位”瓶颈。

目前,我在每个记录条目和退出到文件的子文件的开头和结尾加上 print 语句,以及 time 函数的结果。并不理想,但考虑到目前的情况,这是我能做到的最好的了。至少它可以让我看到每个子程序被调用了多少次。

代码在Unix下运行。我看到最接近我需要的是 perlfaq8,但这似乎没有帮助(我不知道如何进行系统调用,并且想知道它是否会不可预测地影响代码计时)。

这不是典型的日常问题......

I'm tempted to relabel this question 'Look at this brick. What type of house does it belong to?'

Here's the situation: I've effectively been asked to profile some subroutines having access to neither profilers (even Devel::DProf) nor Time::HiRes. The purpose of this exercise is to 'locate' bottlenecks.

At the moment, I'm sprinkling print statements at the beginning and end of each sub that log entries and exits to file, along with the result of the time function. Not ideal, but it's the best I can go by given the circumstances. At the very least it'll allow me to see how many times each sub is called.

The code is running under Unix. The closest thing I see to my need is perlfaq8, but that doesn't seem to help (I don't know how to make a syscall, and am wondering if it'll affect the code timing unpredictably).

Not your typical everyday SO question...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

万劫不复 2024-09-06 08:25:35

此技术应该有效。

基本上,这个想法是如果您使用 -d 标志运行 Perl,它就会进入调试器。然后,当您运行该程序时,ctrl-Break 或 ctrl-C 应使其在正在执行的操作中暂停。然后,您可以键入 T 以显示堆栈,并在继续之前检查任何其他变量(如果您愿意)。

这样做大约10或20次。花费大量时间的任何代码行(或任何函数,如果您愿意)都会粗略地出现在该百分比的堆栈样本中,因此您不会错过它。

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

然后你可以重复一遍以发现更多问题。

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

This technique should work.

Basically, the idea is if you run Perl with the -d flag, it goes into the debugger. Then, when you run the program, ctrl-Break or ctrl-C should cause it to pause in the middle of whatever it is doing. Then you can type T to show the stack, and examine any other variables if you like, before continuing it.

Do this about 10 or 20 times. Any line of code (or any function, if you prefer) costing a significant percent of time will appear on that percent of stack samples, roughly, so you will not miss it.

For example, if a line of code (typically a function call) costs 20% of time, and you pause the program 20 times, you will see that line on 4 stack samples, give or take 1.8 samples. The amount of time that could be saved if you could avoid executing that line, or execute it a lot less, is a 20% reduction in overall execution time.

Then you can repeat it to find more problems.

You said the purpose is to 'locate' bottlenecks. This method does exactly that. Measuring function execution time is only a very indirect way to do that.

墨小墨 2024-09-06 08:25:35
  1. syscall而言,这篇文章中有一个很好的例子:http://www.cpan.org/scripts/date_and_time/gettimeofday

    我认为即使对于以前从未使用过系统调用的人(比如我自己)来说,这也足够清楚了:)

  2. 我可以问“没有访问权限”的具体情况是什么吗?

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

    如果其中一个是挂断,它可能可以修复......如果这是一些公司政策,那就是无价的:(

  1. As far as syscall, there's a pretty good example in this post: http://www.cpan.org/scripts/date_and_time/gettimeofday

    I think it's clear enough even for someone who never used syscall before (like myself :)

  2. May I ask what the specifics of "having no access" are?

    It's usually possible to get access to CPAN modules, even in cases where installing them in central location is not in the cards. Is there a problem with downloading the module? Installing it in your home directory? Using software with the module incuded?

    If one of those is a hang-up it can probably be fixed... if it's some company policy, that's priceless :(

瑕疵 2024-09-06 08:25:35

好吧,您可以编写自己的分析器。这并不像听起来那么糟糕。分析器只是一个非常特殊的调试器。您需要阅读 perldebguts 手册页以获取一些好的入门代码,如果您必须自己编写。

想要以及您的老板想要的(尽管他或她可能不知道)是使用Devel::NYTProf 能够很好地分析您的代码,并完成工作,而不必等待您部分复制它的功能,同时学习它是如何工作的完成了。

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

是否是其他人拒绝签署该模块以将其安装在运行要测量的软件的机器上的问题?这是一个许可问题吗?是否不允许在生产计算机上安装任意软件(可以理解,但在软件上线之前必须通过某种方式进行测试 - 我希望 - 在那里对其进行配置)?

无法使用来自可靠来源的知名模块的原因是什么?您是否向经理证明,从头开始编写一个新的、功能较少的分析器比寻找一种使用既好又可用的分析器的方法要花更多的钱?

Well, you can write your own profiler. It's not as bad as it sounds. A profiler is just a very special-case debugger. You want to read the perldebguts man page for some good first-cut code to get started if you must write your own.

What you want, and what your boss wants, though he or she may not know it, is to use Devel::NYTProf to do a really good job of profiling your code, and getting the job done instead of having to wait for you to partially duplicate the functions of it while learning how it is done.

The comment you made about "personal use" doesn't make sense. You're doing a job for work, and the work needs to get done, and you need (or your manager needs to get you) the resources to do that work. "Personal use" doesn't seem to enter into it.

Is it a question of someone else refusing to sign off on the module to have it installed on the machine running the software to be measured? Is it a licensing question? Is it not being allowed to install arbitrary software on a production machine (understandable, but there's got to be some way the software's tested before it goes live - I hope - profile it there)?

What is the reason that a well-known module from a trustworthy source can't be used? Have you made the money case to your manager that more money will be spent coding a new, less-functional, profiler from scratch than finding a way to use one that is both good and already available?

始终不够爱げ你 2024-09-06 08:25:35

对于每个子例程,围绕它创建一个包装器,以某种格式报告时间,您可以将其导出到 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);
    }    
}

将“您想要分析的潜艇”替换为您需要分析的潜艇,并根据需要使用 open()ed 文件句柄而不是 STDERR,请记住,您可以获得与脚本输出分开的运行结果(在 Unix 上,使用 bourne、korn 和 bash shell),就像这样

perl ./myscript.pl 2>myscript.profile

For each subroutine, create a wrapper around it which reports the time in some format which you can export to something like R, a database, Excel or something similar (CSV would be a good choice). Add something like this to your code. If you are using a Perl less than 5.7 (when Time::HiRes was first added to core), use syscall as mentioned above instead of Time::HiRes's functions below.

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);
    }    
}

Replace 'subs you want to profile' with the subs you need profiled, and use an open()ed file handle instead of STDERR if you need to, bearing in mind you can get the results of the run separate from the output of the script (on Unix, with the bourne, korn and bash shells), like this

perl ./myscript.pl 2>myscript.profile
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文