[#42338] [Ruby 1.9-Bug#3907][Open] WIN32OLE_TYPELIB Can't load while envvar in the pathname . — Akio Tajima <redmine@...>
Bug #3907: WIN32OLE_TYPELIB Can't load while envvar in the pathname .
[#42345] [Ruby 1.9-Feature#3917][Open] [proposal] called_from() which is much faster than caller() — makoto kuwata <redmine@...>
Feature #3917: [proposal] called_from() which is much faster than caller()
ささだです。
桑田です。日本語が文字化けしてたようで申し訳ないです。
桑田さん
[#42369] [BUG: trunk] Lazy sweep and ObjectSpace.each_object — SASADA Koichi <ko1@...>
ささだです。
まつもと ゆきひろです
ささだです。
nariです。
ささだです。
[#42375] [Ruby 1.9-Feature#3946][Open] Array#packのqQ指定子に機種依存サイズフラグ!を追加 — Yui NARUSE <redmine@...>
Feature #3946: Array#packのqQ指定子に機種依存サイズフラグ!を追加
2010年10月14日15:36 Yui NARUSE <redmine@ruby-lang.org>:
(2010/10/14 21:07), Tanaka Akira wrote:
2010年10月14日21:29 NARUSE, Yui <naruse@airemix.jp>:
2010年10月18日13:26 Tanaka Akira <akr@fsij.org>:
2010年10月18日14:04 NARUSE, Yui <naruse@airemix.jp>:
チケット #3946 が更新されました。 (by Usaku NAKAMURA)
2010年11月25日10:57 Usaku NAKAMURA <redmine@ruby-lang.org>:
こんにちは、なかむら(う)です。
2012年2月9日16:47 U.Nakamura <usa@garbagecollect.jp>:
[#42376] [Ruby 1.9-Feature#3947][Open] Array#packのにエンディアン指定修飾子</>を追加 — Yui NARUSE <redmine@...>
Feature #3947: Array#packのにエンディアン指定修飾子</>を追加
チケット #3947 が更新されました。 (by Yui NARUSE)
2010年10月14日21:36 Yui NARUSE <redmine@ruby-lang.org>:
2010年10月15日8:01 Tanaka Akira <akr@fsij.org>:
[#42403] [Ruby 1.9-Bug#3956][Open] format() の %a 指定子で幅指定が正しく機能しない — tadayoshi funaba <redmine@...>
Bug #3956: format() の %a 指定子で幅指定が正しく機能しない
2010年10月17日23:21 tadayoshi funaba <redmine@ruby-lang.org>:
> 2010年10月17日23:21 tadayoshi funaba <redmine@ruby-lang.org>:
> > 2010年10月17日23:21 tadayoshi funaba <redmine@ruby-lang.org>:
[#42420] [Ruby 1.9-Feature#3961][Open] printfと精度指定と負の値と — Yui NARUSE <redmine@...>
Feature #3961: printfと精度指定と負の値と
[#42464] [Ruby 1.9-Bug#3990][Assigned] tests of rexml/rss reports many errors and failures without iconv — Usaku NAKAMURA <redmine@...>
Bug #3990: tests of rexml/rss reports many errors and failures without iconv
チケット #3990 が更新されました。 (by Kouhei Sutou)
成瀬です。
須藤です。
(2010/11/02 21:50), Kouhei Sutou wrote:
須藤です。
成瀬です。
須藤です。
成瀬です。
須藤です。
(2010/11/06 12:10), Kouhei Sutou wrote:
須藤です。
成瀬です。
須藤です。
成瀬です。
須藤です。
成瀬です。
須藤です。
成瀬です。
須藤です。
成瀬です。
須藤です。
成瀬です。
須藤です。
成瀬です。
須藤です。
成瀬です。
須藤です。
> iconv.soがない環境でtest-allを実行すると、rexmlとrssのテストで
[#42469] Re: [ruby-cvs:36800] Ruby:r29603 (trunk): * object.c (Init_Object), constant.h, variable.c — Yukihiro Matsumoto <matz@...>
まつもと ゆきひろです
遠藤です。
[#42477] [Ruby 1.9-Feature#3995][Open] Hash#update with Enumerable — Nobuyoshi Nakada <redmine@...>
Feature #3995: Hash#update with Enumerable
[#42480] memory profiler for test-all — SASADA Koichi <ko1@...>
ささだです。
ささだです。
[ruby-dev:42345] [Ruby 1.9-Feature#3917][Open] [proposal] called_from() which is much faster than caller()
Feature #3917: [proposal] called_from() which is much faster than caller()
http://redmine.ruby-lang.org/issues/show/3917
起票者: makoto kuwata
ステータス: Open, 優先度: Normal
カテゴリ: core, Target version: 1.9.x
I propose to introduce Kernel#called_from() which is similar to caller()
but much faster than it.
Background
----------
There are some cases to want to know from where current method is called.
In this case, Kernel#caller() is used.
But Kernel#caller() has performance issues for these cases.
* caller() retrieves entire stack frame. It is too heavy.
* caller() returns an array of "filename:linenum in `method'" string.
User must parse it and retrieve filename and linenum by rexp.
It is also very heavy weight task.
Therefore I propose Kernel#called_from() which is very light weight
compared to caller(). A certain benchmark shows that called_from()
is more than 20 times faster tan caller().
現在のメソッドがどこから呼び出されたかを知りたい場合がときどきある。
こういう場合は通常 Kernel#caller() が使われる。
しかし Kernel#caller() は、こういった用途ではパフォーマンスが非常に悪い。
* caller() はスタックフレームをすべて取り出す。これは非常に重い操作。
* caller() は "ファイル名:行番号 in `メソッド名'" という文字列の配列を返す。
ユーザは正規表現を使ってこの文字列をわざわざパースしなければならない。
これも重い操作。
そのため、Kernel#called_from() を追加することを提案する。
このメソッドは caller() と比べて非常に動作が軽く、ベンチマークでは
called_from() は caller() と比べて20倍以上高速。
Spec
-----
call-seq:
called_from(start=1) -> array or nil
Returns file name, line number, and method name of the stack.
The optional _start_ parameter represents the number of stack
entries to skip.
Returns +nil+ if _start_ is greater than the size of
current execution stack.
Raises ArgumentError if _start_ is negative value.
Example code
------------
# example.rb
1: def f1()
2: f2()
3: end
4: def f2()
5: f3()
6: end
7: def f3()
8: p called_from() #=> ["example.rb", 5, "f2"]
9: p called_from(0) #=> ["example.rb", 9, "f3"]
10: p called_from(1) #=> ["example.rb", 5, "f2"]
11: p called_from(2) #=> ["example.rb", 2, "f1"]
12: p called_from(3) #=> ["example.rb", 15, "<main>"]
13: p called_from(4) #=> nil
14: end
15: f1()
Use Case
--------
Case 1: logging method
def log_info(message)
filename, linenum, _ = called_from() # !!!
@logger.info "#{filename}:#{linenum}: #{message}"
end
Case 2: debug print
def debug(message)
filename, linenum, _ = called_from() # !!!
$stderr.puts "*** DEBUG: #{filename}:#{linenum}: #{message}"
end
Case 3: deprecation message
def send(*args)
filename, linenum, _ = called_from() # !!!
msg = "`send()' is deprecated. use `__send__()' instead."
msg << " (file: #{filename}, line: #{linenum})"
$stderr.puts "*** warning: #{msg}"
__send__(*args)
end
Case 4: ActiveSupport::Testing::Pending
module ActiveSupport::Testing::Peding
def pending(description = "", &block)
:
#caller[0] =~ (/(.*):(.*):in `(.*)'/) # original
#@@pending_cases << "#{$3} at #{$1}, line #{$2}" # original
#print "P" # original
filenemae, linenum, method = called_from() # !!!
@@pending_cases << "#{method} at #{filename}, line #{linenum}"
print "P"
:
end
end
Case 5: activesupport/lib/active_support/core_ext/module/delegation.rb
class Module
def delegate(*methods)
:
#file, line = caller.first.split(':', 2) # original
#line = line.to_i # original
file, line, _ = called_from() # !!!
:
module_eval(<<-EOS, file, line - 5)
:
end
end
Case 6: caching helper for template system
def cache_with(key)
data, created_at = @_cache_store.get(key)
filename, = called_from() # !!!
## if template file is newer than cached data then clear cache.
## (performance is very important in this case.)
if created_at < File.mtime(filename)
data = nil
@_cache_store.del(key)
end
##
if data.nil?
len = @_buf.length
yield
data = @_buf[len..-1]
@_cache_store.set(key, data)
else
@_buf << data
end
nil
end
## in template file
<% cache_with("orders/#{@order.id}") do %>
<p>Order ID: <%=h @order.id %></p>
<p>Customer: <%=h @order.customer.name %></p>
<% end %>
Benchmark
---------
Attached benchmark shows that called_from() is much faster than caller().
This is very important for logging or template timestamp check.
$ ./ruby -s bench.rb -N=100000
user system total real
caller()[0] 1.890000 0.010000 1.900000 ( 1.941812)
caller()[0] (retrieve) 2.190000 0.010000 2.200000 ( 2.225966)
called_from() 0.100000 0.000000 0.100000 ( 0.102810)
called_from() (retrieve) 0.100000 0.000000 0.100000 ( 0.102133)
Another Solutions
-----------------
Adding new gobal function may be refused.
The followings are another solutions instead of new global function.
* Extend caller() to take 'count' parameter.
For example:
start = 1
count = 1
caller(start, count) #=> ["filename:linenum in `method'"]
* Extend caller() to take 'conbine' flag.
For example:
start = 1
count = nil
conbine = false
caller(start, count, conbine)
#=> [["filename", linenum, "method"],
# ["filename", linenum, "method"],
# .... ]
* Add new standard library 'called_from.so' instead of Kernel#called_from().
新しいグローバル関数を導入するのは拒絶される可能性が高い。
その場合は、caller()を拡張してcalled_from()相当のことができるように
してもらえるとうれしい。
あるいは Kernel#called_from() ではなくても called_from.so を標準添付
する方針でもいい。
Note
----
* I tried to implement the above solutions, but failed because
vm_backtrace_each() seems to search stack frames in the reverse
order of what called_from() requires.
* I can implement called_from() as user library in Ruby 1.8.
http://rubygems.org/gems/called_from
It is allowed to access to stack frame in Ruby 1.8, but no in 1.9.
This is why I submit this propose.
* 実は上記のanother solutionsを実装しようとしたが、called_from() では
直近のスタックフレームから辿りたいのに対し、vm_backtrace_each() は
逆の順番で辿ることしかできないようなので、実装を諦めた。
* Ruby 1.8 では拡張モジュールからスタックフレームにアクセスできるので
ライブラリとして実装した。
http://rubygems.org/gems/called_from
けど1.9ではスタックフレームへのアクセスができないので、ライブラリが
作れない。そのため今回このような提案をしてみた。
----------------------------------------
http://redmine.ruby-lang.org
Attachments (3)
##
## usage: ruby -s bench.rb [-N=100000]
##
## ex.
## $ ./ruby bench.rb
## user system total real
## caller()[0] 1.890000 0.010000 1.900000 ( 1.941812)
## caller()[0] (retrieve) 2.190000 0.010000 2.200000 ( 2.225966)
## called_from() 0.100000 0.000000 0.100000 ( 0.102810)
## called_from() (retrieve) 0.100000 0.000000 0.100000 ( 0.102133)
##
require 'benchmark'
def f1; f2; end
def f2; f3; end
def f3; f4; end
def f4; f5; end
def f5; f6; end
def f6; f7; end
def f7; f8; end
def f8; f9; end
def f9; f10; end
n = ($N || 100000).to_i
Benchmark.bm(30) do |x|
## benchmarks for caller()
def f10
caller()[0]
end
x.report("caller()[0]") do
n.times { f1() }
end
x.report("caller()[0] (retrieve)") do
n.times { f1() =~ /:(\d+)/; fname = $`; lnum = $1.to_i }
end
## benchmarks for called_from()
def f10
called_from()
end
x.report("called_from()") do
n.times { f1() }
end
x.report("called_from() (retrieve)") do
n.times { fname, lnum, func_name = f1(); }
end
end