App-psst
view release on metacpan or search on metacpan
# Attempt to determine whether the shell is forking per prompt.
# Likely to be flaky.
#
# Likely outcomes,
# broken: can't see pids
# sequential=1 <n>: Perl eats one per line
# promptburn=2 <n>: Bash & Perl each eat one per line
# random: no discernable pattern (e.g. on OpenBSD)
#
# PID wrap should not cause problems. Fast PID churn from other
# sources might require larger $N to get non-weird results.
sub pidseq_subtest {
my ($N) = @_;
my $retrying = defined $N;
$N ||= 50;
# print many prompts, examine pid issued to the process requested
my $run = ". t/bashrc\n".("perl -e 'print qq{pid:\$\$\\n}'\n" x $N);
my $txt = bash_interactive($run, maxt => $N / 5);
my @pid = ($txt =~ m{^pid:(\d+)$}mg);
if ($N != @pid) {
return sprintf('broken: see %d/%d pid: lines', scalar @pid, $N);
}
# Very basic stats. Output elements are
#
# "$diff1 <$count_significant>"
# "($diff2 x$count_insignificant)"
my %hist; # key = line-to-line difference in PID; value = event count
while ($#pid) {
my $diff = $pid[1] - (shift @pid);
$hist{$diff} ++;
}
$N --; # we are now interested in differences between PIDs; sample of these is smaller
my @hist; # output elements
my @diff_sig; # $diff which are significant
my $thres = sqrt($N);
foreach my $diff (sort {$hist{$b} <=> $hist{$a}} keys %hist) {
my $count = $hist{$diff};
my $sig = $count / $thres;
$count .= "/$N" if !@hist; # show total on first ele
my $ele = $sig > 1 ? "$diff <$count>" : "($diff x$count)";
push @diff_sig, $diff if $sig > 1;
push @hist, $ele;
}
my $raw = join ', ', @hist;
$raw .= sprintf('; thres=%.2f', $thres);
# Summarise
if (0 == @diff_sig) {
return "random: $raw";
} elsif (1 == @diff_sig) {
my $diff = $diff_sig[0];
my $type = { 1 => 'sequential', 2 => 'promptburn' }->{$diff} || 'weird';
return "$type=$raw";
} else {
if ($retrying) {
return "weird (not unimodal.. not enough trials? system busy?): $raw";
} else {
diag("weird pidseq ($raw) - going to try harder");
return pidseq_subtest($N * 10);
}
}
}
sub deansi { # removes ANSI/vt100 codes we use
my ($txt) = @_;
$txt =~ s{\x1b\[([0-9;]*)m}{dv(c => $1)}eg; # colour
$txt =~ s{\x1b\[([0-2]?)K}{dv(e => $1)."\n"}eg; # erase
$txt =~ s{\x1b([78])}{dv(sr => $1)."\n"}eg; # save/restore
$txt =~ s{\x1b\[(\d*[A-D])}{dv(udrl => $1)."\n"}eg; # up/down/right/left
$txt =~ s{\r*\n+[\r\n]*}{\n}g; # compaction to visible linebreaks
return $txt;
}
sub dv { # deansi: hackable verbosity, for debugging; breaks tests
return $ENV{TEST_DEANSI_SHOW} ? "(($_[0] => $_[1]))" : '';
}
main();
( run in 0.700 second using v1.01-cache-2.11-cpan-995e09ba956 )