[前][次][番号順一覧][スレッド一覧]

ruby-changes:56803

From: Takashi <ko1@a...>
Date: Sun, 4 Aug 2019 22:21:31 +0900 (JST)
Subject: [ruby-changes:56803] Takashi Kokubun: 346aa557b3 (master): Make opt_eq and opt_neq insns leaf

https://git.ruby-lang.org/ruby.git/commit/?id=346aa557b3

From 346aa557b31fe96760e505d30da26eb7a846bac9 Mon Sep 17 00:00:00 2001
From: Takashi Kokubun <takashikkbn@g...>
Date: Sun, 4 Aug 2019 20:11:00 +0900
Subject: Make opt_eq and opt_neq insns leaf

# Benchmark zero?

```
require 'benchmark/ips'

Numeric.class_eval do
  def ruby_zero?
    self == 0
  end
end

Benchmark.ips do |x|
  x.report('0.zero?') { 0.ruby_zero? }
  x.report('1.zero?') { 1.ruby_zero? }
  x.compare!
end
```

## VM
No significant impact for VM.

### before
ruby 2.7.0dev (2019-08-04T02:56:02Z master 2d8c037e97) [x86_64-linux]

  0.zero?: 21855445.5 i/s
  1.zero?: 21770817.3 i/s - same-ish: difference falls within error

### after
ruby 2.7.0dev (2019-08-04T11:17:10Z opt-eq-leaf 6404bebd6a) [x86_64-linux]

  1.zero?: 21958912.3 i/s
  0.zero?: 21881625.9 i/s - same-ish: difference falls within error

## JIT
The performance improves about 1.23x.

### before
ruby 2.7.0dev (2019-08-04T02:56:02Z master 2d8c037e97) +JIT [x86_64-linux]

  0.zero?: 36343111.6 i/s
  1.zero?: 36295153.3 i/s - same-ish: difference falls within error

### after
ruby 2.7.0dev (2019-08-04T11:17:10Z opt-eq-leaf 6404bebd6a) +JIT [x86_64-linux]

  0.zero?: 44740467.2 i/s
  1.zero?: 44363616.1 i/s - same-ish: difference falls within error

# Benchmark str == str / str != str

```
# frozen_string_literal: true
require 'benchmark/ips'

Benchmark.ips do |x|
  x.report('a == a') { 'a' == 'a' }
  x.report('a == b') { 'a' == 'b' }
  x.report('a != a') { 'a' != 'a' }
  x.report('a != b') { 'a' != 'b' }
  x.compare!
end
```

## VM
No significant impact for VM.

### before
ruby 2.7.0dev (2019-08-04T02:56:02Z master 2d8c037e97) [x86_64-linux]

  a == a: 27286219.0 i/s
  a != a: 24892389.5 i/s - 1.10x  slower
  a == b: 23623635.8 i/s - 1.16x  slower
  a != b: 21800958.0 i/s - 1.25x  slower

### after
ruby 2.7.0dev (2019-08-04T11:17:10Z opt-eq-leaf 6404bebd6a) [x86_64-linux]

  a == a: 27224016.2 i/s
  a != a: 24490109.5 i/s - 1.11x  slower
  a == b: 23391052.4 i/s - 1.16x  slower
  a != b: 21811321.7 i/s - 1.25x  slower

## JIT
The performance improves on JIT a little.

### before
ruby 2.7.0dev (2019-08-04T02:56:02Z master 2d8c037e97) +JIT [x86_64-linux]

  a == a: 42010674.7 i/s
  a != a: 38920311.2 i/s - same-ish: difference falls within error
  a == b: 32574262.2 i/s - 1.29x  slower
  a != b: 32099790.3 i/s - 1.31x  slower

### after
ruby 2.7.0dev (2019-08-04T11:17:10Z opt-eq-leaf 6404bebd6a) +JIT [x86_64-linux]

  a == a: 46902738.8 i/s
  a != a: 43097258.6 i/s - 1.09x  slower
  a == b: 35822018.4 i/s - 1.31x  slower
  a != b: 33377257.8 i/s - 1.41x  slower

This is needed towards Bug#15589.
Closes: https://github.com/ruby/ruby/pull/2318

diff --git a/insns.def b/insns.def
index 7c93af6..e91382d 100644
--- a/insns.def
+++ b/insns.def
@@ -1161,7 +1161,7 @@ opt_eq https://github.com/ruby/ruby/blob/trunk/insns.def#L1161
 /* This instruction can compare a string with non-string.  This
  * (somewhat) coerces the non-string into a string, via a method
  * call. */
-// attr bool leaf = false; /* has rb_str_equal() */
+// attr bool leaf = true;
 {
     val = opt_eq_func(recv, obj, ci, cc);
 
@@ -1177,7 +1177,7 @@ opt_neq https://github.com/ruby/ruby/blob/trunk/insns.def#L1177
 (VALUE recv, VALUE obj)
 (VALUE val)
 /* Same discussion as opt_eq. */
-// attr bool leaf = false; /* has rb_str_equal() */
+// attr bool leaf = true;
 {
     val = vm_opt_neq(ci, cc, ci_eq, cc_eq, recv, obj);
 
diff --git a/internal.h b/internal.h
index 5ecb229..d391597 100644
--- a/internal.h
+++ b/internal.h
@@ -2125,6 +2125,22 @@ VALUE rb_str_eql(VALUE str1, VALUE str2); https://github.com/ruby/ruby/blob/trunk/internal.h#L2125
 VALUE rb_obj_as_string_result(VALUE str, VALUE obj);
 const char *ruby_escaped_char(int c);
 
+/* expect tail call optimization */
+static inline VALUE
+rb_str_eql_internal(const VALUE str1, const VALUE str2)
+{
+    const long len = RSTRING_LEN(str1);
+    const char *ptr1, *ptr2;
+
+    if (len != RSTRING_LEN(str2)) return Qfalse;
+    if (!rb_str_comparable(str1, str2)) return Qfalse;
+    if ((ptr1 = RSTRING_PTR(str1)) == (ptr2 = RSTRING_PTR(str2)))
+        return Qtrue;
+    if (memcmp(ptr1, ptr2, len) == 0)
+        return Qtrue;
+    return Qfalse;
+}
+
 /* symbol.c */
 #ifdef RUBY_ENCODING_H
 VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc);
diff --git a/string.c b/string.c
index edcb6aa..6cef5ab 100644
--- a/string.c
+++ b/string.c
@@ -3258,22 +3258,6 @@ rb_str_cmp(VALUE str1, VALUE str2) https://github.com/ruby/ruby/blob/trunk/string.c#L3258
     return -1;
 }
 
-/* expect tail call optimization */
-static VALUE
-str_eql(const VALUE str1, const VALUE str2)
-{
-    const long len = RSTRING_LEN(str1);
-    const char *ptr1, *ptr2;
-
-    if (len != RSTRING_LEN(str2)) return Qfalse;
-    if (!rb_str_comparable(str1, str2)) return Qfalse;
-    if ((ptr1 = RSTRING_PTR(str1)) == (ptr2 = RSTRING_PTR(str2)))
-	return Qtrue;
-    if (memcmp(ptr1, ptr2, len) == 0)
-	return Qtrue;
-    return Qfalse;
-}
-
 /*
  *  call-seq:
  *     str == obj    -> true or false
@@ -3297,7 +3281,7 @@ rb_str_equal(VALUE str1, VALUE str2) https://github.com/ruby/ruby/blob/trunk/string.c#L3281
 	}
 	return rb_equal(str2, str1);
     }
-    return str_eql(str1, str2);
+    return rb_str_eql_internal(str1, str2);
 }
 
 /*
@@ -3312,7 +3296,7 @@ rb_str_eql(VALUE str1, VALUE str2) https://github.com/ruby/ruby/blob/trunk/string.c#L3296
 {
     if (str1 == str2) return Qtrue;
     if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
-    return str_eql(str1, str2);
+    return rb_str_eql_internal(str1, str2);
 }
 
 /*
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 1875d35..e68ded7 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1506,10 +1506,11 @@ opt_eq_func(VALUE recv, VALUE obj, CALL_INFO ci, CALL_CACHE cc) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1506
 	    return rb_float_equal(recv, obj);
 	}
     }
-    else if (BUILTIN_CLASS_P(recv, rb_cString)) {
-	if (EQ_UNREDEFINED_P(STRING)) {
-	    return rb_str_equal(recv, obj);
-	}
+    else if (BUILTIN_CLASS_P(recv, rb_cString) && EQ_UNREDEFINED_P(STRING)) {
+        if (recv == obj) return Qtrue;
+        if (RB_TYPE_P(obj, T_STRING)) {
+            return rb_str_eql_internal(recv, obj);
+        }
     }
 
   fallback:
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]