Skip to content

Instantly share code, notes, and snippets.

@funny-falcon
Created March 12, 2012 05:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save funny-falcon/2020108 to your computer and use it in GitHub Desktop.
Save funny-falcon/2020108 to your computer and use it in GitHub Desktop.
uglier is sometimes faster
#!/usr/bin/env ruby
require 'yaml'
y=[]
(1..10000).each{|x|
#next unless x/2==(1.0*x)/2
z=x
divisors=[1]
_continue=true
while _continue
_continue=false
((divisors.last+1)..z).each{|w|
r=z/w
if (1.0*z)/w==r && w<x
divisors<<w
_continue=true
break
end
}
end
if divisors.inject(&:+)>x and (3..(divisors.count)).find{|w| divisors.combination(w).find{|w2| w2.inject(&:+)==x } }
y<<x
end
}
puts "amount: #{y.count}"
#!/usr/bin/env ruby
require 'yaml'
class Test
attr_reader :y
def initialize(up)
@up = up
@y = []
end
def perform
for x in 1..@up
divisors, w = [1], 1
while (w = get_next(w+1, x))
divisors << w
end
y << x if sum(divisors) > x && check(divisors, x)
end
self
end
def get_next(from, z)
w = from
while w < z
return w if z/w == (1.0*z)/w
w += 1
end
nil
end
def sum(ar)
s = ar[0]
i, up = 1, ar.size
while i < up
s += ar[i]
i += 1
end
s
end
def check(divisors, x)
(3..(divisors.count)).find{|w|
divisors.combination(w).find{|w2|
sum(w2) == x
}
}
end
end
puts "amount: #{Test.new(10000).perform.y.count}"
@mpapis
Copy link

mpapis commented Mar 12, 2012

that was hell much faster ...

$ rvm jruby-head-d19,1.9.3-perf do time ruby -v ugly_test.rb
jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-03-11 d62a1a4) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_03) [linux-amd64-java]
amount: 2481
77.90user 0.91system 1:19.83elapsed 98%CPU (0avgtext+0avgdata 946016maxresident)k
27736inputs+136outputs (30major+59248minor)pagefaults 0swaps
ruby 1.9.3p125 (2012-02-16) [x86_64-linux]
amount: 2481
156.95user 0.06system 2:38.03elapsed 99%CPU (0avgtext+0avgdata 27120maxresident)k
6920inputs+0outputs (21major+10062minor)pagefaults 0swaps

so loops are faster then any kinds of blocks, also notable change with inject(&:+) replaced with the sum function ... couldn't mri/jruby do the same optimizations ?

@headius as promised switching default to jruby

@headius
Copy link

headius commented Mar 12, 2012

Non-block loops are faster in JRuby (and maybe in others) because blocks have a lot of hidden overhead. Specifically, the closure state (local vars, etc), argument processing, and in JRuby some deoptimizations happen because blocks can potentially be used as bindings (grr). Future JRuby (probably post 1.7) will do a better job optimizing and inlining blocks, but it's much harder than just inlining (or letting the JVM inline) method bodies and simple loops.

@mpapis
Copy link

mpapis commented Mar 12, 2012

and here is rbx:

$ rvm rbx-head-d19 do time ruby -v ugly_test.rb
rubinius 2.0.0dev (1.9.3 9a4b4c1c yyyy-mm-dd JI) [x86_64-unknown-linux-gnu]
amount: 2481
1789.27user 1.19system 30:07.73elapsed 99%CPU (0avgtext+0avgdata 185024maxresident)k
36288inputs+0outputs (107major+13196minor)pagefaults 0swaps

As I remember last time it was around 43 minutes so also slight speedup.

@mpapis
Copy link

mpapis commented Apr 8, 2012

update for latest rbx:

$ time rvm rbx do ruby -v ugly_test.rb
rubinius 2.0.0dev (1.9.3 b4aa36e4 yyyy-mm-dd JI) [x86_64-unknown-linux-gnu]
amount: 2481

real    3m37.907s
user    3m33.326s
sys 0m0.516s

big speedup, still slower but already a lot better then before, here is 1.9.3-p125 for comparison

$ time rvm 1.9.3 do ruby -v ugly_test.rb
ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-linux]
amount: 2481

real    2m35.360s
user    2m32.542s
sys 0m0.378s

and jruby-head on java7 is over 2 times faster:

$ time rvm jruby-head do ruby -v ugly_test.rb
jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-04-02 f031f63) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_03) [linux-amd64-java]
amount: 2481

real    1m29.288s
user    1m25.240s
sys 0m1.670s

@funny-falcon
Copy link
Author

It is big step forward for rbx!!!
I'm more interested in IO behavior though. Maybe it improved too.

@headius
Copy link

headius commented Apr 10, 2012

My numbers seem to put JRuby farther ahead of Ruby 1.9.3 than your numbers:

Ruby 1.9.3:
111.640000 0.080000 111.720000 (111.722357)

JRuby master on Java 7u4:
41.103000 0.000000 41.103000 ( 41.104000)

JRuby's run time is 36% of Ruby 1.9.3's, compared to around 58% in your case. Nearly 3x faster rather than less than 2x. Perhaps JRuby has improved since this run? Perhaps my dual cores are helping (the JVM does use multiple cores for GC)?

@headius
Copy link

headius commented Apr 10, 2012

A small change improves JRuby further... replace the #[] calls in sum with #at calls:

real 0m33.895s
user 0m37.502s
sys 0m0.421s

In JRuby, #[] is flagged as a method that requires a heap-based scope because some versions of it set $~ (backref). Using .at avoids that.

We plan to fix that deoptimization, but it does make a difference right now.

@mpapis
Copy link

mpapis commented Apr 10, 2012

that could be also java version (mine is a bit older):

$ java -version
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) 64-Bit Server VM (build 22.1-b02, mixed mode)

@funny-falcon
Copy link
Author

In JRuby, #[] is flagged as a method that requires a heap-based scope because some versions of it set $~ (backref). Using .at avoids that.

Wow :)

@headius
Copy link

headius commented Apr 10, 2012

@mpapis that certainly could be true. There's also been some optimization work on JRuby master that may not be in your copy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment