【问题标题】:How do I disable Devel::Cover for forked child processes?如何为分叉的子进程禁用 Devel::Cover?
【发布时间】:2020-01-07 07:25:23
【问题描述】:

我注意到,当我使用 perl -MDevel::Cover=-silent,-nogcov foo.pl 运行我的程序以收集 foo.pl 的覆盖率信息时,我的部分程序的运行速度大幅下降,这些程序分叉和执行非 perl 程序,如 tar、@987654325 @ 或 dpkg-deb。感谢this question 我想出了如何选择性地禁用Devel::Cover,所以我现在写:

my $is_covering = !!(eval 'Devel::Cover::get_coverage()');
my $pid = fork();
if ($pid == 0) {
    eval 'Devel::Cover::set_coverage("none")' if $is_covering;
    exec 'tar', '-cf', ...
}

这样做,每次测试减少了 5 分钟的运行时间,对于 122 次测试,我节省了 10 小时的计算时间。

不幸的是,我不能总是将此 eval 语句添加到分叉的子进程中。例如,当我使用system() 时,这是不可能的。我想避免将我的每个system() 调用重写为手动fork/exec

有没有办法为我的分叉进程或基本上不是我的脚本foo.pl 的所有内容禁用 Devel::Cover?

谢谢!

【问题讨论】:

    标签: perl code-coverage devel-cover


    【解决方案1】:

    Forks::Super 有点重,但它具有分叉后回调的特性,在每个分叉之后但在子进程中的任何其他代码执行之前执行。

    use Forks::Super;
    my $is_covering = !!(eval 'Devel::Cover::get_coverage()');
    POSTFORK_CHILD {
        # runs in every child process immediately after fork()
        eval 'Devel::Cover::set_coverage("none")' if $is_covering;
    };
    ...
    

    【讨论】:

    • 我的脚本现在不依赖于 perl 核心模块以外的任何东西。这个模块甚至没有打包在 Debian 或 Ubuntu 中... :(
    • 此外,这种技术的缺点是它会禁用Devel::Cover,即使我在不​​调用 exec 的情况下分叉自己。在这些情况下,我显然不想禁用Devel::Cover。完美的解决方案会明确告诉Devel::Cover:“仅跟踪此文件,但如果执行另一个文件则停止跟踪”。所以我宁愿不需要一个 POSTFORK 钩子,而是需要一个 pre-exec 钩子。
    【解决方案2】:

    我怀疑您的问题不在于 fork 本身,而在于 exec。差异在一定程度上是学术性的,但可能会导致可能的解决方案。如果您不介意编译自己的 Devel::Cover 版本,可以尝试注释掉这一行:https://github.com/pjcj/Devel--Cover/blob/05392f3062dd2bdbf019d9a8fbae1b152b97d862/Cover.xs#L1140

    这将导致 exec 调用之前收集的所有覆盖率数据丢失并加快 exec 调用。

    如果您无法编译自己的版本,在 exec 调用之前添加 local *Devel::Cover::_report = sub { }; 也应该会加快 exec 的速度,但这最终是与您已经拥有的解决方案类似的解决方案,但缺点是不使用已发布的 API。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 2011-01-17
      • 2010-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-16
      相关资源
      最近更新 更多