Zed and Luis drop the bomb on Ruby's poor performance

On 5/23/06, Robert K. [email protected] wrote:

optimization and instrumentation. Current JVMs’ instrumentation
interfaces give you a lot of options in analyzing runtime behavior of
your application.

And how well will the Java app run across (list taken from
Host/Target specific installation notes for GCC - GNU Project) :
* alpha*--
* alpha*-dec-osf*
* alphaev5-cray-unicosmk*
* arc--elf
* arm-
-elf arm--coff arm--aout
* xscale--
* avr
* Blackfin
* c4x
* DOS
* --freebsd*
* h8300-hms
* hppa*-hp-hpux*
* hppa*-hp-hpux10
* hppa*-hp-hpux11
* --linux-gnu
* i?86--linuxaout
* i?86--linux
* i?86--sco3.2v5
* i?86--solaris2.10
* i?86-
-udk
* ia64--linux
* ia64-
-hpux*
* -ibm-aix
* iq2000--elf
* m32c-
-elf
* m32r--elf
* m6811-elf
* m6812-elf
* m68k-hp-hpux
* mips-
-*
* mips-sgi-irix5
* mips-sgi-irix6
* powerpc*-- powerpc--sysv4
* powerpc-
-darwin*
* powerpc--elf powerpc--sysv4
* powerpc*--linux-gnu
* powerpc--netbsd
* powerpc--eabisim
* powerpc-
-eabi
* powerpcle--elf powerpcle--sysv4
* powerpcle--eabisim
* powerpcle-
-eabi
* s390--linux
* s390x--linux
* s390x-ibm-tpf*
* --solaris2*
* sparc-sun-solaris2*
* sparc-sun-solaris2.7
* sparc--linux
* sparc64--solaris2
* sparcv9--solaris2
* --sysv*
* vax-dec-ultrix
* --vxworks*
* x86_64-- amd64--
* xtensa--elf
* xtensa-
-linux*
* Microsoft Windows
* OS/2
Note that this list of install notes is not a list of supported hosts
or targets. Not all supported hosts and targets are listed here, only
the ones that require host-specific or target-specific information
are.

Ara did say speed and portability :wink:

Lisp has a tiny syntax.
Lisp has uncountable years of development.
Lisp had lots of people who wanted it to go fast, so it goes fast.

Ruby has lots of people complaining about it being slow but only a
handful of people doing something about it.

Lisp does not have uncountable years of development. unless you’re
speaking in terms of man-years, which would indeed be very difficult
to calculate, Lisp has 48 years of development (not counting
brainstorming or experimentation prior to its original specification
in 1958). I can count to 48 and I’m sure this ability is not unique to
me.

however, I think your point is actually a very good point. if the
things I’ve read have been true, compiled Lisp has performance
competitive with C and superior to Java. it started out slow and
became fast because people wanted it to do that. if people want Ruby
to do the same thing, the work is there for them to do.

I’m still skeptical about the whole question, though. if other
things I’ve read have also been true, you can get much better
performance improvements from putting your database in RAM than you
can from any language change. in fact, don’t quote me on this, but my
recollection is that the difference was measured in orders of
magnitude.

On Monday 22 May 2006 05:45 pm, Sam R. wrote:

Yes, performance was dominated by string comparisons, I wrote the
benchmark to see if changing to symbols would help.

How long is your program (lines, for example)? Is it small enough to
either
post to the list or make available to those who might be interested.

It would be interesting to see what others might suggest to improve the
performance of your code. (For example, maybe there are ways to use
fewer
string comparisons?)

If your program is (to pick an arbitrary number) 60 lines or less, post
it.
(And you’re willing to :wink: If longer, post with the length of the
program–maybe some people will be interested enough to request a copy
to
look at (with an eye to optimizing it).

Randy K.

Eric H. wrote:

Lisp has a tiny syntax.
Lisp has uncountable years of development.
Lisp had lots of people who wanted it to go fast, so it goes fast.

The Lisp compiler can optimize in ways that the ruby interpreter cannot.
(Optional type declarations, for example. Also, list manipulations are
not method calls.)

On 5/22/06, Alder G. [email protected] wrote:

up, Ruby doesn’t win (doesn’t matter if the application requires it or
language and offered an improved development experience.
Exactly.
pretty smart for that. And for those 99%, being smart means they would
have been using Java. If they were even smarter, they’d be using Ruby
:stuck_out_tongue:

A lot of people write a lot of software that don’t run on desktop
machines. A lot of people write a lot of realtime or embedded
software. In those application domains, C++ works pretty well
(maybe the best?).

(although, I’m not sure why you’d use C++ for anything not embedded or
non-realtime. That’s my experience, anyways.)

On May 23, 2006, at 1:52 PM, Joel VanderWerf wrote:


vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

How about we rewrite the ruby runtime as a combination of macros and
functions in Lisp, use ParseTree to get the S-Exp representation of a
ruby program and then feed that into our Lisp compiler? Instant
speedy ruby! :wink:

How about we rewrite the ruby runtime as a combination of macros and
functions in Lisp, use ParseTree to get the S-Exp representation of a
ruby program and then feed that into our Lisp compiler? Instant
speedy ruby! :wink:

I don’t know what you’re saying but it sounds like the work of the
devil.

Go for it.

2006/5/24, Logan C. [email protected]:

How about we rewrite the ruby runtime as a combination of macros and
functions in Lisp, use ParseTree to get the S-Exp representation of a
ruby program and then feed that into our Lisp compiler? Instant
speedy ruby! :wink:

With an install of ParseTree:

$ cat example.rb
#!/usr/local/bin/ruby
def sum(a, b)
return a+b
end

a = 3
b = 4
c = pythag(a, b)
puts c

$ cat lispify.rb
#!/usr/local/bin/ruby

def lispify(code)
code.gsub!(/[:,]/, ‘’)
code.gsub!(/[/, ‘(’)
code.gsub!(/]/, ‘)’)
end

code = $stdin.read

puts lispify(code)

$ cat example.rb | parse_tree_show -f | ./lispify.rb
((defn
sum
(scope
(block
(args a b)
(return (call (lvar a) + (array (lvar b)))))))
(lasgn a (lit 3))
(lasgn b (lit 4))
(lasgn c (fcall pythag (array (lvar a) (lvar b))))
(fcall puts (array (lvar c))))

So, it looks like Lisp to me! Now, some macros?

Douglas

Douglas L. wrote:

$ cat lispify.rb
#!/usr/local/bin/ruby

def lispify(code)
code.gsub!(/[:,]/, ‘’)
code.gsub!(/[/, ‘(’)
code.gsub!(/]/, ‘)’)
end

Topher’s article[0] at RC&S might be of interest, too.

[0] artima - If It's Not Nailed Down, Steal It


James B.

“People want simple stories.”

On May 23, 2006, at 10:24 PM, Douglas L. wrote:

$ cat example.rb
$ cat lispify.rb
puts lispify(code)
(lasgn c (fcall pythag (array (lvar a) (lvar b))))
(fcall puts (array (lvar c))))

So, it looks like Lisp to me! Now, some macros?

Douglas

What scares (excites?) me is that this looks almost close enough to
work already.

[email protected] wrote:

i think making a fast, protable, vm is
a lions job. however, i’d be quite happy to be wrong, it just seems
un-likely. consider how long has parrot been ‘almost’, for example…
Well … I guess my point of view is that Forth is the ultimate “virtual
machine”, and that the good folks who created GForth exploited a feature
in GCC that’s outside the ANSI C standard to create a “fast, portable,
virtual machine.” In passing, I found it interesting that at least one
of the Ruby VMs posted on the link a couple of messages back uses the
same “virtual machine generation” concept that GForth uses.

So … does Parrot use this? I’m pretty sure YARV doesn’t. Meanwhile,
have a look at


M. Edward (Ed) Borasky

On May 23, 2006, at 11:15 PM, James B. wrote:

Topher’s article[0] at RC&S might be of interest, too.

[0] artima - If It's Not Nailed Down, Steal It

I was actually reading this earlier today, which brought it to mind.

On 5/23/06, Douglas L. [email protected] wrote:

((defn sum (scope (block (args a b) (return (call (lvar a) + (array
(lvar b))))))) (lasgn a (lit 3)) (lasgn b (lit 4)) (lasgn c (fcall sum
(array (lvar a) (lvar b)))) (fcall puts (array (lvar c))))

Odd, the output I get for lispifying:

$ cat example.rb
def sum(a, b)
a + b
end

a = 3
b = 4
c = sum(a, b)
puts c

is:

((class Example Object (defn example (scope (block (args) (defn sum
(scope (block (args a b) (call (lvar a) + (array (lvar b)))))) (lasgn
a
(lit 3)) (lasgn b (lit 4)) (lasgn c (fcall sum (array (lvar a) (lvar
b)))) (fcall puts (array (lvar c))))))))

The interior (starting from “(defn sum…”) is the same as you’ve got
(minus the return statement), but I’ve got a lot of extra stuff
wrapped around it. I’ve double checked the my sexp and parsetree gems
are the latest (sexp-0.1, ParseTree-1.4.1).

Jacob F.

2006/5/24, Jacob F. [email protected]:

I think you’ve deleted an extra line, try putting this in after your
result=ParseTree:

result = result[0][3][2][1][2…-1]

Or it might just be how you’re running the script, I’m doing:

$ cat example.rb | ./parse.rb -f

hth,
Douglas

2006/5/24, James B. [email protected]:

Topher’s article[0] at RC&S might be of interest, too.

gemp install sexp

Nice link. Doing the hack job solution, taking parse_tree_show and
appending sexp to it, gives:

$ diff parse_tree_show parse_tree_lisp
44,48c44,48
< unless defined? $q then
< pp result
< else
< p result
< end

class Object; def to_sexp; inspect(); end; end
class Symbol; def to_sexp; id2name(); end; end
class Array; def to_sexp; “(#{map{|x| x.to_sexp }.join(’ ')})”; end; end

puts result.to_sexp

Resulting in the probably-more-reliable-than-gsub result of:

((defn sum (scope (block (args a b) (return (call (lvar a) + (array
(lvar b))))))) (lasgn a (lit 3)) (lasgn b (lit 4)) (lasgn c (fcall sum
(array (lvar a) (lvar b)))) (fcall puts (array (lvar c))))

Douglas

On May 23, 2006, at 7:24 PM, Douglas L. wrote:

(fcall puts (array (lvar c))))
It’ll look better if you run it through Rewriter first. Rewriter
removes a few of the AST optimizations ruby makes in exchange for
more-readable sexps.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On 5/24/06, Douglas L. [email protected] wrote:

2006/5/24, Jacob F. [email protected]:

The interior (starting from “(defn sum…”) is the same as you’ve got
(minus the return statement), but I’ve got a lot of extra stuff
wrapped around it. I’ve double checked the my sexp and parsetree gems
are the latest (sexp-0.1, ParseTree-1.4.1).

I think you’ve deleted an extra line, try putting this in after your
result=ParseTree:

result = result[0][3][2][1][2…-1]

Odd. Adding that line does indeed “fix” it (make the output match),
but my original copy of parse_tree_show (copied right out of the gem
directory) didn’t have that line to start with. I don’t care much, it
just struck me as interesting.

Jacob F.

“Douglas L.” [email protected] writes:

How about we rewrite the ruby runtime as a combination of macros and
functions in Lisp, use ParseTree to get the S-Exp representation of a
ruby program and then feed that into our Lisp compiler? Instant
speedy ruby! :wink:

So, it looks like Lisp to me! Now, some macros?

Now try to port the Ruby object system to CL so it will have
reasonable runtime performance.

Good luck.

Christian N. wrote:

(block
reasonable runtime performance.

Good luck.

Yup. I’m afraid all this lovely syntactical work is not going to get
past the basic facts that (a) method calls are pervasive in ruby and (b)
we depend on (a) for all of our favorite tricks. It’s hard to optimize a
language in which so much meaning is deferred until the moment of
execution.

What’s special about ruby (and languages that share the smalltalk
heritage) is that this deferment of meaning (aka late binding) is
enforced so pervasively that it becomes possible to reuse libraries in
ways that were not originally intended (duck typing). Duck typing in CL
is probably much harder, because library writers may make more type
decisions in the interest of “efficiency” (but that’s just a wild guess
from someone who hasn’t used Lisp seriously in 10 years, so I’ll pipe
down about that now). A good example in ruby is the #to_s method invoked
by the #{ } construct. Another example is #each.

On Thu, May 25, 2006 at 06:29:39AM +0900, Logan C. wrote:

inheritance stuff for free (and arrays and strings, numbers etc.).

From what I remember CLOS has distinct class and method hierarchies,
and multi-dispatch of methods on all parameters. You can specialize
functions depending on almost anything, not just class of the first
parameter, which is the implicit receiver in message based OO systems.

So, for singleton methods, it should suffice to specialize a generic
function on the first paramter beeing some specific instance.

CLOS classes do have a fixed and predeclared number of attributes
called slots, and Ruby’s dynamic attributes would have to be assigned
to a slot holding a list/array/hash of attributes.

Alas, my Lisp times are gone, short as they were in academics. But
it’s itching.

Jürgen