[#45530] [ruby-trunk - Feature #6311][Open] memmem()によるrb_memsearch()の高速化 — "Glass_saga (Masaki Matsushita)" <glass.saga@...>

12 messages 2012/04/17

[#45554] [ruby-trunk - Bug #6344][Open] 1.9.3 p125, p194 ruby causes SEGV with test_massign.rb on ppc/ppc64 — "mtasaka (Mamoru Tasaka)" <mtasaka@...>

14 messages 2012/04/23

[ruby-dev:45488] [ruby-trunk - Feature #6082] io_binwrite()内でwritev()を使う

From: "Glass_saga (Masaki Matsushita)" <glass.saga@...>
Date: 2012-04-02 13:17:14 UTC
List: ruby-dev #45488
Issue #6082 has been updated by Glass_saga (Masaki Matsushita).

File shift_fflush.diff added
File binwrite.diff added

次のようなベンチマークを実行してみましたが、結果にばらつきはあるものの意味のある高速化にはならなかったようです。

require 'benchmark'
require 'tempfile'

str = "a" * 8000

Tempfile.open("foo") do |f|
  Benchmark.bm do |x|
    x.report do
      20000.times { f.write str }
    end
  end
end

trunk(r35215):
       user     system      total        real
   0.070000   0.240000   0.310000 (  0.346534)
       user     system      total        real
   0.110000   0.270000   0.380000 (  0.418857)
       user     system      total        real
   0.070000   0.270000   0.340000 (  0.512318)

proposal:
       user     system      total        real
   0.050000   0.240000   0.290000 (  0.363697)
       user     system      total        real
   0.050000   0.220000   0.270000 (  0.428360)
       user     system      total        real
   0.080000   0.260000   0.340000 (  0.518545)

但し、modeにFile::SYNCを指定している場合には格段に速くなるようです。

require 'benchmark'
require 'tempfile'

str = "a" * 8000

Tempfile.open("foo", nil, nil,{:mode => File::SYNC}) do |f|
  Benchmark.bm do |x|
    x.report do
      1000.times { f.write str }
    end
  end
end

trunk(r35215):
       user     system      total        real 
   0.020000   0.280000   0.300000 (  1.452105)
       user     system      total        real 
   0.010000   0.270000   0.280000 (  1.452677)
       user     system      total        real 
   0.010000   0.220000   0.230000 (  1.348059)

proposal:
       user     system      total        real 
   0.010000   0.120000   0.130000 (  0.714809)
       user     system      total        real 
   0.020000   0.120000   0.140000 (  0.669088)
       user     system      total        real 
   0.010000   0.210000   0.220000 (  0.833870)

しかし、同期モードでの書き込みが速くなる事にどれほどの意義があるのかはわかりません。

straceで見るとproposalでは確かにwritev()が使われているので、trunkにおいてmemmove()やシステムコールの呼び出しにかかるコストと、
proposalにおいてiovec構造体の配列を造るのにかかるコストが同程度な為に、同期モードでない場合には高速化に至らなかったものと思われます。
始めからきちんとベンチマークを取っていれば良かったのですが、お騒がせしました。

#ifdefを小さくする為に書いた2つのpatchをご参考までに添付します(速度面ではどちらも変わりません)。
「ここがおかしいから直せば速くなる」などありましたら指摘して下さると幸いです。
----------------------------------------
Feature #6082: io_binwrite()内でwritev()を使う
https://bugs.ruby-lang.org/issues/6082#change-25599

Author: Glass_saga (Masaki Matsushita)
Status: Feedback
Priority: Normal
Assignee: Glass_saga (Masaki Matsushita)
Category: core
Target version: 


io.cのio_binwrite()内で、writev()を用いる事を提案します。

現在のio_binwrite()は、実際にシステムコールを呼ぶ時には渡された文字列がwbufに収まるならばMEMMOVE()で収めてしまってio_fflush()し、
収まらなければfflushした後に再度rb_write_internal()を呼んでいますが、writev()を用いる事でMEMMOVE()の必要がなくなり、
wbufと渡された文字列を結合する事なく一度のシステムコールで書き出す事ができます。
また、wbufと渡された文字列を1度に書き出す事に成功すれば、他のスレッドからのwriteが間に入らないというメリットもあります。

patchを添付します。
test-allを実行したところ、test_keep_alive_EOF(TestNetHTTPKeepAlive)でfailure、test_inspect_nonascii(TestDir_M17N)でerrorとなりますが、
これはtrunkのr34799でも同様なので、このpatchによる問題ではないものと思われます。


-- 
http://bugs.ruby-lang.org/

In This Thread