【问题标题】:How can I get the CPU time for a perl system call?如何获取 perl 系统调用的 CPU 时间?
【发布时间】:2017-10-10 11:31:35
【问题描述】:

我有一个使用system() 调用外部可执行文件的perl 脚本。我想测量这些外部程序占用的 CPU 秒数。理想情况下,我想使用 shell 内置 time 命令运行它们(这是在 Linux 系统上)。像这样的:

system("time /path/to/command")

现在,time 将其输出打印到 stderr,但为了这样做,请启动在单独的子 shell 中给出的命令。这意味着,为了在 shell 中手动运行时捕获时间的输出,您需要显式使用子 shell 并重定向子 shell 的 stderr:

$ time ( command > command.log 2> command.er) 2> time.out

文件time.out 将具有time 命令的输出,而command.er 具有command 的标准错误。不幸的是,括号破坏了 perl 的系统调用:

$ time ( ls ) 2> er ## works
$ perl -e 'system("time (ls)")'
sh: 1: Syntax error: word unexpected (expecting ")")

这意味着我无法捕获time 的输出。更糟糕的是,这似乎取决于版本:

$ perl --version | head -n2
This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux-gnu-thread-multi

但如果我用新版本尝试同样的事情:

$ perl --version | head -n2
This is perl 5, version 24, subversion 1 (v5.24.1) built for x86_64-linux-thread-multi
$ perl -e 'system("time (ls)")'
file1

real    0m0.002s
user    0m0.000s
sys     0m0.000s

不幸的是,我需要它在生产机器上运行,所以升级 Perl 不是一种选择。那么,如何在 Perl 5.18 中为系统调用计时?我需要usersys 值,所以简单地记录开始和结束时间是没有帮助的。如果有必要,我愿意使用专用模块,尽管我更喜欢让我使用 shell 的time 的技巧。


更新:事实证明,行为上的差异不是因为更新的 perl 版本,而是因为我在 Arch 系统上测试了它,其 /bin/shbash,而其他命令正在运行/bin/shdash 的 Ubuntu 系统,这是一个不支持子 shell 括号的最小 shell。

【问题讨论】:

  • 您可以使用metacpan.org/pod/Capture::Tiny 直接捕获STDERR。
  • sh: 1: Syntax error 表示错误来自/bin/sh,而不是来自perl
  • @el.pescado 是的,我知道,但这是因为 perl 调用命令的方式。请注意,当直接在 shell 中运行时,同样的事情可以正常工作,更重要的是,当使用更新版本的 Perl 运行时,它也可以正常工作。
  • @simbabque 谢谢,我会试试的。但是,我担心它只会捕获命令运行的标准错误,而不是time。两者是分开的。
  • 值得记住的是,您的交互式 shell 可能与 system 调用使用的 shell 不同。通常bin/sh/bin/bash 的符号链接,但AFAIR Ubuntu 使用/bin/bash 作为交互式shell,/bin/dash 用于执行脚本(包括system)。

标签: linux perl time system-calls


【解决方案1】:

您可以使用Capture::Tiny 来捕获 Perl 中几乎所有内容的 STDOUT 和 STDERR。

use Capture::Tiny 'capture';

my ($stdout, $stderr, $exit) = capture { system "time ls" };

print $stderr;

由于某种原因,我的系统上的输出缺少一些空格,但足够清晰,可以解析出您需要的内容。

0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 2272maxresident)k
0inputs+8outputs (0major+111minor)pagefaults 0swaps

【讨论】:

  • 以前我使用qx 尝试过这个,我也很容易捕获了空白。但现在我也得到了相同的输出!
  • 好吧qx 就像反引号。它返回所有输出,这就是重点。但是 OP 特别想要 system,它返回返回码,而不是输出。
  • @AbhiNickz 我意识到这一点。而且我不明白为什么会这样。 :-/
  • 不需要使用任何此类模块,只需使用反引号即可,详细信息请参见答案stackoverflow.com/a/46486568/1760065
  • @Jerry 请重新阅读问题。这里涉及一个子shell,您建议的输出重定向不起作用。这个问题中的OP在询问之前已经排除了这一点。
【解决方案2】:

您已经使用bash 测试了该命令,但您将它传递给了sh

system("time (ls)")

简称

system("/bin/sh", "-c", "time (ls)")

但你想要

system("/bin/bash", "-c", "time (ls)")

【讨论】:

  • 好的,谢谢。我认为这不是 shell 问题,因为 i)带括号的子 shell 是 POSIX,所以我认为即使 dash(这是基于 Debian 的系统上的默认 /bin/sh)也会支持它们,并且 ii)它在我的 Arch 上工作有一个更新的 perl 版本,所以我断定这是一个 Perl 问题,忘记了 Arch 使用 bash 作为 /bin/sh叹息
【解决方案3】:
$ time ( ls ) 2> er ## works
$ perl -e 'system("time (ls)")'
sh: 1: Syntax error: word unexpected (expecting ")")

问题在于,在第一种情况下,您的外壳可能是/bin/bash,而在第二种情况下,它是/bin/sh。如果你想用另一个 shell 运行你的命令,你可以使用system LIST 形式:

system("/bin/bash", "-c", "time(ls)")

注意 1:有 PERL5SHELL environmnet 值,但这似乎在 Win32 上生效。

注意2:如果要测量子进程的CPU时间,可以使用Unix::GetrusageBSD::Resource模块。

【讨论】:

    猜你喜欢
    • 2011-05-17
    • 1970-01-01
    • 2022-12-30
    • 2019-03-20
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 2013-08-26
    • 2012-06-01
    相关资源
    最近更新 更多