【问题标题】:Measure the runtime of a program run via perl "open"测量通过 perl "open" 运行的程序的运行时间
【发布时间】:2017-11-09 01:39:24
【问题描述】:

我正在开发一个带有测试套件的库,该套件使用 Perl open 来运行它的测试。它看起来像这样:

open (MYOUT, "$myprog $arg1 $arg2 $arg3 2>&1 |") die "Bad stuff happened";

我真正想做的是测量$myprog 的运行时间。不幸的是,仅在 open 命令周围获取开始时间和结束时间只是大致获取启动进程所需的时间。

是否有某种方法可以强制open 命令完成该过程(从而准确地测量时间),或者可能有其他方法可以完成同样的事情?

关键限制是我们需要捕获(可能很多)STDOUTSTDERR

【问题讨论】:

  • $myprog 是什么/做什么?
  • 这是一个任意的 Linux 命令。在我的例子中,它是一个 MPI (mpi-forum.org) 程序,可以运行几分钟。

标签: perl


【解决方案1】:

既然你打开了一个管道,你需要从opening之前到至少读完之后的时间

use warnings;
use strict;
use Time::HiRes qw(gettimeofday tv_interval sleep);

my $t0 = [gettimeofday];

open my $read, '-|', qw(ls -l) or die "Can't open process: $!";

while (<$read>)
{
    sleep 0.1;
    print;
}

print "It took ", tv_interval($t0), " seconds\n";
# close pipe and check 

或者,为了计时整个过程,在管道上调用close之后(所有读取完成之后)

my $t0 = [gettimeofday];
open my $read, '-|', qw(ls -l)  or die "Can't open process: $!";
# ... while ($read) { ... }
close $read  or 
    warn $! ? "Error closing pipe: $!" : "Exit status: $?";
print "It took ", tv_interval($t0), " seconds\n";

close 阻塞并等待程序完成

关闭管道还会等待在管道上执行的进程退出——以防你想在之后查看管道的输出——并将该命令的退出状态值隐式放入$? [。 ..]

有关状态检查,请参阅 $? variable in perlvarsystem

如果定时程序分叉并且不以阻塞方式对其子级进行wait,这将无法正确计时。 在这种情况下,您需要识别他们使用的资源(文件?)并对其进行监控。

我想补充一点,外部命令应该小心组合在一起,以避免 shell 注入问题。一个好的模块是String::ShellQuote。参见例如this answerthis answer

使用模块来捕获流可以让您从 shell 中解放出来,并且可能会打开其他方式来运行和更可靠地计时。一个好的是Capture::Tiny(还有其他的)。

感谢 HåkonHægland 提供 cmets。感谢ikegami 让我直截了当,使用close(而不是waitpid)。

【讨论】:

  • 或者,您可以添加另一个 fork() 作为整个事物的包装。然后在waitpid() 之后找到那个fork 的运行时
  • @HåkonHægland 是的,我正在考虑以某种方式手动添加注释。但这并不能解决问题,我认为。
  • 是的,我没有想清楚..我认为额外的分叉无济于事..它需要从句柄读取直到 EOF(如您所示)或在返回的 PID 上使用 waitpid() open
  • @HåkonHægland 对,我认为现在没有更好的方法,相应更新。
  • 谢谢。我错过了脚本中的close(MYOUT)。由于读取输出的开销,我将在那里有一些额外的时间,但这可能没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-08
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多