Как отключить Devel :: Cover для разветвленных дочерних процессов? - PullRequest
7 голосов
/ 07 января 2020

Я заметил, что когда я запускаю свою программу с perl -MDevel::Cover=-silent,-nogcov foo.pl для сбора информации о покрытии для foo.pl, я получаю огромное замедление от частей моей программы, которые работают с c не perl программами типа tar, gzip или dpkg-deb. Благодаря этому вопросу я выяснил, как выборочно отключить 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', ...
}

При этом сбрасывается пять минут времени выполнения на тест, который , для 122 тестов экономит 10 часов вычислительного времени.

К сожалению, я не всегда могу добавить это утверждение eval в разветвленный дочерний процесс. Например, это невозможно сделать, когда я использую system(). Я хочу избежать переписывания каждого из моих system() обращений к руководству fork/exec.

Есть ли способ отключить Devel :: Cover для моих разветвленных процессов или в основном для всего, что не является моим сценарием foo.pl?

Спасибо!

Ответы [ 2 ]

1 голос
/ 09 января 2020

Я подозреваю, что ваша проблема не в форке как таковом, а в exe c. Разница несколько академична c, но может привести к возможному решению. Если вы не против собрать свою собственную версию Devel :: Cover, вы можете попробовать закомментировать эту строку: https://github.com/pjcj/Devel--Cover/blob/05392f3062dd2bdbf019d9a8fbae1b152b97d862/Cover.xs#L1140

Это приведет к тому, что любые данные о покрытии будут собраны до exe c вызов теряется и ускоряет вызов exe c.

Если вы не можете скомпилировать свою собственную версию, добавьте local *Devel::Cover::_report = sub { }; перед вызовами exe c. ускорить выполнение, но в конечном итоге это решение похоже на то, что у вас уже есть, с недостатком не использовать опубликованный API.

1 голос
/ 07 января 2020

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