xref: /openbsd-src/gnu/usr.bin/perl/dist/threads-shared/t/stress.t (revision fac98b93b71777a71b1e912ccaf68ce33d7b87c4)
1b39c5158Smillertuse strict;
2b39c5158Smillertuse warnings;
3b39c5158Smillert
4b39c5158SmillertBEGIN {
5b39c5158Smillert    use Config;
6b39c5158Smillert    if (! $Config{'useithreads'}) {
7b39c5158Smillert        print("1..0 # SKIP Perl not compiled with 'useithreads'\n");
8b39c5158Smillert        exit(0);
9b39c5158Smillert    }
10b39c5158Smillert    if ($^O eq 'hpux' && $Config{osvers} <= 10.20) {
11b39c5158Smillert        print("1..0 # SKIP Broken under HP-UX 10.20\n");
12b39c5158Smillert        exit(0);
13b39c5158Smillert    }
14898184e3Ssthen
1556d68f1eSafresh1    # https://lists.alioth.debian.org/pipermail/perl-maintainers/2011-June/002285.html
16898184e3Ssthen    # There _is_ TLS support on m68k, but this stress test is overwhelming
17898184e3Ssthen    # for the hardware
18898184e3Ssthen    if ($^O eq 'linux' && $Config{archname} =~ /^m68k/) {
19898184e3Ssthen        print("1..0 # Skip: m68k doesn't have enough oomph for these stress tests\n");
20898184e3Ssthen        exit(0);
21898184e3Ssthen    }
22b39c5158Smillert}
23b39c5158Smillert
24b39c5158Smillertuse ExtUtils::testlib;
25b39c5158Smillert
26b39c5158SmillertBEGIN {
27b39c5158Smillert    $| = 1;
28b39c5158Smillert    print("1..1\n");   ### Number of tests that will be run ###
29b39c5158Smillert};
30b39c5158Smillert
31b39c5158Smillertuse threads;
32b39c5158Smillertuse threads::shared;
33b39c5158Smillert
34b39c5158Smillert### Start of Testing ###
35b39c5158Smillert
36b39c5158Smillert#####
37b39c5158Smillert#
38b39c5158Smillert# Launches a bunch of threads which are then
39b39c5158Smillert# restricted to finishing in numerical order
40b39c5158Smillert#
41b39c5158Smillert#####
42b39c5158Smillert{
43b39c5158Smillert    my $cnt = 50;
44b39c5158Smillert
45e9ce3842Safresh1    # Depending on hardware and compiler options, the time for a busy loop can
46e9ce3842Safresh1    # by a factor of (at least) 40, so one size doesn't fit all.
47e9ce3842Safresh1    # For a fixed iteration count, on a particularly slow machine the timeout
48e9ce3842Safresh1    # can fire before all threads have had a realistic chance to complete, but
49e9ce3842Safresh1    # dropping the iteration count will cause fast machines to finish each
50e9ce3842Safresh1    # thread too quickly.
51e9ce3842Safresh1    # Fastest machine I tested can loop 20,000,000 times a second, slowest
52e9ce3842Safresh1    # 500,000
53e9ce3842Safresh1
54e9ce3842Safresh1    my $busycount;
55e9ce3842Safresh1    {
56e9ce3842Safresh1        my $tries = 1e4;
57e9ce3842Safresh1        # Try to align to the start of a second:
58e9ce3842Safresh1        my $want = time + 1;
59e9ce3842Safresh1        while (time < $want && --$tries) {
60e9ce3842Safresh1            my $sum;
61e9ce3842Safresh1            for (0..1e4) {
62e9ce3842Safresh1                ++$sum;
63e9ce3842Safresh1            }
64e9ce3842Safresh1        }
65e9ce3842Safresh1
66e9ce3842Safresh1        if ($tries) {
67e9ce3842Safresh1            $tries = 1e4;
68e9ce3842Safresh1            ++$want;
69e9ce3842Safresh1
70e9ce3842Safresh1            while (time < $want && --$tries) {
71e9ce3842Safresh1                my $sum;
72e9ce3842Safresh1                for (0..1e4) {
73e9ce3842Safresh1                    ++$sum;
74e9ce3842Safresh1                }
75e9ce3842Safresh1            }
76e9ce3842Safresh1
77e9ce3842Safresh1            # This should be about 0.025s
78e9ce3842Safresh1            $busycount = (1e4 - $tries) * 250;
79e9ce3842Safresh1        } else {
80e9ce3842Safresh1            # Fall back to the old default if everything fails
81e9ce3842Safresh1            $busycount = 500000;
82e9ce3842Safresh1        }
83e9ce3842Safresh1        print "# Looping for $busycount iterations should take about 0.025s\n";
84e9ce3842Safresh1    }
85e9ce3842Safresh1
86*fac98b93Safresh1    my $TIMEOUT = 600;
87b39c5158Smillert
88b39c5158Smillert    my $mutex = 1;
89b39c5158Smillert    share($mutex);
90b39c5158Smillert
91b39c5158Smillert    my $warning;
92b39c5158Smillert    $SIG{__WARN__} = sub { $warning = shift; };
93b39c5158Smillert
94b39c5158Smillert    my @threads;
95b39c5158Smillert
96b39c5158Smillert    for (reverse(1..$cnt)) {
97b39c5158Smillert        $threads[$_] = threads->create(sub {
98b39c5158Smillert                            my $tnum = shift;
99b39c5158Smillert                            my $timeout = time() + $TIMEOUT;
100b39c5158Smillert                            threads->yield();
101b39c5158Smillert
102b39c5158Smillert                            # Randomize the amount of work the thread does
103b39c5158Smillert                            my $sum;
104e9ce3842Safresh1                            for (0..($busycount+int(rand($busycount)))) {
105b39c5158Smillert                                $sum++
106b39c5158Smillert                            }
107b39c5158Smillert
108b39c5158Smillert                            # Lock the mutex
109b39c5158Smillert                            lock($mutex);
110b39c5158Smillert
111b39c5158Smillert                            # Wait for my turn to finish
112b39c5158Smillert                            while ($mutex != $tnum) {
113b39c5158Smillert                                if (! cond_timedwait($mutex, $timeout)) {
114b39c5158Smillert                                    if ($mutex == $tnum) {
115b39c5158Smillert                                        return ('timed out - cond_broadcast not received');
116b39c5158Smillert                                    } else {
117b39c5158Smillert                                        return ('timed out');
118b39c5158Smillert                                    }
119b39c5158Smillert                                }
120b39c5158Smillert                            }
121b39c5158Smillert
122b39c5158Smillert                            # Finish up
123b39c5158Smillert                            $mutex++;
124b39c5158Smillert                            cond_broadcast($mutex);
125b39c5158Smillert                            return ('okay');
126b39c5158Smillert                      }, $_);
127b39c5158Smillert
128b39c5158Smillert        # Handle thread creation failures
129b39c5158Smillert        if ($warning) {
130b39c5158Smillert            my $printit = 1;
131b39c5158Smillert            if ($warning =~ /returned 11/) {
132b39c5158Smillert                $warning = "Thread creation failed due to 'No more processes'\n";
133b39c5158Smillert                $printit = (! $ENV{'PERL_CORE'});
134b39c5158Smillert            } elsif ($warning =~ /returned 12/) {
135b39c5158Smillert                $warning = "Thread creation failed due to 'No more memory'\n";
136b39c5158Smillert                $printit = (! $ENV{'PERL_CORE'});
137b39c5158Smillert            }
138b39c5158Smillert            print(STDERR "# Warning: $warning") if ($printit);
139b39c5158Smillert            lock($mutex);
140b39c5158Smillert            $mutex = $_ + 1;
141b39c5158Smillert            last;
142b39c5158Smillert        }
143b39c5158Smillert    }
144b39c5158Smillert
145b39c5158Smillert    # Gather thread results
146b39c5158Smillert    my ($okay, $failures, $timeouts, $unknown) = (0, 0, 0, 0, 0);
147b39c5158Smillert    for (1..$cnt) {
148b39c5158Smillert        if (! $threads[$_]) {
149b39c5158Smillert            $failures++;
150b39c5158Smillert        } else {
151b39c5158Smillert            my $rc = $threads[$_]->join();
152b39c5158Smillert            if (! $rc) {
153b39c5158Smillert                $failures++;
154b39c5158Smillert            } elsif ($rc =~ /^timed out/) {
155b39c5158Smillert                $timeouts++;
156b39c5158Smillert            } elsif ($rc eq 'okay') {
157b39c5158Smillert                $okay++;
158b39c5158Smillert            } else {
159b39c5158Smillert                $unknown++;
160b39c5158Smillert                print(STDERR "# Unknown error: $rc\n");
161b39c5158Smillert            }
162b39c5158Smillert        }
163b39c5158Smillert    }
164b39c5158Smillert
165b39c5158Smillert    if ($failures) {
166b39c5158Smillert        my $only = $cnt - $failures;
167b39c5158Smillert        print(STDERR "# Warning: Intended to use $cnt threads, but could only muster $only\n");
168b39c5158Smillert        $cnt -= $failures;
169b39c5158Smillert    }
170b39c5158Smillert
171b39c5158Smillert    if ($unknown || (($okay + $timeouts) != $cnt)) {
172b39c5158Smillert        print("not ok 1\n");
173b39c5158Smillert        my $too_few = $cnt - ($okay + $timeouts + $unknown);
174b39c5158Smillert        print(STDERR "# Test failed:\n");
175b39c5158Smillert        print(STDERR "#\t$too_few too few threads reported\n") if $too_few;
176b39c5158Smillert        print(STDERR "#\t$unknown unknown errors\n")           if $unknown;
177b39c5158Smillert        print(STDERR "#\t$timeouts threads timed out\n")       if $timeouts;
178b39c5158Smillert
179b39c5158Smillert    } elsif ($timeouts) {
180b39c5158Smillert        # Frequently fails under MSWin32 due to deadlocking bug in Windows
181b39c5158Smillert        # hence test is TODO under MSWin32
18256d68f1eSafresh1        #   https://rt.perl.org/rt3/Public/Bug/Display.html?id=41574
183b39c5158Smillert        #   http://support.microsoft.com/kb/175332
184b39c5158Smillert        if ($^O eq 'MSWin32') {
185b39c5158Smillert            print("not ok 1 # TODO - not reliable under MSWin32\n")
186b39c5158Smillert        } else {
187b39c5158Smillert            print("not ok 1\n");
188b39c5158Smillert            print(STDERR "# Test failed: $timeouts threads timed out\n");
189b39c5158Smillert        }
190b39c5158Smillert
191b39c5158Smillert    } else {
192b39c5158Smillert        print("ok 1\n");
193b39c5158Smillert    }
194b39c5158Smillert}
195b39c5158Smillert
196b39c5158Smillertexit(0);
197b39c5158Smillert
198b39c5158Smillert# EOF
199