On 6/14/05, Austin Ziegler <halostatue / gmail.com> wrote: > On 6/14/05, Phil Tomson <ptkwt / aracnet.com> wrote: > > Amidst all of the discussion about the alioth benchmarks and how > > they are (insert disparaging term here) there was a little > > discussion about the Ackermann benchmark and how Ruby finishes > > dead last even behind gawk(in fact doesn't finish for values of N > > larger than 6). > > [snipped benchmark] > > > Well, that's simple enough. Nothing to improve there and > > essentially looks like the Python version, except that the python > > version includes: > > > > import sys > > sys.setrecursionlimit(5000000) > > > > ....kind of handy that they can do that from within their program. > > This is a bit of a cheat, IMO, to do this within Python. I suspect > that it could be done within Ruby, but I think that Matz had > indicated that this is more appropriately an operating system > function. Indeed: > > austin@austin:~$ time ack.rb 7 > Ack(3,7): 1021 > > real 0m1.258s > user 0m1.230s > sys 0m0.010s > > austin@austin:~$ ulimit -s 16384 > austin@austin:~$ time ack.rb 8 > Ack(3,8): 2045 > > real 0m5.306s > user 0m5.250s > sys 0m0.030s > > austin@austin:~$ time ack.rb 9 > Ack(3,9): 4093 > > real 0m22.707s > user 0m22.520s > sys 0m0.150s > austin@austin:~$ ruby -v > ruby 1.8.2 (2005-03-10) [i686-linux] > > Thus, by changing ulimit in the user level, I can do the Ackermann > test. That is a linode, by the way, with 96 Mb of memory. Comparing > like to like, I get: > > 7 8 9 > Python 0.643 3.071 11.519 > Python-s DNF DNF DNF > Python-u DNF DNF DNF > Ruby 1.234 DNF DNF (1933 levels) > Ruby-u 1.210 5.319 23.275 > Perl 0.835 3.659 20.935 > > Python-s removes the setrecursion limit; Python-u does the same but > changes ulimit. IN REALITY, we see that Python -- without this > setting change -- can't even finish Ack(3,7). (The variance in the > test table above and my earlier results is that they were run at > different times.) > > Ruby, on the other hand, does finish it with this OS setting. I > suspect that the stack frames (bindings) in Ruby are larger, which > explains the speed difference to some degree. Could Ruby be faster? > We're pretty competitive with Perl there. Probably. I wouldn't know > the first thing about speeding it up -- or if we really need to. > > > So the conclusion is that Ruby isn't so great at recursion (not a > > new conclusion). If you're looking for a language that's good for > > recursion (because you like that style of programming or whatever) > > then looking at the results of this benchmark would be > > informative. You could tell right away that Ruby isn't a good > > choice for that style of programming. One might dismiss this by > > saying "well, I never use recursion anyway", but a lot of > > algorithms are much easier to implement recusively (algorithms > > which deal with walking trees for example). > > But it would be an incorrect assumption -- remember, I changed a > userspace OS-level value from 8192 (the default stack size in > kilobytes) to 16384, and was able to do ack(3,9). It blew up on > ack(3, 10) -- but I can't change the stack any larger. However, we > went from blowing up around 1500 levels to 4500 levels of recursion. > > This is *part* of the reason that I have significant issues with the > alioth shootout. They don't take any responsibility for these > numbers or understanding the nature of problems -- and seem to be > proud of it. They've accepted a Perl version that goes for fast-and- > ugly: > > # in our quest for speed, we must get ugly: > # it helps reduce stack frame size a little bit > # from Leif Stensson > sub Ack { > return $_[0] ? ($_[1] ? Ack($_[0]-1, Ack($_[0], $_[1]-1)) > : Ack($_[0]-1, 1)) > : $_[1]+1; > } > > All because it's "prettier but slower to do this": > > sub Ack { > my($M, $N) = @_; > return( $N + 1 ) if ($M == 0); > return( Ack($M - 1, 1) ) if ($N == 0); > Ack($M - 1, Ack($M, $N - 1)); > } > > IMO, this is completely inappropriate. If the Perlers are going to > do things to reduce their stack frames, and the Pythonistas are > going to muck around with recursion limits that help their code run > at all ... why can't Rubyists reduce or eliminate the recursion > entirely? > > -austin > -- > Austin Ziegler * halostatue / gmail.com > * Alternate: austin / halostatue.ca > > Ok I realize that this (definitely) probably won't make it any faster but could some clever hacker use callcc to implement a CPS version? It would still technically be recursive, but should bypass the stack (almost) entirely.