https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112014-09-08T08:58:38ZRuby Issue Tracking SystemRuby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=487182014-09-08T08:58:38Znormalperson (Eric Wong)normalperson@yhbt.net
<ul></ul><p><a href="mailto:ko1@atdot.net" class="email">ko1@atdot.net</a> wrote:</p>
<blockquote>
<p>I haven't dig details, but maybe it is because of GC perforamance.<br>
Because Proc (and Env) objects are wb-unprotected, such objects are<br>
marked on every minor GC.</p>
</blockquote>
<p>Right, perf says lots of calloc/free.</p>
<p>Micro-optimization:</p>
<p>I wonder if calloc/ZALLOC costs for zero-ing small objects in<br>
TypedData_Make_Struct ends up being measurable sometimes.<br>
We often overwrite most of the object immediately in the case of<br>
rb_proc_t.</p>
<blockquote>
<p>This problem is not critical because MRI is not for lambda calculus :p<br>
but we can improve about it.</p>
</blockquote>
<p>More micro-optimization:</p>
<p>I notice a lot of YARV mark/free functions do:</p>
<pre><code>if (ptr) { ... }
</code></pre>
<p>(e.g. proc_mark/proc_free)<br>
Maybe tiny branching + icache overheads add up for common cases where<br>
data->ptr is always valid. I'll see if it's measurable once I figure<br>
out Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: garbage symbols crash symbol GC (Closed)" href="https://bugs.ruby-lang.org/issues/10206">#10206</a>.</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=487242014-09-08T10:59:01Znormalperson (Eric Wong)normalperson@yhbt.net
<ul></ul><p>rb_env_t may use a flexible array, helps a little even on my busy system:</p>
<p><a href="http://80x24.org/misc/m/1410173063-19208-1-git-send-email-e%4080x24.org.txt" class="external">http://80x24.org/misc/m/1410173063-19208-1-git-send-email-e%4080x24.org.txt</a></p>
<p>trunk 135.18708946416155<br>
trunk 123.50244501209818<br>
trunk 133.2718793260865<br>
fa 109.13581056008115<br>
fa 116.52121020900086<br>
fa 114.37961085699499</p>
<hr>
<p>raw data:</p>
<p>[["app_lc_fizzbuzz",<br>
[[135.18708946416155, 123.50244501209818, 133.2718793260865],<br>
[109.13581056008115, 116.52121020900086, 114.37961085699499]]]]</p>
<a name="Elapsed-time-732008122514-sec"></a>
<h2 >Elapsed time: 732.008122514 (sec)<a href="#Elapsed-time-732008122514-sec" class="wiki-anchor">¶</a></h2>
<p>benchmark results:<br>
minimum results in each 3 measurements.<br>
Execution time (sec)<br>
name trunk fa<br>
app_lc_fizzbuzz 123.502 109.136</p>
<p>Speedup ratio: compare with the result of `trunk' (greater is better)<br>
name fa<br>
app_lc_fizzbuzz 1.132</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=487362014-09-08T18:58:56Zko1 (Koichi Sasada)
<ul></ul><p>(2014/09/08 19:48), Eric Wong wrote:</p>
<blockquote>
<p>rb_env_t may use a flexible array, helps a little even on my busy system:</p>
<p><a href="http://80x24.org/misc/m/1410173063-19208-1-git-send-email-e%4080x24.org.txt" class="external">http://80x24.org/misc/m/1410173063-19208-1-git-send-email-e%4080x24.org.txt</a></p>
</blockquote>
<p>Cool. Could you commit it?</p>
<p>Drastic solution is make them wb protected.<br>
But it has several problems.</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=487372014-09-08T20:49:04Znormalperson (Eric Wong)normalperson@yhbt.net
<ul></ul><p>SASADA Koichi <a href="mailto:ko1@atdot.net" class="email">ko1@atdot.net</a> wrote:</p>
<blockquote>
<p>Cool. Could you commit it?</p>
</blockquote>
<p>Done, r47453.</p>
<p>I think the xcalloc was overreaching, though.</p>
<p>Removing redundant zero from env_alloc + rb_proc_alloc has a measurable<br>
effect:</p>
<p><a href="http://80x24.org/misc/m/1410209049-23179-1-git-send-email-e%4080x24.org.txt" class="external">http://80x24.org/misc/m/1410209049-23179-1-git-send-email-e%4080x24.org.txt</a></p>
<p>Makes code a little more fragile, though, so we must be careful about<br>
GC...</p>
<p>clear 108.073316744<br>
clear 105.554970603<br>
clear 105.501751921<br>
nozero 99.350965249<br>
nozero 96.923739953<br>
nozero 100.743984655</p>
<hr>
<p>raw data:</p>
<p>[["app_lc_fizzbuzz",<br>
[[108.073316744, 105.554970603, 105.501751921],<br>
[99.350965249, 96.923739953, 100.743984655]]]]</p>
<a name="Elapsed-time-616150981421-sec"></a>
<h2 >Elapsed time: 616.150981421 (sec)<a href="#Elapsed-time-616150981421-sec" class="wiki-anchor">¶</a></h2>
<p>benchmark results:<br>
minimum results in each 3 measurements.<br>
Execution time (sec)<br>
name clear nozero<br>
app_lc_fizzbuzz 105.502 96.924</p>
<p>Speedup ratio: compare with the result of `clear' (greater is better)<br>
name nozero<br>
app_lc_fizzbuzz 1.089</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=488522014-09-11T19:21:29Znormalperson (Eric Wong)normalperson@yhbt.net
<ul></ul><p>Eric Wong <a href="mailto:normalperson@yhbt.net" class="email">normalperson@yhbt.net</a> wrote:</p>
<blockquote>
<p>I think the xcalloc was overreaching, though.</p>
<p>Removing redundant zero from env_alloc + rb_proc_alloc has a measurable<br>
effect:</p>
<p><a href="http://80x24.org/misc/m/1410209049-23179-1-git-send-email-e%4080x24.org.txt" class="external">http://80x24.org/misc/m/1410209049-23179-1-git-send-email-e%4080x24.org.txt</a></p>
<p>Makes code a little more fragile, though, so we must be careful about<br>
GC...</p>
</blockquote>
<p>Any comment? I think the improvement is worth it since proc allocation<br>
only happens in 2 places, and env allocation in 1 place.</p>
<blockquote>
<p>Speedup ratio: compare with the result of `clear' (greater is better)<br>
name nozero<br>
app_lc_fizzbuzz 1.089</p>
</blockquote> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=488562014-09-12T02:09:02Zko1 (Koichi Sasada)
<ul></ul><p>Eric Wong wrote:</p>
<blockquote>
<p>Any comment? I think the improvement is worth it since proc allocation<br>
only happens in 2 places, and env allocation in 1 place.</p>
</blockquote>
<p>For me, +1 for Env, but -1 for Proc.</p>
<p>For Env, allocation part is merged, and easy to be careful.<br>
However, rb_proc_alloc() can be called far from defenition.</p>
<p>Or inline allocation code for rb_proc_alloc()?</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=488682014-09-12T10:10:40Znormalperson (Eric Wong)normalperson@yhbt.net
<ul></ul><p><a href="mailto:ko1@atdot.net" class="email">ko1@atdot.net</a> wrote:</p>
<blockquote>
<p>Eric Wong wrote:</p>
<blockquote>
<p>Any comment? I think the improvement is worth it since proc allocation<br>
only happens in 2 places, and env allocation in 1 place.</p>
</blockquote>
<p>For me, +1 for Env, but -1 for Proc.</p>
</blockquote>
<p>OK, committed env.</p>
<blockquote>
<p>For Env, allocation part is merged, and easy to be careful.<br>
However, rb_proc_alloc() can be called far from defenition.</p>
<p>Or inline allocation code for rb_proc_alloc()?</p>
</blockquote>
<p>Yes, I think the following API is OK. rb_proc_t is big.<br>
The new inline rb_proc_alloc() takes 7(!) parameters.<br>
Maybe we can drop klass since that is always rb_cProc.</p>
<p>--- a/proc.c<br>
+++ b/proc.c<br>
@@ -84,10 +84,11 @@ static const rb_data_type_t proc_data_type = {<br>
};</p>
<p>VALUE<br>
-rb_proc_alloc(VALUE klass)<br>
+rb_proc_wrap(VALUE klass, rb_proc_t *proc)<br>
{</p>
<ul>
<li>rb_proc_t *proc;</li>
<li>return TypedData_Make_Struct(klass, rb_proc_t, &proc_data_type, proc);</li>
</ul>
<ul>
<li>proc->block.proc = TypedData_Wrap_Struct(klass, &proc_data_type, proc);</li>
<li>
<li>return proc->block.proc;<br>
}</li>
</ul>
<p>VALUE<br>
@@ -105,19 +106,12 @@ rb_obj_is_proc(VALUE proc)<br>
static VALUE<br>
proc_dup(VALUE self)<br>
{</p>
<ul>
<li>VALUE procval = rb_proc_alloc(rb_cProc);</li>
<li>rb_proc_t *src, *dst;</li>
<li>GetProcPtr(self, src);</li>
<li>GetProcPtr(procval, dst);</li>
</ul>
<ul>
<li>rb_proc_t *src;</li>
</ul>
<ul>
<li>dst->block = src->block;</li>
<li>dst->block.proc = procval;</li>
<li>dst->blockprocval = src->blockprocval;</li>
<li>dst->envval = src->envval;</li>
<li>dst->safe_level = src->safe_level;</li>
<li>dst->is_lambda = src->is_lambda;</li>
</ul>
<ul>
<li>GetProcPtr(self, src);</li>
</ul>
<ul>
<li>return procval;</li>
</ul>
<ul>
<li>return rb_proc_alloc(rb_cProc, &src->block, src->envval, src->blockprocval,</li>
<li>
<pre><code> src->safe_level, src->is_from_method, src->is_lambda);
</code></pre>
</li>
</ul>
<p>}</p>
<p>/* :nodoc: */<br>
diff --git a/vm.c b/vm.c<br>
index f5fb5a7..7c68f6e 100644<br>
--- a/vm.c<br>
+++ b/vm.c<br>
@@ -655,7 +655,6 @@ VALUE<br>
rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)<br>
{<br>
VALUE procval, envval, blockprocval = 0;</p>
<ul>
<li>
<p>rb_proc_t *proc;<br>
rb_control_frame_t *cfp = RUBY_VM_GET_CFP_FROM_BLOCK_PTR(block);</p>
<p>if (block->proc) {<br>
@@ -667,16 +666,9 @@ rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)<br>
if (PROCDEBUG) {<br>
check_env_value(envval);<br>
}</p>
</li>
<li>
<p>procval = rb_proc_alloc(klass);</p>
</li>
<li>
<p>GetProcPtr(procval, proc);</p>
</li>
<li>
<p>proc->blockprocval = blockprocval;</p>
</li>
<li>
<p>proc->block.self = block->self;</p>
</li>
<li>
<p>proc->block.klass = block->klass;</p>
</li>
<li>
<p>proc->block.ep = block->ep;</p>
</li>
<li>
<p>proc->block.iseq = block->iseq;</p>
</li>
<li>
<p>proc->block.proc = procval;</p>
</li>
<li>
<p>proc->envval = envval;</p>
</li>
<li>
<p>proc->safe_level = th->safe_level;</p>
</li>
</ul>
<ul>
<li>
<li>
<p>procval = rb_proc_alloc(klass, block, envval, blockprocval,</p>
</li>
<li>
<pre><code> th->safe_level, 0, 0);
</code></pre>
<p>if (VMDEBUG) {<br>
if (th->stack < block->ep && block->ep < th->stack + th->stack_size) {<br>
diff --git a/vm_core.h b/vm_core.h<br>
index 1c3d0cc..e34a755 100644<br>
--- a/vm_core.h<br>
+++ b/vm_core.h<br>
@@ -884,7 +884,32 @@ rb_block_t *rb_vm_control_frame_block_ptr(rb_control_frame_t *cfp);</p>
</li>
</ul>
<p>/* VM related object allocate functions */<br>
VALUE rb_thread_alloc(VALUE klass);<br>
-VALUE rb_proc_alloc(VALUE klass);<br>
+VALUE rb_proc_wrap(VALUE klass, rb_proc_t *);<br>
+<br>
+static inline VALUE<br>
+rb_proc_alloc(VALUE klass, const rb_block_t *block,</p>
<ul>
<li>
<pre><code> VALUE envval, VALUE blockprocval,
</code></pre>
</li>
<li>
<pre><code> int8_t safe_level, int8_t is_from_method, int8_t is_lambda)
</code></pre>
</li>
</ul>
<p>+{</p>
<ul>
<li>VALUE procval;</li>
<li>rb_proc_t *proc = ALLOC(rb_proc_t);</li>
<li>
<li>proc->block = *block;</li>
<li>proc->safe_level = safe_level;</li>
<li>proc->is_from_method = is_from_method;</li>
<li>proc->is_lambda = is_lambda;</li>
<li>
<li>procval = rb_proc_wrap(klass, proc);</li>
<li>
<li>/*</li>
<li>
<pre><code>* ensure VALUEs are markable here as rb_proc_wrap may trigger allocation
</code></pre>
</li>
<li>
<pre><code>* and clobber envval + blockprocval
</code></pre>
</li>
<li>
<pre><code>*/
</code></pre>
</li>
<li>proc->envval = envval;</li>
<li>proc->blockprocval = blockprocval;</li>
<li>
<li>return procval;<br>
+}</li>
</ul>
<p>/* for debug */<br>
extern void rb_vmdebug_stack_dump_raw(rb_thread_t *, rb_control_frame_t *);</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=488692014-09-12T10:19:53Zko1 (Koichi Sasada)
<ul></ul><p>(2014/09/12 19:03), Eric Wong wrote:</p>
<blockquote>
<p>Yes, I think the following API is OK. rb_proc_t is big.<br>
The new inline rb_proc_alloc() takes 7(!) parameters.<br>
Maybe we can drop klass since that is always rb_cProc.</p>
</blockquote>
<p>Nice.</p>
<p>Additionally, I recommend to move the definition from vm_core.h to vm.c<br>
(and expose it) because proc_dup() in proc.c is minor function.</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=488702014-09-12T10:28:53Znormalperson (Eric Wong)normalperson@yhbt.net
<ul></ul><p>SASADA Koichi <a href="mailto:ko1@atdot.net" class="email">ko1@atdot.net</a> wrote:</p>
<blockquote>
<p>(2014/09/12 19:03), Eric Wong wrote:</p>
<blockquote>
<p>Yes, I think the following API is OK. rb_proc_t is big.<br>
The new inline rb_proc_alloc() takes 7(!) parameters.<br>
Maybe we can drop klass since that is always rb_cProc.</p>
</blockquote>
<p>Nice.</p>
<p>Additionally, I recommend to move the definition from vm_core.h to vm.c</p>
</blockquote>
<p>OK, I think I'll move the inline to vm.c</p>
<blockquote>
<p>(and expose it) because proc_dup() in proc.c is minor function.</p>
</blockquote>
<p>But exposing it seems worse, even. In other words: the new rb_proc_alloc<br>
is the wrong interface for rb_proc_dup. I like the following much<br>
more (still using rb_proc_wrap):</p>
<p>--- a/proc.c<br>
+++ b/proc.c<br>
@@ -106,12 +106,13 @@ rb_obj_is_proc(VALUE proc)<br>
static VALUE<br>
proc_dup(VALUE self)<br>
{</p>
<ul>
<li>rb_proc_t *src;</li>
</ul>
<ul>
<li>
<p>rb_proc_t *src, *dst;</p>
<p>GetProcPtr(self, src);</p>
</li>
</ul>
<ul>
<li>return rb_proc_alloc(rb_cProc, &src->block, src->envval, src->blockprocval,</li>
<li>
<pre><code> src->safe_level, src->is_from_method, src->is_lambda);
</code></pre>
</li>
</ul>
<ul>
<li>dst = ALLOC(rb_proc_t);</li>
<li>*dst = *src;</li>
<li>return rb_proc_wrap(rb_cProc, dst);<br>
}</li>
</ul>
<p>/* :nodoc: */</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=598202016-07-28T11:21:22Zko1 (Koichi Sasada)
<ul></ul><p>Compare with the following 3 interpreters.</p>
<pre><code>target 0: trunk (ruby 2.4.0dev (2016-07-28 trunk 55767) [x86_64-linux]) at "~/ruby/install/trunk/bin/ruby"
target 1: jruby (jruby 9.1.2.0 (2.3.0) 2016-05-26 7357c8f OpenJDK 64-Bit Server VM 24.95-b01 on 1.7.0_101-b00 +jit [linux-x86_64]) at "~/tmp/jruby-9.1.2.0/bin/jruby"
target 2: mruby (mruby 1.2.0 (2015-11-17)
...
trunk 44.57820153050125
trunk 44.37776151672006
trunk 44.04692719876766
jruby 19.29094495996833
jruby 18.705794921144843
jruby 19.137680288404226
mruby 40.22595031186938
mruby 40.92319735698402
mruby 40.18542462773621
-----------------------------------------------------------
raw data:
[["app_lc_fizzbuzz",
[[44.57820153050125, 44.37776151672006, 44.04692719876766],
[19.29094495996833, 18.705794921144843, 19.137680288404226],
[40.22595031186938, 40.92319735698402, 40.18542462773621]]]]
Elapsed time: 311.477478533 (sec)
-----------------------------------------------------------
benchmark results:
minimum results in each 3 measurements.
Execution time (sec)
name trunk jruby mruby
app_lc_fizzbuzz 44.047 18.706 40.185
Speedup ratio: compare with the result of `trunk' (greater is better)
name jruby mruby
app_lc_fizzbuzz 2.355 1.096
</code></pre>
<p>JRuby wins!</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=598232016-07-28T19:15:20Zko1 (Koichi Sasada)
<ul></ul><p>r55768 makes it faster.</p>
<blockquote>
<p>app_lc_fizzbuzz 42.771 36.976 (x 1.15 faster)</p>
</blockquote>
<p>Now it is faster than mruby :p</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=598252016-07-28T20:39:31Zko1 (Koichi Sasada)
<ul></ul><p><a href="http://www.urbandictionary.com/define.php?term=omake" class="external">Omake</a></p>
<pre><code>target 0: ruby_2_0 (ruby 2.0.0p648 (2015-12-16 revision 53161) [x86_64-linux]) at "~/ruby/install/ruby_2_0_0/bin/ruby"
target 1: ruby_2_1 (ruby 2.1.10p492 (2016-04-22 revision 54691) [x86_64-linux]) at "~/ruby/install/ruby_2_1/bin/ruby"
target 2: ruby_2_2 (ruby 2.2.6p344 (2016-07-12 revision 55637) [x86_64-linux]) at "~/ruby/install/ruby_2_2/bin/ruby"
target 3: ruby_2_3 (ruby 2.3.2p139 (2016-07-11 revision 55635) [x86_64-linux]) at "~/ruby/install/ruby_2_3/bin/ruby"
target 4: trunk (ruby 2.4.0dev (2016-07-28 trunk 55767) [x86_64-linux]) at "~/ruby/install/trunk/bin/ruby"
...
-----------------------------------------------------------
raw data:
[["app_lc_fizzbuzz",
[[101.28207302466035, 107.06514655612409, 103.87018677964807],
[85.14830217137933, 88.05021686293185, 83.31006827391684],
[55.600421745330095, 53.487896678969264, 56.63330595381558],
[56.329297533258796, 55.247374195605516, 56.85174832865596],
[35.20849320106208, 35.567391984164715, 38.8587267305702]]]]
Elapsed time: 1012.521038421 (sec)
-----------------------------------------------------------
benchmark results:
minimum results in each 3 measurements.
Execution time (sec)
name ruby_2_0 ruby_2_1 ruby_2_2 ruby_2_3 trunk
app_lc_fizzbuzz 101.282 83.310 53.488 55.248 35.209
Speedup ratio: compare with the result of `ruby_2_0' (greater is better)
name ruby_2_1 ruby_2_2 ruby_2_3 trunk
app_lc_fizzbuzz 1.216 1.894 1.833 2.877
</code></pre> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=628742017-02-06T02:49:56Zko1 (Koichi Sasada)
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=705312018-02-21T07:32:21Zko1 (Koichi Sasada)
<ul></ul><p>with [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Speedup `Proc#call` to mimic `yield` (Closed)" href="https://bugs.ruby-lang.org/issues/14318">#14318</a>]</p>
<pre><code>name ruby241 ruby250 trunk
app_lc_fizzbuzz 29.140 27.950 20.056
Speedup ratio: compare with the result of `ruby241' (greater is better)
name ruby250 trunk
app_lc_fizzbuzz 1.043 1.453
</code></pre> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=705342018-02-21T07:44:28Zko1 (Koichi Sasada)
<ul></ul><p>One more:</p>
<pre><code>target 0: ruby250 (ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]) at "~/ruby/install/v2_5_0/bin/ruby"
target 1: trunk (ruby 2.6.0dev (2018-02-21 trunk 62512) [x86_64-linux]) at "~/ruby/install/trunk/bin/ruby"
target 2: mruby (mruby 1.4.0 (2018-1-16)
target 3: jruby (jruby 9.1.15.0 (2.3.3) 2017-12-07 929fde8 OpenJDK 64-Bit Server VM 9-internal+0-2016-04-14-195246.buildd.src on 9-internal+0-2016-04-14-19
...
name ruby250 trunk mruby jruby
app_lc_fizzbuzz 28.601 20.069 28.885 15.421
Speedup ratio: compare with the result of `ruby250' (greater is better)
name trunk mruby jruby
app_lc_fizzbuzz 1.425 0.990 1.855
</code></pre>
<p>JRuby is fastest.</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=717662018-05-01T17:02:54Zmvasin (Mikhail Vasin)
<ul></ul><p>I guess this is related, so I'll post it here.</p>
<p>Today I tried this code sample in MRI 2.5</p>
<pre><code>fib = lambda {|x| return x if x == 0 || x == 1; fib.call(x-1) + fib.call(x-2)}; t = Time.now; fib.call(40); puts Time.now - t
</code></pre>
<p>and an equivalent piece in Node.js:</p>
<pre><code>function fib(n) {if (n === 0 || n === 1) return n; return fib(n-1) + fib(n-2)}; t = new Date; fib(40); console.log(new Date - t)
</code></pre>
<p>MRI's Fibonacci runs for 35,5 seconds, while Node.js does the job in 1,084 seconds.</p>
<p>One can think that JavaScript is 35,5 times faster then Ruby...</p>
<p>Of course, you can calculate Fibonacci without recursion and it will be much faster, but I'm curious if there's anything that can be done to improve the performance in this particular case.</p>
<p>BTW, JRuby runs this code for 175,6 seconds on my computer. 162 times slower than Node. Wow.</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=717762018-05-02T02:12:43Zko1 (Koichi Sasada)
<ul></ul><p>On 2018/05/02 2:02, <a href="mailto:michaelvasin@gmail.com" class="email">michaelvasin@gmail.com</a> wrote:</p>
<blockquote>
<p>One can think that JavaSscript is 35,5 times faster then Ruby...</p>
</blockquote>
<p>Ruby has method and it is faster than using lambda. However, it is only<br>
x2 faster so that we have many area to improve :)</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=717902018-05-02T08:16:17Zmvasin (Mikhail Vasin)
<ul></ul><p>This code</p>
<pre><code>def fib(x)
return x if x == 0 || x == 1
fib(x-1) + fib(x-2)
end
t = Time.now; fib(40); puts Time.now - t
</code></pre>
<p>Runs 13,36 seconds on my machine. So lambda is 3 times slower. Does it have to be that slower?</p>
<p>Ruby is manifested as a multi-paradigm language, but recursion and lambdas are way too slow to actually use it in a functional style...</p> Ruby master - Bug #10212: MRI is not for lambda calculushttps://bugs.ruby-lang.org/issues/10212?journal_id=718112018-05-02T21:24:03ZEregon (Benoit Daloze)
<ul></ul><p>mvasin (Mikhail Vasin) wrote:</p>
<blockquote>
<p>Ruby is manifested as a multi-paradigm language, but recursion and lambdas are way too slow to actually use it in a functional style...</p>
</blockquote>
<p>BTW, running this with Ruby's trunk --jit gives 3.2s at me vs 10s without --jit (and fwiw 0.6s on GraalVM).<br>
So it's getting faster, don't conclude too eagerly.<br>
Also the functional style of Ruby is hardly about recursion but much more about the nice Enumerable API and blocks.</p>