Ruby "Speedup" hints?

M

Marc Heiler

Anyone of you has a few hints on how to speed up ruby code?
(Note - not writing it, but running it ;-) )

I only have a few hints, like 5... would love to extend it.

So without further ado:

- Using << instead of += for Strings as += creates a new object
whereas << will simply work on the current object.

- Use Inline C for critical methods (had to include that ;> )

- Reusing variable names might be better than using a lot of
different variables

- for is faster than .each on Arrays

- .last is faster than [0]

- .zero? is faster than == 0


If you know a few more hints, please add!
 
R

Robert Klemme

Anyone of you has a few hints on how to speed up ruby code?
(Note - not writing it, but running it ;-) )

I only have a few hints, like 5... would love to extend it.

So without further ado:

- Using << instead of += for Strings as += creates a new object
whereas << will simply work on the current object.

I'd replace that with the general rule to avoid object creation because
that will cover more cases (Array#concat vs. Array#+, String#gsub! vs.
String#gsub etc.).
- Use Inline C for critical methods (had to include that ;> )

You could argue that this does not speed up Ruby code but replaces it
with something else. So it's questionable whether this item should be
on the list.
- Reusing variable names might be better than using a lot of
different variables

Are you talking about a fact or a guess here? You write "might" - which
indicates to me that this is not a proven fact.
- for is faster than .each on Arrays

- .last is faster than [0]

I guess you meant Array#last is faster than Array#[-1] or Array#first is
faster than Array#[0].
- .zero? is faster than == 0

Interesting, I did not know that. But the difference is really small:

robert@fussel ~
$ time ruby -e '1_000_000.times { 0.zero? }'

real 0m0.748s
user 0m0.468s
sys 0m0.108s

robert@fussel ~
$ time ruby -e '1_000_000.times { 1.zero? }'

real 0m0.748s
user 0m0.483s
sys 0m0.124s

robert@fussel ~
$ time ruby -e '1_000_000.times { 0 == 0 }'

real 0m0.869s
user 0m0.561s
sys 0m0.108s

robert@fussel ~
$ time ruby -e '1_000_000.times { 1 == 0 }'

real 0m0.857s
user 0m0.562s
sys 0m0.124s

robert@fussel ~
$
If you know a few more hints, please add!

- freeze Strings that you are going to use as Hash keys.

Often bad design makes programs slow. While these are valid points
often the bigger effect can be achieved by proper designing an
application (i.e. use a Hash for frequent lookups instead of traversing
an Aarry).

Kind regards

robert
 
I

Ilan Berci

Marc said:
Anyone of you has a few hints on how to speed up ruby code?
(Note - not writing it, but running it ;-) )

I only have a few hints, like 5... would love to extend it.

There is only 1 hint:

PROFILE IT!!!

everything else is BS..

hth

ilan
 
S

Sean Allen

Are you talking about a fact or a guess here? You write "might" -
which indicates to me that this is not a proven fact.

and it certainly will eventually lead to programmer confusion esp when
dynamically scoped
blocks come into play.
 
M

M. Edward (Ed) Borasky

Marc said:
Anyone of you has a few hints on how to speed up ruby code?
(Note - not writing it, but running it ;-) )

I only have a few hints, like 5... would love to extend it.

So without further ado:

- Using << instead of += for Strings as += creates a new object
whereas << will simply work on the current object.

- Use Inline C for critical methods (had to include that ;> )

- Reusing variable names might be better than using a lot of
different variables

- for is faster than .each on Arrays

- .last is faster than [0]

- .zero? is faster than == 0


If you know a few more hints, please add!

http://www.informit.com/store/product.aspx?isbn=0321540034

A whole book full of tips!
 
P

Paul Brannan

+1

All discussions of performance tuning are meaningless without
profiling numbers.

Profiling only tells you where performance bottlenecks are. It does
nothing for letting you know how to fix those bottlenecks. That's where
benchmarks come into play.

Paul
 
J

Jano Svitok

Anyone of you has a few hints on how to speed up ruby code?
(Note - not writing it, but running it ;-) )
If you know a few more hints, please add!

ParseDate#parsedate is expensive - it uses rationals, gcd and other
heavy stuff to convert from [D, M, Y, H, M, S] to timestamp.
Once we did a log merger and we ordered the entries by time. We saved
a lot of processing time by storing the timestamps in the logs along
with the formatted date.
(They were removed afterwards during formatting.)

ERB#new is expensive. Cache compiled templates if they are to be reused.

Use /o switch for Regexp literals that contain constant
#{substitutions} (i.e. that do not depend on function parameters)
 
G

Gerardo Santana Gómez Garrido

Anyone of you has a few hints on how to speed up ruby code?
(Note - not writing it, but running it ;-) )

I only have a few hints, like 5... would love to extend it.

When generating text output, using StringIO is faster than using puts
 
P

Paul Brannan

When generating text output, using StringIO is faster than using puts

This doesn't make sense. One can easily call #puts on a StringIO
object.

Do you have a concrete example/benchmark that demonstrates the
difference?

Paul
 
J

John Carter

Anyone of you has a few hints on how to speed up ruby code?
(Note - not writing it, but running it ;-) )

Sounds like time to repost (yet again, can't we add this to a FAQ somewhere?)

http://rubygarden.org/Ruby/page/show/RubyOptimization

Please add your hints (preferably with a benchmark to show the
magnitude of the improvement) to that page.


Thanks!


John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : (e-mail address removed)
New Zealand
 
G

Gerardo Santana Gómez Garrido

This doesn't make sense. One can easily call #puts on a StringIO
object.

Do you have a concrete example/benchmark that demonstrates the
difference?

Paul

$ time ruby a.rb 10_000_000 > /tmp/a && sleep 3 && time ruby b.rb
10_000_000 > /tmp/b; printf "\a"

real 1m45.305s
user 1m27.581s
sys 0m17.715s

real 0m59.049s
user 0m41.984s
sys 0m16.997s
$ cat a.rb
times = ARGV[0].to_i
times.times { puts "hola mundo" }
$ cat b.rb
require 'stringio'

times = ARGV[0].to_i
output = StringIO.new
times.times { output.write("hola mundo\n") }
output.rewind
print output.read


The difference increases in real world reports.
 
T

ThoML

The difference increases in real world reports.

This and some other tips seem specific to either ruby 1.8 or 1.9.
While StringIO seems much faster with 1.9, in my world, the difference
is rather marginal with 1.8. Also, the following is slightly faster
with 1.8:

times = ARGV[0].to_i
times.times { STDOUT.puts "hola mundo" }

YMMV etc.
 
R

Robert Klemme

2008/3/17 said:
Is that in any way a speedup hint? or is it just a safety hint? What
causes the speedup?

As Jano mentioned it's the skipped #dup for frozen Strings that makes
the speedup.

irb(main):002:0> s="foo"
=> "foo"
irb(main):003:0> h={s=>1}
=> {"foo"=>1}
irb(main):004:0> [s.object_id, h.keys.first.object_id]
=> [1073545320, 1073545340]
irb(main):005:0> s.freeze
=> "foo"
irb(main):006:0> h={s=>1}
=> {"foo"=>1}
irb(main):007:0> [s.object_id, h.keys.first.object_id]
=> [1073545320, 1073545320]
irb(main):008:0>

Kind regards

robert
 
M

Marc Heiler

Hi there,

Thanks for the feedback so far. :)

"PROFILE IT!!!

everything else is BS."

As for profiling, you can always do profiling of course,
but why copy the efforts others did on it already?

Example - General Statements done such as the one by Robert Klemme
seem to hold true no matter how much profiling one would do anyway:
"I'd replace that with the general rule to avoid object creation
because
that will cover more cases (Array#concat vs. Array#+, String#gsub! vs.
String#gsub etc.)."


Personally I like such simple truths. :)
 
M

Marc Heiler

Sorry for replying so soon but I had to ;-)



"Sounds like time to repost (yet again, can't we add this to a FAQ
somewhere?)

http://rubygarden.org/Ruby/page/show/RubyOptimization"


I think collecting it in one place would be best for both
newcomers and old rubyistas.

Personally I think all useful things (to a general user
base of ruby) should be collected at the official homepage - or,
in case it would not qualify, there could be links.

External servers should be somewhat reliable too though.
The following result assents me here slightly when I try to
visit above URL ... ;-)


"Proxy Error

The proxy server received an invalid response from an upstream server.
The proxy server could not handle the request GET
/Ruby/page/show/RubyOptimization.

Reason: Error reading from remote server

Apache/2.2.3 (Unix) DAV/2 PHP/5.1.6 SVN/1.1.4 Server at rubygarden.org
Port 80"


Regards
 
A

Avdi Grimm

Personally I like such simple truths. :)

The problem with simple truths is that often aren't simple, and almost
never stay true. There was/is a large percentage of hackers in the
C/C++ community who learned certain "simple truths" about how to make
programs go faster - and continued to use them religiously for
decades, even after the compilers had made those techniques irrelavent
or even detrimental. I believe the same has happened in Java, as
JITing and other optimizations have made a lot of assumptions about
performance moot.

The other problem with "simple truths" is that in performance, it
really isn't true that every little bit helps. I can't tell you how
many times I've seen a design which was complicated and obfuscated by
some coder's (potentially superstitious) beliefs about certain
techniques being faster than others (e.g. "always avoid dynamic
dispatch"). Almost invariably it turns out that the real performance
gains to be made are algorithmic and/or have to do with IO, and are
orders of magnitude larger than tiny gains made by following
performance "truths" - to the point that the latter gains are lost in
the statistical noise. It's often the case that those little
rule-based optimizations only served to make the code more difficult
to refactor, and thus harder to apply the real optimizations to.

At a time in Ruby's history when it's implementation is in flux, and
there are multiple alternate implementations coming on line, I think
it is very dangerous to start compiling "rules of thumb" or "simple
truths" about Ruby performance hacks. And when such rules are stated,
they need to be quantified with benchmarks and qualified with very
specific information about the platforms those benchmarks were
gathered on.

...and then you should *still* write your code to be clear and
well-factored, and put off any optimizations until after you profile.
Chances are you'll discover that your real slowdown is in IO, or in
some database interaction, not in instantiating objects.

I saw a pertinent quote the other day: "It is easier to optimize
correct code than to correct optimized code." --Bill Harlan
 
R

Rajat Garg

[Note: parts of this message were removed to make it a legal post.]

Guys,

Given, we are talking about optimization, an big part of it is to optimize
page-download times. I am told that this can be somewhat accomplished using
the following -

1. Strip spaces, tabs, CR/LF from the HTML
2. Enable HTTP Compression

Is there a way in RoR w/ Mongrel to accomplish the two?

Rajat



The problem with simple truths is that often aren't simple, and almost
never stay true. There was/is a large percentage of hackers in the
C/C++ community who learned certain "simple truths" about how to make
programs go faster - and continued to use them religiously for
decades, even after the compilers had made those techniques irrelavent
or even detrimental. I believe the same has happened in Java, as
JITing and other optimizations have made a lot of assumptions about
performance moot.

The other problem with "simple truths" is that in performance, it
really isn't true that every little bit helps. I can't tell you how
many times I've seen a design which was complicated and obfuscated by
some coder's (potentially superstitious) beliefs about certain
techniques being faster than others (e.g. "always avoid dynamic
dispatch"). Almost invariably it turns out that the real performance
gains to be made are algorithmic and/or have to do with IO, and are
orders of magnitude larger than tiny gains made by following
performance "truths" - to the point that the latter gains are lost in
the statistical noise. It's often the case that those little
rule-based optimizations only served to make the code more difficult
to refactor, and thus harder to apply the real optimizations to.

At a time in Ruby's history when it's implementation is in flux, and
there are multiple alternate implementations coming on line, I think
it is very dangerous to start compiling "rules of thumb" or "simple
truths" about Ruby performance hacks. And when such rules are stated,
they need to be quantified with benchmarks and qualified with very
specific information about the platforms those benchmarks were
gathered on.

...and then you should *still* write your code to be clear and
well-factored, and put off any optimizations until after you profile.
Chances are you'll discover that your real slowdown is in IO, or in
some database interaction, not in instantiating objects.

I saw a pertinent quote the other day: "It is easier to optimize
correct code than to correct optimized code." --Bill Harlan


--
Rajat Garg


Ph: 206-499-9495
Add: 1314 Spring Street, #412
Seattle, WA 98104
Web: http://www.pilotoutlook.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,285
Messages
2,571,416
Members
48,108
Latest member
Virus9283

Latest Threads

Top