ibm1620 has asked for the wisdom of the Perl Monks concerning the following question:

Hello Perlmonks,

I'm having trouble debugging a heavily random program because I'm unable to force it to repeat its behavior.

After reading perlrun and web-searching a bit I concluded that the following snippet at the top of the program might do the trick:

#!/usr/bin/env perl use v5.36; BEGIN { srand(1); # rand generator is repeatable $ENV{PERL_PERTURB_KEYS}=0; # traversing keys is repeatable $ENV{PERL_HASH_SEED}=1; # hashing is repeatable? }
In addition to calling rand() to choose an array index, it also traverses lists of key(%hash). As far as I know, those are the only places where randomness can occur. (No hashes are modified after they're constructed at initialization.)

I gather from perldoc perlrun ("this mode is as close to pre 5.18 behavior as you can get.") that perhaps there are no guarantees anymore?

Can anyone suggest what I might be doing wrong or overlooking?

Replies are listed 'Best First'.
Re: Repeatable rand() and keys() for debugging
by choroba (Cardinal) on Dec 09, 2022 at 17:30 UTC
    It's too late to set the env vars in the begin block, they must be set in the process that runs Perl itself.

    This works:

    PERL_PERTURB_KEYS=0 PERL_HASH_SEED=1 perl -lE 'say for keys %{ { qw( a + 1 b 2 c 3 d 4 ) } }' c d a b

    If you really insist on doing it from Perl itself, the following seems to work:

    #! /usr/bin/perl use warnings; use strict; use feature qw{ say }; if (($ENV{PERL_PERTURB_KEYS} // 1) != 0 || ($ENV{PERL_HASH_SEED} // 0) + != 1) { $ENV{PERL_PERTURB_KEYS} = 0; $ENV{PERL_HASH_SEED} = 1; exec $^X, $0, @ARGV } say for keys %{ { qw( a 1 b 2 c 3 d 4 ) } }, @ARGV;

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Thanks - that appears to be working consistently now.

      I can see now why it's more practical to just write a wrapper shell script to set the env vars, and then invoke perl.