Project

General

Profile

Feature #12172

Updated by mame (Yusuke Endoh) over 4 years ago

I propose to define `Array#max`.    It is 10+ times faster than `Enumerable#max` since it skips a call to `#each`. 

 ~~~~ 
 a = [*1..10000]; 100000.times { a.max } 
 ~~~~ 

 * no patch: 22.424s 
 * Array#max defined: 1.740s 


 I don't think it is a good idea to copy all Enumerable methods to Array.    But there are two reasons why `max` is special: 

 * It is one of the most basic operations for big data processing. 
 * We often use an idiom `[a, b].max` because of the lack of `Math.max(a, b)`. 

 I think the latter is particularly important.    The idiom is concise but unsuitable in a hotspot since it creates a temporal array.    If `Array#max` is defined, we can easily optimize the idiom by introducing a special instruction like `opt_newarray_max`. 

 ~~~~ 
 x, y = 1, 2; 10000000.times { [x, y].max } 
 ~~~~ 
    
 * no patch: 2.799s 
 * Array#max defined: 1.224s 
 * opt_newarray_max: 0.555s 

 ~~~~ 
 $ ./miniruby ./miniruby.opt2 --dump=insns -e 'x, y = 1, 2; [x, [x. y].max' 
 == disasm: #<ISeq:<main>@-e>============================================ 
 local table (size: 3, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) 
 [ 3] x            [ 2] y           
 0000 trace              1                                                 (     1) 
 0002 putobject_OP_INT2FIX_O_1_C_  
 0003 putobject          2 
 0005 setlocal_OP__WC__0 2 
 0007 setlocal_OP__WC__0 3 
 0009 getlocal_OP__WC__0 3 
 0011 getlocal_OP__WC__0 2 opt_send_without_block <callinfo!mid:y, argc:0, ARGS_SIMPLE>, <callcache> 
 0013 0014 opt_newarray_max 2 1 
 0015 0016 leave 
             
 ~~~~ 

 The patches are attached.    (0001 is a preparation.    0002 introduces `Array#max`.    0003 introduces a special instruction.) 

 Of course, we can say the same for `Array#min`.    The patches include `Array#min` too. 

 What do you think?

Back