From: makoto kuwata Date: 2010-10-08T08:46:00+09:00 Subject: [ruby-dev:42345] [Ruby 1.9-Feature#3917][Open] [proposal] called_from() which is much faster than caller() --mimepart_4cae5bb5d684a_eedcc8fdc8184a1 Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: Quoted-printable Content-Disposition: inline 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, "
"] 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 %>

Order ID: <%=h @order.id %>

Customer: <%=h @order.customer.name %>

<% 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 --mimepart_4cae5bb5d684a_eedcc8fdc8184a1 Content-Type: application/octet-stream; name=0001-add-Kernel-called_from-which-is-similar-to-caller.patch Content-Transfer-Encoding: Base64 Content-Disposition: attachment; filename=0001-add-Kernel-called_from-which-is-similar-to-caller.patch RnJvbSA1MzRiZDdkODY4YjU4OWVkMWM3MGMxODFlMWZhOTk2NjExYjE1YWVh IE1vbiBTZXAgMTcgMDA6MDA6MDAgMjAwMQpGcm9tOiBtYWtvdG8ga3V3YXRh IDxrd2FAa3V3YXRhLWxhYi5jb20+CkRhdGU6IE1vbiwgMjcgU2VwIDIwMTAg MDY6Mjc6NDggKzA5MDAKU3ViamVjdDogW1BBVENIIDEvMl0gYWRkIEtlcm5l bCNjYWxsZWRfZnJvbSgpIHdoaWNoIGlzIHNpbWlsYXIgdG8gY2FsbGVyKCkK CiogU2VlIGNvbW1lbnQgb2YgcmJfZl9jYWxsZWRfZnJvbSgpIG9uIHZtX2V2 YWwuYyBmb3IgZGV0YWlscy4KLS0tCiB2bS5jICAgICAgfCAgIDIzICsrKysr KysrKysrKysrKysrKysrKysrCiB2bV9ldmFsLmMgfCAgIDQ2ICsrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIDIgZmls ZXMgY2hhbmdlZCwgNjkgaW5zZXJ0aW9ucygrKSwgMCBkZWxldGlvbnMoLSkK CmRpZmYgLS1naXQgYS92bS5jIGIvdm0uYwppbmRleCBjZmM5MzEyLi5iODU0 Zjc2IDEwMDY0NAotLS0gYS92bS5jCisrKyBiL3ZtLmMKQEAgLTc0OCw2ICs3 NDgsMjkgQEAgdm1fYmFja3RyYWNlX2VhY2gocmJfdGhyZWFkX3QgKnRoLCBp bnQgbGV2LCB2b2lkICgqaW5pdCkodm9pZCAqKSwgcmJfYmFja3RyYWNlX2kK ICAgICByZXR1cm4gVFJVRTsKIH0KIAorc3RhdGljIFZBTFVFCit2bV9iYWNr dHJhY2VfZ2V0X2xvY2F0aW9uKHJiX3RocmVhZF90ICp0aCwgaW50IGxldikK K3sKKyAgICBjb25zdCByYl9jb250cm9sX2ZyYW1lX3QgKmxpbWl0X2NmcCA9 IHRoLT5jZnA7CisgICAgY29uc3QgcmJfY29udHJvbF9mcmFtZV90ICpjZnAg PSAodm9pZCAqKSh0aC0+c3RhY2sgKyB0aC0+c3RhY2tfc2l6ZSk7CisgICAg aW50IGxpbmVfbm87CisgICAgVkFMVUUgZmlsZW5hbWUsIG5hbWU7CisKKyAg ICBjZnAgLT0gMjsKKyAgICB3aGlsZSAobGV2LS0gPj0gMCkgeworCWlmICgr K2xpbWl0X2NmcCA+IGNmcCkgeworCSAgICByZXR1cm4gUW5pbDsKKwl9Cisg ICAgfQorICAgIGlmIChsaW1pdF9jZnAtPmlzZXEgPT0gTlVMTCkgeworCXJl dHVybiBRbmlsOworICAgIH0KKyAgICBsaW5lX25vICA9IHJiX3ZtX2dldF9z b3VyY2VsaW5lKGxpbWl0X2NmcCk7CisgICAgZmlsZW5hbWUgPSBsaW1pdF9j ZnAtPmlzZXEtPmZpbGVuYW1lOworICAgIG5hbWUgICAgID0gbGltaXRfY2Zw LT5pc2VxLT5uYW1lOworICAgIHJldHVybiByYl9hcnlfbmV3MygzLCBmaWxl bmFtZSwgbGluZV9ubyA/IElOVDJOVU0obGluZV9ubykgOiBRbmlsLCBuYW1l KTsKK30KKwogc3RhdGljIHZvaWQKIHZtX2JhY2t0cmFjZV9hbGxvYyh2b2lk ICphcmcpCiB7CmRpZmYgLS1naXQgYS92bV9ldmFsLmMgYi92bV9ldmFsLmMK aW5kZXggNDEzNzE4OS4uOTBiNjE5NSAxMDA2NDQKLS0tIGEvdm1fZXZhbC5j CisrKyBiL3ZtX2V2YWwuYwpAQCAtMTgsNiArMTgsNyBAQCBzdGF0aWMgaW5s aW5lIFZBTFVFIHZtX3lpZWxkKHJiX3RocmVhZF90ICp0aCwgaW50IGFyZ2Ms IGNvbnN0IFZBTFVFICphcmd2KTsKIHN0YXRpYyBpbmxpbmUgVkFMVUUgdm1f YmFja3RyYWNlKHJiX3RocmVhZF90ICp0aCwgaW50IGxldik7CiBzdGF0aWMg aW50IHZtX2JhY2t0cmFjZV9lYWNoKHJiX3RocmVhZF90ICp0aCwgaW50IGxl diwgdm9pZCAoKmluaXQpKHZvaWQgKiksIHJiX2JhY2t0cmFjZV9pdGVyX2Z1 bmMgKml0ZXIsIHZvaWQgKmFyZyk7CiBzdGF0aWMgTk9ERSAqdm1fY3JlZl9w dXNoKHJiX3RocmVhZF90ICp0aCwgVkFMVUUga2xhc3MsIGludCBub2V4LCBy Yl9ibG9ja190ICpibG9ja3B0cik7CitzdGF0aWMgVkFMVUUgdm1fYmFja3Ry YWNlX2dldF9sb2NhdGlvbihyYl90aHJlYWRfdCAqdGgsIGludCBsZXYpOwog c3RhdGljIFZBTFVFIHZtX2V4ZWMocmJfdGhyZWFkX3QgKnRoKTsKIHN0YXRp YyB2b2lkIHZtX3NldF9ldmFsX3N0YWNrKHJiX3RocmVhZF90ICogdGgsIFZB TFVFIGlzZXF2YWwsIGNvbnN0IE5PREUgKmNyZWYpOwogc3RhdGljIGludCB2 bV9jb2xsZWN0X2xvY2FsX3ZhcmlhYmxlc19pbl9oZWFwKHJiX3RocmVhZF90 ICp0aCwgVkFMVUUgKmRmcCwgVkFMVUUgYXJ5KTsKQEAgLTE1ODMsNiArMTU4 NCw1MCBAQCByYl9mX2NhbGxlcihpbnQgYXJnYywgVkFMVUUgKmFyZ3YpCiAg ICAgcmV0dXJuIHZtX2JhY2t0cmFjZShHRVRfVEhSRUFEKCksIGxldik7CiB9 CiAKKy8qCisgKiAgY2FsbC1zZXE6CisgKiAgICAgY2FsbGVkX2Zyb20oc3Rh cnQ9MSkgICAgLT4gYXJyYXkgb3IgbmlsCisgKgorICogIFJldHVybnMgZmls ZSBuYW1lLCBsaW5lIG51bWJlciwgYW5kIG1ldGhvZCBuYW1lIG9mIHRoZSBz dGFjay4KKyAqICBUaGUgb3B0aW9uYWwgX3N0YXJ0XyBwYXJhbWV0ZXIgcmVw cmVzZW50cyB0aGUgbnVtYmVyIG9mIHN0YWNrCisgKiAgZW50cmllcyB0byBz a2lwLgorICoKKyAqICBSZXR1cm5zICtuaWwrIGlmIF9zdGFydF8gaXMgZ3Jl YXRlciB0aGFuIHRoZSBzaXplIG9mCisgKiAgY3VycmVudCBleGVjdXRpb24g c3RhY2suCisgKgorICogIFJhaXNlcyBBcmd1bWVudEVycm9yIGlmIF9zdGFy dF8gaXMgbmVnYXRpdmUgdmFsdWUuCisgKgorICogICAgICMgZXhhbXBsZS5y YgorICogICAgICAxOiAgZGVmIGYxKCkKKyAqICAgICAgMjogICAgZjIoKQor ICogICAgICAzOiAgZW5kCisgKiAgICAgIDQ6ICBkZWYgZjIoKQorICogICAg ICA1OiAgICBmMygpCisgKiAgICAgIDY6ICBlbmQKKyAqICAgICAgNzogIGRl ZiBmMygpCisgKiAgICAgIDg6ICAgIHAgY2FsbGVkX2Zyb20oKSAgICAjPT4g WyJleGFtcGxlLnJiIiwgNSwgImYyIl0KKyAqICAgICAgOTogICAgcCBjYWxs ZWRfZnJvbSgwKSAgICM9PiBbImV4YW1wbGUucmIiLCA5LCAiZjMiXQorICog ICAgIDEwOiAgICBwIGNhbGxlZF9mcm9tKDEpICAgIz0+IFsiZXhhbXBsZS5y YiIsIDUsICJmMiJdCisgKiAgICAgMTE6ICAgIHAgY2FsbGVkX2Zyb20oMikg ICAjPT4gWyJleGFtcGxlLnJiIiwgMiwgImYxIl0KKyAqICAgICAxMjogICAg cCBjYWxsZWRfZnJvbSgzKSAgICM9PiBbImV4YW1wbGUucmIiLCAxNSwgIjxt YWluPiJdCisgKiAgICAgMTM6ICAgIHAgY2FsbGVkX2Zyb20oNCkgICAjPT4g bmlsCisgKiAgICAgMTQ6ICBlbmQKKyAqICAgICAxNTogIGYxKCkKKyAqLwor c3RhdGljIFZBTFVFCityYl9mX2NhbGxlZF9mcm9tKGludCBhcmdjLCBWQUxV RSAqYXJndikKK3sKKyAgICBWQUxVRSBsZXZlbDsKKyAgICBpbnQgbGV2Owor ICAgIFZBTFVFIGFyeSA9IFFuaWw7CisKKyAgICByYl9zY2FuX2FyZ3MoYXJn YywgYXJndiwgIjAxIiwgJmxldmVsKTsKKyAgICBsZXYgPSBOSUxfUChsZXZl bCkgPyAxIDogTlVNMklOVChsZXZlbCk7CisgICAgaWYgKGxldiA8IDApIHJi X3JhaXNlKHJiX2VBcmdFcnJvciwgIm5lZ2F0aXZlIGxldmVsICglZCkiLCBs ZXYpOworCisgICAgcmV0dXJuIHZtX2JhY2t0cmFjZV9nZXRfbG9jYXRpb24o R0VUX1RIUkVBRCgpLCBsZXYpOworfQorCiBzdGF0aWMgaW50CiBwcmludF9i YWNrdHJhY2Uodm9pZCAqYXJnLCBWQUxVRSBmaWxlLCBpbnQgbGluZSwgVkFM VUUgbWV0aG9kKQogewpAQCAtMTc3NCw1ICsxODE5LDYgQEAgSW5pdF92bV9l dmFsKHZvaWQpCiAgICAgcmJfZGVmaW5lX21ldGhvZChyYl9jTW9kdWxlLCAi Y2xhc3NfZXZhbCIsIHJiX21vZF9tb2R1bGVfZXZhbCwgLTEpOwogCiAgICAg cmJfZGVmaW5lX2dsb2JhbF9mdW5jdGlvbigiY2FsbGVyIiwgcmJfZl9jYWxs ZXIsIC0xKTsKKyAgICByYl9kZWZpbmVfZ2xvYmFsX2Z1bmN0aW9uKCJjYWxs ZWRfZnJvbSIsIHJiX2ZfY2FsbGVkX2Zyb20sIC0xKTsKIH0KIAotLSAKMS43 LjIuMwoK --mimepart_4cae5bb5d684a_eedcc8fdc8184a1 Content-Type: application/octet-stream; name=0002-add-test-script-for-Kernel-called_from.patch Content-Transfer-Encoding: Base64 Content-Disposition: attachment; filename=0002-add-test-script-for-Kernel-called_from.patch RnJvbSBhNTgyYTIyZmEwNWU0MTU3ZDg1Y2U2NDIwOGRmZDFmYmI2NGM0NGE0 IE1vbiBTZXAgMTcgMDA6MDA6MDAgMjAwMQpGcm9tOiBtYWtvdG8ga3V3YXRh IDxrd2FAa3V3YXRhLWxhYi5jb20+CkRhdGU6IE1vbiwgMjcgU2VwIDIwMTAg MDY6NTk6MjIgKzA5MDAKU3ViamVjdDogW1BBVENIIDIvMl0gYWRkIHRlc3Qg c2NyaXB0IGZvciBLZXJuZWwjY2FsbGVkX2Zyb20oKQoKLS0tCiB0ZXN0L3J1 YnkvdGVzdF9jYWxsZWRfZnJvbS5yYiB8ICAgNzcgKysrKysrKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKysKIDEgZmlsZXMgY2hhbmdlZCwg NzcgaW5zZXJ0aW9ucygrKSwgMCBkZWxldGlvbnMoLSkKIGNyZWF0ZSBtb2Rl IDEwMDY0NCB0ZXN0L3J1YnkvdGVzdF9jYWxsZWRfZnJvbS5yYgoKZGlmZiAt LWdpdCBhL3Rlc3QvcnVieS90ZXN0X2NhbGxlZF9mcm9tLnJiIGIvdGVzdC9y dWJ5L3Rlc3RfY2FsbGVkX2Zyb20ucmIKbmV3IGZpbGUgbW9kZSAxMDA2NDQK aW5kZXggMDAwMDAwMC4uMGRkNWE5MQotLS0gL2Rldi9udWxsCisrKyBiL3Rl c3QvcnVieS90ZXN0X2NhbGxlZF9mcm9tLnJiCkBAIC0wLDAgKzEsNzcgQEAK K3JlcXVpcmUgJ3Rlc3QvdW5pdCcKKworCitjbGFzcyBUZXN0Q2FsbGVkRnJv bSA8IFRlc3Q6OlVuaXQ6OlRlc3RDYXNlCisKKyAgZGVmIHNwZWModGV4dCkK KyAgICB5aWVsZAorICBlbmQKKworICBkZWYgc2V0dXAKKyAgICAjQGZuYW1l ID0gRmlsZS5iYXNlbmFtZShfX0ZJTEVfXykKKyAgICAjQGZuYW1lID0gRmls ZS5leHBhbmRfcGF0aChGaWxlLmJhc2VuYW1lKF9fRklMRV9fKSkKKyAgICBA Zm5hbWUgPSBjYWxsZXIoMCkuZmlyc3Quc3BsaXQoLzpcZCs6aW4vKS5maXJz dAorICBlbmQKKworICBkZWYgZjEobikKKyAgICBAZjFfbGluZW51bSA9IF9f TElORV9fICsgMQorICAgIGYyKG4pCisgIGVuZAorCisgIGRlZiBmMihuKQor ICAgIEBmMl9saW5lbnVtID0gX19MSU5FX18gKyAxCisgICAgZjMobikKKyAg ZW5kCisKKyAgZGVmIGYzKG4pCisgICAgQGYzX2xpbmVudW0gPSBfX0xJTkVf XyArIDEKKyAgICBmNChuKQorICBlbmQKKworICBkZWYgZjQobikKKyAgICBA ZjRfbGluZW51bSA9IF9fTElORV9fICsgMQorICAgIGNhbGxlZF9mcm9tKG4p CisgIGVuZAorCisgIGRlZiB0ZXN0X2NhbGxlZF9mcm9tX3JldHVybl92YWx1 ZQorICAgIHNwZWMgJ3JldHVybnMgYXJyYXkgb2YgZmlsZW5hbWUsIGxpbmUg bnVtYmVyLCBhbmQgZnVuY3Rpb24gbmFtZScgZG8KKyAgICAgIGEgPSBmMShu aWwpCisgICAgICBhc3NlcnRfZXF1YWwoW0BmbmFtZSwgQGYzX2xpbmVudW0s ICJmMyJdLCBhKQorICAgIGVuZAorICBlbmQKKworICBkZWYgdGVzdF9jYWxs ZWRfZnJvbV93aXRoXzEKKyAgICBzcGVjICdpZiBsZXZlbCBpcyBub3Qgc3Bl Y2lmaWVkIHRoZW4gcmV0dXJucyB0aGUgc2FtZSBhcyBhcmcgMSBzcGVjaWZp ZWQnIGRvCisgICAgICBlID0gZjEoMSkKKyAgICAgIGEgPSBmMShuaWwpCisg ICAgICBhc3NlcnRfZXF1YWwoZSwgYSkKKyAgICBlbmQKKyAgZW5kCisKKyAg ZGVmIHRlc3RfY2FsbGVkX2Zyb21fd2l0aF9uCisgICAgc3BlYyAnbGV2ZWwg aXMgc3BlY2lmaWVkIHRoZW4gcmV0dXJucyBhcnJheSBhY2NvcmRpbmcgdG8g bGV2ZWwnIGRvCisgICAgICBhID0gZjEoMikKKyAgICAgIGFzc2VydF9lcXVh bChbQGZuYW1lLCBAZjJfbGluZW51bSwgImYyIl0sIGEpCisgICAgICBhID0g ZjEoMykKKyAgICAgIGFzc2VydF9lcXVhbChbQGZuYW1lLCBAZjFfbGluZW51 bSwgImYxIl0sIGEpCisgICAgZW5kCisgIGVuZAorCisgIGRlZiB0ZXN0X2Nh bGxlZF9mcm9tX3Rvb19kZWVwCisgICAgc3BlYyAnY2FsbGVkIHdpdGggdG9v IGRlZXAgbGV2ZWwgdGhlbiByZXR1cm5zIG5pbCcgZG8KKyAgICAgIGFzc2Vy dF9uaWwoZjEoMTAwKSkKKyAgICBlbmQKKyAgZW5kCisKKyAgZGVmIHRlc3Rf Y2FsbGVkX2Zyb21fb25fdG9wbGV2ZWwKKyAgICBzcGVjICdsaW5lIG51bWJl ciBtYXkgYmUgbmlsJyBkbworICAgICAgYSA9IGV2YWwoJ2NhbGxlZF9mcm9t KDApJywgVE9QTEVWRUxfQklORElORykKKyAgICAgIGFzc2VydF9lcXVhbChb IjxtYWluPiIsIG5pbCwgIjxtYWluPiJdLCBhKQorICAgIGVuZAorICAgIHNw ZWMgJ3JldHVybiBuaWwgaWYgc3RhY2sgZnJhbWUgbm90IGZvdW5kJyBkbwor ICAgICAgYSA9IGV2YWwoJ2NhbGxlZF9mcm9tJywgVE9QTEVWRUxfQklORElO RykKKyAgICAgIGFzc2VydF9uaWwoYSkKKyAgICBlbmQKKyAgZW5kCisKK2Vu ZAotLSAKMS43LjIuMwoK --mimepart_4cae5bb5d684a_eedcc8fdc8184a1 Content-Type: text/x-ruby-script; name=bench.rb Content-Transfer-Encoding: Base64 Content-Disposition: attachment; filename=bench.rb IyMKIyMgIHVzYWdlOiBydWJ5IC1zIGJlbmNoLnJiIFstTj0xMDAwMDBdCiMj CiMjICBleC4KIyMgICAgICQgLi9ydWJ5IGJlbmNoLnJiCiMjICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyICAgICBzeXN0 ZW0gICAgICB0b3RhbCAgICAgICAgcmVhbAojIyAgICAgY2FsbGVyKClbMF0g ICAgICAgICAgICAgICAgICAgICAxLjg5MDAwMCAgIDAuMDEwMDAwICAgMS45 MDAwMDAgKCAgMS45NDE4MTIpCiMjICAgICBjYWxsZXIoKVswXSAocmV0cmll dmUpICAgICAgICAgIDIuMTkwMDAwICAgMC4wMTAwMDAgICAyLjIwMDAwMCAo ICAyLjIyNTk2NikKIyMgICAgIGNhbGxlZF9mcm9tKCkgICAgICAgICAgICAg ICAgICAgMC4xMDAwMDAgICAwLjAwMDAwMCAgIDAuMTAwMDAwICggIDAuMTAy ODEwKQojIyAgICAgY2FsbGVkX2Zyb20oKSAocmV0cmlldmUpICAgICAgICAw LjEwMDAwMCAgIDAuMDAwMDAwICAgMC4xMDAwMDAgKCAgMC4xMDIxMzMpCiMj CgpyZXF1aXJlICdiZW5jaG1hcmsnCgpkZWYgZjE7IGYyOyBlbmQKZGVmIGYy OyBmMzsgZW5kCmRlZiBmMzsgZjQ7IGVuZApkZWYgZjQ7IGY1OyBlbmQKZGVm IGY1OyBmNjsgZW5kCmRlZiBmNjsgZjc7IGVuZApkZWYgZjc7IGY4OyBlbmQK ZGVmIGY4OyBmOTsgZW5kCmRlZiBmOTsgZjEwOyBlbmQKCm4gPSAoJE4gfHwg MTAwMDAwKS50b19pCgpCZW5jaG1hcmsuYm0oMzApIGRvIHx4fAoKICAjIyBi ZW5jaG1hcmtzIGZvciBjYWxsZXIoKQoKICBkZWYgZjEwCiAgICBjYWxsZXIo KVswXQogIGVuZAoKICB4LnJlcG9ydCgiY2FsbGVyKClbMF0iKSBkbwogICAg bi50aW1lcyB7IGYxKCkgfQogIGVuZAoKICB4LnJlcG9ydCgiY2FsbGVyKClb MF0gKHJldHJpZXZlKSIpIGRvCiAgICBuLnRpbWVzIHsgZjEoKSA9fiAvOihc ZCspLzsgZm5hbWUgPSAkYDsgbG51bSA9ICQxLnRvX2kgfQogIGVuZAoKICAj IyBiZW5jaG1hcmtzIGZvciBjYWxsZWRfZnJvbSgpCgogIGRlZiBmMTAKICAg IGNhbGxlZF9mcm9tKCkKICBlbmQKCiAgeC5yZXBvcnQoImNhbGxlZF9mcm9t KCkiKSBkbwogICAgbi50aW1lcyB7IGYxKCkgfQogIGVuZAoKICB4LnJlcG9y dCgiY2FsbGVkX2Zyb20oKSAocmV0cmlldmUpIikgZG8KICAgIG4udGltZXMg eyBmbmFtZSwgbG51bSwgZnVuY19uYW1lID0gZjEoKTsgfQogIGVuZAoKZW5k Cg== --mimepart_4cae5bb5d684a_eedcc8fdc8184a1--