From 9bc73cd81f29ab9d8fb6e7bbae0322110ecd3faa Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 29 Sep 2017 07:43:22 +0000 Subject: [PATCH] array.c: improve operations on small arrays [Feature #13884] Reduce number of memory allocations for "and", "or" and "diff" operations on small arrays Very often, arrays are used to filter parameters and to select interesting items from 2 collections and very often these collections are small enough, for example: ```ruby SAFE_COLUMNS = [:id, :title, :created_at] def columns @all_columns & SAFE_COLUMNS end ``` In this patch, I got rid of unnecessary memory allocations for small arrays when "and", "or" and "diff" operations are performed. name | HEAD | PATCH -----------------+------:+------: array_small_and | 0.615 | 0.263 array_small_diff | 0.676 | 0.282 array_small_or | 0.953 | 0.463 name | PATCH -----------------+------: array_small_and | 2.343 array_small_diff | 2.392 array_small_or | 2.056 name | HEAD | PATCH -----------------+------:+------: array_small_and | 1.429 | 1.005 array_small_diff | 1.493 | 0.878 array_small_or | 1.672 | 1.152 name | PATCH -----------------+------: array_small_and | 1.422 array_small_diff | 1.700 array_small_or | 1.452 Author: Dmitry Bochkarev git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60057 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- array.c | 54 ++++++++++++++++++++++- benchmark/bm_array_small_and.rb | 17 +++++++ benchmark/bm_array_small_diff.rb | 17 +++++++ benchmark/bm_array_small_or.rb | 17 +++++++ spec/ruby/core/array/intersection_spec.rb | 11 ++--- spec/ruby/core/array/minus_spec.rb | 10 ++--- spec/ruby/core/array/union_spec.rb | 10 ++--- test/ruby/test_array.rb | 44 ++++++++++++++++++ 8 files changed, 163 insertions(+), 17 deletions(-) create mode 100644 benchmark/bm_array_small_and.rb create mode 100644 benchmark/bm_array_small_diff.rb create mode 100644 benchmark/bm_array_small_or.rb diff --git a/array.c b/array.c index 27126cefbc..a59cb6c3e9 100644 --- a/array.c +++ b/array.c @@ -30,6 +30,7 @@ VALUE rb_cArray; #define ARY_DEFAULT_SIZE 16 #define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE)) +#define SMALL_ARRAY_LEN 16 # define ARY_SHARED_P(ary) \ (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \ @@ -3985,6 +3986,20 @@ rb_ary_includes(VALUE ary, VALUE item) return Qfalse; } +static VALUE +rb_ary_includes_by_eql(VALUE ary, VALUE item) +{ + long i; + VALUE e; + + for (i=0; i