Skip to content

Instantly share code, notes, and snippets.

@headius
Created September 1, 2012 02:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save headius/3563069 to your computer and use it in GitHub Desktop.
Save headius/3563069 to your computer and use it in GitHub Desktop.
ONE = 1
TWO = 2
def plus(a, b)
a + b
end
def minus(a, b)
a - b
end
def lt(a, b)
a < b
end
def fib_ruby(n)
if n < 2
n
else
fib_ruby(n - 2) + fib_ruby(n - 1)
end
end
def fib_ruby1(n)
a = 1
b = 2
if n < b
n
else
fib_ruby(n - b) + fib_ruby(n - a)
end
end
def fib_ruby2(n)
if n < TWO
n
else
plus(fib_ruby2(n - TWO), fib_ruby2(n - ONE))
end
end
def fib_ruby3(n)
if lt(n, 2)
n
else
plus(fib_ruby3(minus(n, 2)), fib_ruby3(minus(n, 1)))
end
end
def fib_ruby4(n)
if lt(n, TWO)
n
else
plus(fib_ruby4(minus(n, TWO)), fib_ruby4(minus(n, ONE)))
end
end
puts "normal fib"
t = Time.now
fib_ruby(37)
puts Time.now - t
t = Time.now
fib_ruby(37)
puts Time.now - t
t = Time.now
fib_ruby(37)
puts Time.now - t
t = Time.now
fib_ruby(37)
puts Time.now - t
t = Time.now
fib_ruby(37)
puts Time.now - t
puts "fib with variables"
t = Time.now
fib_ruby1(37)
puts Time.now - t
t = Time.now
fib_ruby1(37)
puts Time.now - t
t = Time.now
fib_ruby1(37)
puts Time.now - t
t = Time.now
fib_ruby1(37)
puts Time.now - t
t = Time.now
fib_ruby1(37)
puts Time.now - t
puts "fib with constants"
t = Time.now
fib_ruby2(37)
puts Time.now - t
t = Time.now
fib_ruby2(37)
puts Time.now - t
t = Time.now
fib_ruby2(37)
puts Time.now - t
t = Time.now
fib_ruby2(37)
puts Time.now - t
t = Time.now
fib_ruby2(37)
puts Time.now - t
puts "fib with additional calls"
t = Time.now
fib_ruby3(37)
puts Time.now - t
t = Time.now
fib_ruby3(37)
puts Time.now - t
t = Time.now
fib_ruby3(37)
puts Time.now - t
t = Time.now
fib_ruby3(37)
puts Time.now - t
t = Time.now
fib_ruby3(37)
puts Time.now - t
puts "fib with constants and additional calls"
t = Time.now
fib_ruby4(37)
puts Time.now - t
t = Time.now
fib_ruby4(37)
puts Time.now - t
t = Time.now
fib_ruby4(37)
puts Time.now - t
t = Time.now
fib_ruby4(37)
puts Time.now - t
t = Time.now
fib_ruby4(37)
puts Time.now - t
# JRuby + IR + invokedynamic, Java 7
system ~/projects/jruby $ jruby -Xcompile.invokedynamic=true -X+CIR bench_fib_complex.rb
normal fib
1.352
1.182
1.178
1.189
1.196
fib with variables
1.208
1.185
1.18
1.193
1.195
fib with constants
1.268
1.208
1.218
1.2
1.206
fib with additional calls
1.445
1.369
1.385
1.382
1.388
fib with constants and additional calls
1.448
1.38
1.38
1.396
1.372
# JRUBY normal compiler, no invokedynamic, Java 7
system ~/projects/jruby $ jruby bench_fib_complex.rb
normal fib
1.677
1.437
1.54
1.442
1.449
fib with variables
1.429
1.419
1.413
1.428
1.455
fib with constants
4.345
3.48
3.44
3.478
3.46
fib with additional calls
4.115
4.019
4.013
3.961
3.947
fib with constants and additional calls
5.08
5.037
5.069
5.03
5.038
# JRuby normal compiler, with invokedynamic, Java 7
system ~/projects/jruby $ jruby -Xcompile.invokedynamic=true bench_fib_complex.rb
normal fib
1.022
0.895
0.882
0.891
0.878
fib with variables
0.898
0.903
0.894
0.891
0.878
fib with constants
2.294
2.218
2.2
2.219
2.229
fib with additional calls
1.263
1.192
1.203
1.191
1.194
fib with constants and additional calls
2.498
2.49
2.463
2.464
2.467
# JRuby + IR + indy on Java 8 current preview
system ~/projects/jruby $ jruby -Xcompile.invokedynamic=true -X+CIR bench_fib_complex.rb
normal fib
2.123
1.883
1.906
1.927
1.936
fib with variables
1.964
1.949
2.056
1.972
1.95
fib with constants
2.537
2.341
2.314
2.321
2.314
fib with additional calls
3.023
2.853
2.817
2.784
2.779
fib with constants and additional calls
3.814
3.504
3.453
3.464
3.477
# JRuby normal compiler + invokedynamic Java 8
system ~/projects/jruby $ jruby -Xcompile.invokedynamic=true bench_fib_complex.rb
normal fib
1.273
1.145
1.147
1.142
1.146
fib with variables
1.145
1.158
1.146
1.151
1.132
fib with constants
4.179
3.973
4.021
3.995
3.993
fib with additional calls
5.947
5.105
5.143
5.131
5.112
fib with constants and additional calls
3.3
3.275
3.235
3.23
3.21
# Mac Ruby 0.11
system ~/projects/jruby $ macruby bench_fib_complex.rb
normal fib
1.540885
1.52045
1.514113
1.523034
1.515216
fib with variables
1.519008
1.510532
1.522152
1.523368
1.52119
fib with constants
4.034211
4.015224
4.041765
4.035574
4.022384
fib with additional calls
11.902849
11.898826
11.903194
11.916912
11.928757
fib with constants and additional calls
12.526754
12.481892
12.630251
12.696828
12.565837
# Ruby 1.9.3
system ~/projects/jruby $ ruby-1.9.3 bench_fib_complex.rb
normal fib
8.425049
8.435634
8.470232
8.530792
8.431036
fib with variables
8.489791
8.357061
8.407082
8.319713
8.304296
fib with constants
12.058306
12.082609
12.078435
12.2678
12.033094
fib with additional calls
25.732491
25.687056
25.916108
26.020998
26.290875
fib with constants and additional calls
26.128745
26.178898
25.856474
26.035318
25.864822
# Rubinius master
system ~/projects/jruby $ ../rubinius/bin/rbx bench_fib_complex.rb
normal fib
5.78509
5.733961
5.769155
5.753868
5.718023
fib with variables
5.718492
5.750543
5.746102
5.761694
5.780769
fib with constants
9.956583
9.985609
9.913486
9.954977
9.98208
fib with additional calls
15.448432
15.729208
16.458048
15.623091
15.592828
fib with constants and additional calls
16.651151
16.625031
16.628007
16.62336
16.639159
# MagLev 1.0.0
system ~/projects/jruby $ rvm maglev do ruby bench_fib_complex.rb
normal fib
1.79315
1.782173
1.78689
1.797193
1.818359
fib with variables
1.829706
1.821148
1.828031
1.82781
1.813357
fib with constants
6.875184
6.840194
6.839581
6.848165
6.837607
fib with additional calls
3.338842
3.357359
3.34526
3.38869
3.365903
fib with constants and additional calls
8.911834000000001
8.871909
8.893435999999999
8.797692
8.829554999999999
@sleeptillseven
Copy link

JRuby and MacRuby being awesome.

@thedarkone
Copy link

What is the main difference in generated bytecode between the IR and normal compiler? Why is IR slower in the simpler case, while being faster for the more complex ones?

@headius
Copy link
Author

headius commented Sep 3, 2012

@thedarkone For the simple cases, the normal compiler wins because it has fast-path logic for numeric operations with literal fixnums, avoiding type and overflow checks in most cases that IR still does. IR is using opaque object references, so it needs to use the normal logic that typechecks and overflow checks.

For the more complex cases, IR compiler wins because it has been designed to pass in everything needed for constant lookup, where the normal compiler pushes that data onto a per-thread stack. That stack juggling ends up opaque to the JVM, so it constant lookup can't be completely optimized away like it can for the IR compiler.

Both compilers can be adapted to do the optimizations the other does, but it will be easier going forward to focus on the IR compile since it is already very functional and far, far simpler than the old compiler.

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