perl5 icon indicating copy to clipboard operation
perl5 copied to clipboard

Add support for PERL_RAND_SEED env var

Open demerphq opened this issue 3 years ago • 0 comments

The idea of this env var is to provide consistent behavior to scripts that call srand() with no arguments, either implicitly or explicitly. This is implemented in such a way that each process in the process tree should get unique but repeatable initialization.

Eg

$ PERL_RAND_SEED=123 ./perl -Ilib -le'print map { chr(65+rand 26) } 1..10'
HKYDDJQVSD
$ PERL_RAND_SEED=123 ./perl -Ilib -le'print map { chr(65+rand 26) } 1..10'
HKYDDJQVSD

Should produce the same results in each time. Similarly if the program forks() or starts subthreads the Nth forked child should get the same initialization each time, and each child should be seeded differently from the parent similarly to how the seed would normally be randomly initialized. In the below example the | sort -n sorts the results by which fork they come from so that it is more obvious they are producing the same results

$ PERL_RAND_SEED=123 ./perl -Ilib -le'for my $n (1..5) { my $pid= fork(); if (!$pid) { print $n,map { chr(65+rand 26) } 1..10; exit} }' | sort -n
1ZFKXOTACST
2IXQXRCLXGV
3YZSNSMOBHX
4BNSLRHINMT
5SFCPDTHIRV

$ PERL_RAND_SEED=123 ./perl -Ilib -le'for my $n (1..5) { my $pid= fork(); if (!$pid) { print $n,map { chr(65+rand 26) } 1..10; exit} }' | sort -n
1ZFKXOTACST
2IXQXRCLXGV
3YZSNSMOBHX
4BNSLRHINMT
5SFCPDTHIRV

The exact seeding is deliberately unspecified, although in practice when no sub processes are involved it should be equivalent to calling srand($ENV{PERL_RAND_SEED}) at the top of the script, however each fork() or thread->create() call could change the exact value the mother process uses if the use of rand() or srand() occurs post fork. The main point is that if the program is executed twice it should produce the exact same results from rand() and srand() assuming all other factors are equal:

PERL_RAND_SEED=1 ./perl -Ilib -le'for my $n (1..5) { my $pid= fork(); if ($pid) { push @pids, $pid} else { print join ", ",$n,map { sprintf "%08x", srand() } 1..10; exit} } waitpid $_,0 for @pids; printf "%08x\n", srand() for 1..5'
1, 80a42501, 8484e763, 1579e1b7, 00adb710, 7fb26ad7, 6ffae7c3, 53515602, 4bb4738a, 7d6f7c68, cea49639
2, 8dcef731, 36372a05, bd8b947e, 2f824c7c, a7b2103a, 53117ee0, e5655046, a2db49f0, b740ac42, fbdf19e6
3, 7de9d161, bf7f82e3, ab5b6b32, 01944dac, 8c10be3c, e1390937, c3eeae38, d31d00ac, 121f9c28, d2c77045
4, be5614a4, e497f265, 41b0be08, 98433330, 3a8cc862, d39bede2, 6ad8a4d1, b615c5f0, dbd39605, 8b7f330c
5, 8a3616fb, 55c3036f, 8071ceb8, 8d74df0b, c4233c61, d646fb76, 2c2fc3a2, 5f26d86f, 0144353a, 7b85efab
00000001
2c6f5bd0
25b2331a
19f91cb2
77877125

The new env var does NOT change behavior of scripts using srand() with an argument.

This can be combined with PERL_HASH_SEED and PERL_INTERNAL_RAND_SEED to produce a repeatable test run of of code that does not hard initialize the random number generator. We document that users cannot expect consistency except in the most constrained circumstance of a given perl executable, but in practice the results should be stable (all other things considered) which we porters can exploit to test the feature in the perl test suite.

This includes a few patches for issues that came up while I testing this with our test suite along with PERL_HASH_SEED=0 and PERL_INTERNAL_RAND_SEED=123.

demerphq avatar Aug 06 '22 18:08 demerphq