Ruby Issue Tracking System: Issueshttps://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112018-04-24T23:28:13ZRuby Issue Tracking System
Redmine Ruby master - Feature #14710 (Open): I'd like to know from C API that "It has only one reference ...https://redmine.ruby-lang.org/issues/147102018-04-24T23:28:13Znaitoh (Jun NAITOH)
<p>I'd like to know from C API that "It has only one reference to Ruby object" to determine whether it is a temporary object.</p>
<p>Because broadcasting with python numpy is faster for</p>
<pre><code>(1 line case)
y = x + 1 + 1
</code></pre>
<p>than</p>
<pre><code>(2 line case)
y = x + 1
y + 1
</code></pre>
<p>.</p>
<p>In 1 line case, since the result of x + 1 is not stored in the variable, it is determined to be a temporary object (in case of "refcnt == 1") and the in-place operation is performed as it is.<br>
(A new calculation result storage area is not used.)</p>
<p>Please see the comment of numpy.<br>
<a href="https://github.com/numpy/numpy/blob/ac76793dafcd6e5f24ed052fc40413f29ebc5306/numpy/core/src/multiarray/temp_elide.c#L276" class="external">https://github.com/numpy/numpy/blob/ac76793dafcd6e5f24ed052fc40413f29ebc5306/numpy/core/src/multiarray/temp_elide.c#L276</a></p>
<p>Ruby's Numo::NArray also wants to speed up the computation speed by performing similar processing, but since I think that Ruby Object does not have a reference counter, I think that it can not be realized with the current Ruby.</p>
<p>Is not there a good idea?</p>
<a name="Benchmarked-code"></a>
<h1 >Benchmarked code<a href="#Benchmarked-code" class="wiki-anchor">¶</a></h1>
<a name="Python-numpy-Benchmarked-code"></a>
<h2 >Python numpy Benchmarked code<a href="#Python-numpy-Benchmarked-code" class="wiki-anchor">¶</a></h2>
<pre><code>$ cat inplace.py
from benchmarker import Benchmarker
import numpy as np
## specify number of loop
with Benchmarker(5000, width=40) as bench:
@bench(None) ## empty loop
def _(bm):
x = np.ones([1000,784], dtype=np.float32)
for i in bm:
pass
@bench("y = x + 1.0; y + 1.0")
def _(bm):
x = np.ones([1000,784], dtype=np.float32)
for i in bm:
y = x + 1.0
y + 1.0
@bench("x + 1.0")
def _(bm):
x = np.ones([1000,784], dtype=np.float32)
for i in bm:
x + 1.0
@bench("x + 1.0 + 1.0")
def _(bm):
x = np.ones([1000,784], dtype=np.float32)
for i in bm:
x + 1.0 + 1.0
@bench("x + 1.0 + 1.0 + 1.0")
def _(bm):
x = np.ones([1000,784], dtype=np.float32)
for i in bm:
x + 1.0 + 1.0 + 1.0
@bench("x += 1.0")
def _(bm):
x = np.ones([1000,784], dtype=np.float32)
for i in bm:
x += 1.0
</code></pre>
<a name="Ruby-NumoNArray-Benchmarked-code"></a>
<h2 >Ruby Numo::NArray Benchmarked code<a href="#Ruby-NumoNArray-Benchmarked-code" class="wiki-anchor">¶</a></h2>
<pre><code>$ cat inplace.rb
require 'benchmark'
require 'numo/narray'
num_iteration = 5000
Benchmark.bm 40 do |r|
x = Numo::SFloat.ones([1000,784])
r.report "y = x + 1.0; y + 1.0" do
num_iteration.times do
y = x + 1.0
y + 1.0
end
end
x = Numo::SFloat.ones([1000,784])
r.report "x + 1.0" do
num_iteration.times do
x + 1.0
end
end
x = Numo::SFloat.ones([1000,784])
r.report "x + 1.0 + 1.0" do
num_iteration.times do
x + 1.0 + 1.0
end
end
x = Numo::SFloat.ones([1000,784])
r.report "x + 1.0 + 1.0 + 1.0" do
num_iteration.times do
x + 1.0 + 1.0 + 1.0
end
end
x = Numo::SFloat.ones([1000,784])
r.report "x.inplace + 1.0" do
num_iteration.times do
x.inplace + 1.0
end
end
x = Numo::SFloat.ones([1000,784])
r.report "(x + 1.0).inplace + 1.0" do
num_iteration.times do
(x + 1.0).inplace + 1.0
end
end
x = Numo::SFloat.ones([1000,784])
r.report "(x + 1.0).inplace + 1.0 + 1.0" do
num_iteration.times do
(x + 1.0).inplace + 1.0 + 1.0
end
end
end
</code></pre>
<a name="Result"></a>
<h1 >Result<a href="#Result" class="wiki-anchor">¶</a></h1>
<a name="Python-numpy-Result"></a>
<h2 >Python numpy Result<a href="#Python-numpy-Result" class="wiki-anchor">¶</a></h2>
<pre><code>$ python inplace.py
## benchmarker: release 4.0.1 (for python)
## python version: 2.7.5
## python compiler: GCC 4.8.5 20150623 (Red Hat 4.8.5-16)
## python platform: Linux-3.10.0-514.6.1.el7.x86_64-x86_64-with-centos-7.3.1611-Core
## python executable: /usr/bin/python
## cpu model: Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz # 2299.822 MHz
## parameters: loop=5000, cycle=1, extra=0
## real (total = user + sys)
(Empty) 0.0022 0.0000 0.0000 0.0000
y = x + 1.0; y + 1.0 6.5245 6.0100 5.9900 0.0200
x + 1.0 3.2048 2.9600 2.9500 0.0100
x + 1.0 + 1.0 4.4024 4.0500 4.0500 0.0000
x + 1.0 + 1.0 + 1.0 5.7188 5.2700 5.2500 0.0200
x += 1.0 1.2219 1.1300 1.1300 0.0000
</code></pre>
<p>Please look at the column of total.<br>
x + = 1.0 is the calculation result in pure in-place.</p>
<a name="Ruby-NumoNArray-Result-current-master-7bba089-Ruby-251"></a>
<h2 >Ruby Numo::NArray Result (current master 7bba089, Ruby 2.5.1)<a href="#Ruby-NumoNArray-Result-current-master-7bba089-Ruby-251" class="wiki-anchor">¶</a></h2>
<pre><code>$ ruby inplace.rb
user system total real
y = x + 1.0; y + 1.0 6.014225 1.091965 7.106190 ( 7.709003)
x + 1.0 3.013632 0.697821 3.711453 ( 4.023327)
x + 1.0 + 1.0 6.175142 0.958922 7.134064 ( 7.769464)
x + 1.0 + 1.0 + 1.0 9.290738 1.716084 11.006822 ( 11.982892)
x.inplace + 1.0 1.496372 0.011782 1.508154 ( 1.636363)
(x + 1.0).inplace + 1.0 5.151556 0.687806 5.839362 ( 6.340946)
(x + 1.0).inplace + 1.0 + 1.0 6.714924 0.784504 7.499428 ( 8.138534)
</code></pre>
<p>In Numo::NArray, "y = x + 1; y + 1" and "y = x + 1 + 1" have the same calculation speed.<br>
Since Numo::NArray can not determine the temporary object, in order to do the same processing it is necessary to explicitly set inplace().</p> Ruby master - Feature #14701 (Open): If the object is not frozen, I want to be able to redefine t...https://redmine.ruby-lang.org/issues/147012018-04-19T23:30:07Znaitoh (Jun NAITOH)
<p>If the object is not frozen, I want to be able to redefine the compound assignment operator (e.g. +=, -=, *=, /=, ..etc ).</p>
<p><a href="https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html" class="external">https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html</a></p>
<ul>
<li>Redefinable operator (method)</li>
</ul>
<pre><code> | ^ & <=> == === =~ > >= < <= << >>
+ - * / % ** ~ +@ -@ [] []= ` ! != !~
</code></pre>
<ul>
<li>use case</li>
</ul>
<pre><code>> require 'numo/narray'
> a = Numo::Int32[5, 6]
=> Numo::Int32#shape=[2]
[5, 6]
> a.object_id
=> 70326927544920
> a += 1
=> Numo::Int32#shape=[2]
[6, 7]
> a.object_id
=> 70326927530540
> a.inplace + 1
=> Numo::Int32(view)#shape=[2]
[7, 8]
> a.object_id
=> 70326927530540
</code></pre>
<p>With Numo::NArray, using "inplace" instead of "+=" will update the same object so it will be faster.</p>
<p>I want to write "a += 1" instead of "a.inplace + 1".<br>
However, Ruby can not redefine "+=".</p> Ruby master - Bug #9848 (Third Party's Issue): OpenSSL::SSL::SSLContext の SSLv2 利用不可サーバへの接続時のデフォル...https://redmine.ruby-lang.org/issues/98482014-05-19T01:50:28Znaitoh (Jun NAITOH)
<p>SSLv2利用不可なサーバに対する環境において、<br>
以下のようなコードを 1.8.7 と 1.9.3 と 2.0.0 で実行した場合の結果が異なりました。</p>
<p>確認した ruby 版数は以下になります。</p>
<ul>
<li>ruby 1.8.7p299</li>
<li>ruby 1.9.3p484</li>
<li>ruby 2.0.0p481</li>
</ul>
<a name="SSLContex-オプション指定無し"></a>
<h3 >SSLContex オプション指定無し。<a href="#SSLContex-オプション指定無し" class="wiki-anchor">¶</a></h3>
<pre><code>$ cat ssl_ng.rb
require 'socket'
require 'openssl'
io = TCPSocket.new("XXX.com", XXXX)
ctx = OpenSSL::SSL::SSLContext.new
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
conn.connect
</code></pre>
<ul>
<li>
<p>ruby 1.8.7<br>
⇒ 問題無し。</p>
</li>
<li>
<p>ruby 1.9.3/2.0.0<br>
⇒ エラー発生。<br>
ssl_ng.rb:7:in `connect': SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: (null) (OpenSSL::SSL::SSLError)</p>
</li>
</ul>
<a name="SSLv3-指定時"></a>
<h3 >SSLv3 指定時<a href="#SSLv3-指定時" class="wiki-anchor">¶</a></h3>
<p>以下の様に SSLv3 を明示的に指定した場合は問題なく接続できました。</p>
<pre><code>$ cat ssl_ok.rb
require 'socket'
require 'openssl'
io = TCPSocket.new("XXX.com", XXXX)
ctx = OpenSSL::SSL::SSLContext.new(:SSLv3)
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
conn.connect
</code></pre>
<ul>
<li>ruby 1.8.7/1.9.3/2.0.0<br>
⇒ 問題無し。</li>
</ul>
<a name="SSLv2-指定時"></a>
<h3 >SSLv2 指定時<a href="#SSLv2-指定時" class="wiki-anchor">¶</a></h3>
<p>以下の様に SSLv2 を明示的に指定した場合は、全てエラーしました。 (期待通り)</p>
<pre><code>$ cat ssl_ng1.rb
require 'socket'
require 'openssl'
io = TCPSocket.new("XXX.com", XXXX)
ctx = OpenSSL::SSL::SSLContext.new(:SSLv2)
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
conn.connect
</code></pre>
<ul>
<li>ruby 1.8.7/2.0.0<br>
⇒ エラー発生。<br>
ssl_ng1.rb:7:in `connect': SSL_connect returned=6 errno=0 state=SSLv2 read server hello A (OpenSSL::SSL::SSLError)</li>
</ul>
<p>※ 1.9.3 は "ssl_ng1.rb:5:in <code>initialize': unknown SSL method </code>SSLv2'. (ArgumentError)" となったので未確認。</p>
<a name="SSLv23-指定時"></a>
<h3 >SSLv23 指定時<a href="#SSLv23-指定時" class="wiki-anchor">¶</a></h3>
<p>SSLv23 を明示的に指定時には、1.9.3 と 2.0.0 でエラーが発生しました。</p>
<pre><code>$ cat ssl_ng2.rb
require 'socket'
require 'openssl'
io = TCPSocket.new("XXX.com", XXXX)
ctx = OpenSSL::SSL::SSLContext.new(:SSLv23)
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
conn.connect
</code></pre>
<ul>
<li>
<p>ruby 1.8.7<br>
⇒ 問題無し。</p>
</li>
<li>
<p>ruby 1.9.3/2.0.0<br>
⇒ エラー発生。<br>
ssl_ng2.rb:7:in `connect': SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: (null) (OpenSSL::SSL::SSLError)</p>
</li>
</ul>
<p>OpenSSL::SSL::SSLContextのデフォルト値として SSLv23 が設定されていると思うのですが、</p>
<ul>
<li>ruby 1.8.7 : TLSv1/SSLv2/SSLv3 のいずれかが利用可能であれば、OK</li>
<li>ruby 1.9以降 : TLSv1/SSLv2/SSLv3 の全てが利用可能であれば、OK (SSLv2が利用不可の場合はエラー)</li>
</ul>
<p>のように、挙動が変更になっていると推測されます。</p>
<p>ruby 1.8.7の挙動の方が望ましいと思うのですがいかがでしょうか</p>
<p>net-ldap (0.3.1 or 0.6.1)などでは、SSLContext をオプション指定無しで利用しているため、SSLv2 利用不可のサーバに接続する場合、ruby 1.9以降では接続できません。</p>