summaryrefslogtreecommitdiff
path: root/lib/Memoize/t/speed.t
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Memoize/t/speed.t')
-rwxr-xr-xlib/Memoize/t/speed.t52
1 files changed, 44 insertions, 8 deletions
diff --git a/lib/Memoize/t/speed.t b/lib/Memoize/t/speed.t
index d887aae60c..ef30a8138d 100755
--- a/lib/Memoize/t/speed.t
+++ b/lib/Memoize/t/speed.t
@@ -7,11 +7,28 @@ if (-e '.fast') {
print "1..0\n";
exit 0;
}
+$| = 1;
+
+# If we don't say anything, maybe nobody will notice.
+# print STDERR "\nWarning: I'm testing the speedup. This might take up to thirty seconds.\n ";
-print "# Warning: I'm testing the speedup. This might take up to sixty seconds.\n";
print "1..6\n";
+# This next test finds an example that takes a long time to run, then
+# checks to make sure that the run is actually speeded up by memoization.
+# In some sense, this is the most essential correctness test in the package.
+#
+# We do this by running the fib() function with successfily larger
+# arguments until we find one that tales at leasrtt $LONG_RUN seconds
+# to execute. Then we memoize fib() and run the same call cagain. If
+# it doesn't produce the same test in less than one-tenth the time,
+# something is seriously wrong.
+#
+# $LONG_RUN is the number of seconds that the function call must last
+# in order for the call to be considered sufficiently long.
+
+
sub fib {
my $n = shift;
$COUNT++;
@@ -19,20 +36,39 @@ sub fib {
fib($n-1) + fib($n-2);
}
-$N = 0;
+sub max { $_[0] > $_[1] ?
+ $_[0] : $_[1]
+ }
+
+$N = 1;
$ELAPSED = 0;
-until ($ELAPSED > 10) {
- $N++;
+
+my $LONG_RUN = 10;
+
+while (1) {
my $start = time;
$COUNT=0;
$RESULT = fib($N);
$ELAPSED = time - $start;
- print "# fib($N) took $ELAPSED seconds.\n" if $N % 1 == 0;
+ last if $ELAPSED >= $LONG_RUN;
+ if ($ELAPSED > 1) {
+ print "# fib($N) took $ELAPSED seconds.\n" if $N % 1 == 0;
+ # we'd expect that fib(n+1) takes about 1.618 times as long as fib(n)
+ # so now that we have a longish run, let's estimate the value of $N
+ # that will get us a sufficiently long run.
+ $N += 1 + int(log($LONG_RUN/$ELAPSED)/log(1.618));
+ print "# OK, N=$N ought to do it.\n";
+ # It's important not to overshoot here because the running time
+ # is exponential in $N. If we increase $N too aggressively,
+ # the user will be forced to wait a very long time.
+ } else {
+ $N++;
+ }
}
print "# OK, fib($N) was slow enough; it took $ELAPSED seconds.\n";
-
+print "# Total calls: $COUNT.\n";
&memoize('fib');
@@ -48,12 +84,12 @@ print (($ELAPSED/$ELAPSED2 > 10) ? "ok 2\n" : "not ok 2\n");
print (($COUNT > $N) ? "ok 3\n" : "not ok 3\n");
# Do it again. Should be even faster this time.
+$COUNT = 0;
$start = time;
$RESULT2 = fib($N);
$ELAPSED2 = time - $start + .001; # prevent division by 0 errors
-
print (($RESULT == $RESULT2) ? "ok 4\n" : "not ok 4\n");
print (($ELAPSED/$ELAPSED2 > 10) ? "ok 5\n" : "not ok 5\n");
# This time it shouldn't have called the function at all.
-print ($COUNT ? "ok 6\n" : "not ok 6\n");
+print ($COUNT == 0 ? "ok 6\n" : "not ok 6\n");