From: richard.schneeman@... Date: 2015-07-23T18:45:23+00:00 Subject: [ruby-core:70103] [Ruby trunk - Feature #11375] Decreased Object Allocation in Pathname.rb Issue #11375 has been updated by Richard Schneeman. Thanks for reviewing! I added a new patch above: https://bugs.ruby-lang.org/attachments/download/5400/ruby-changes.patch You've mentioned the case statement optimization previously in a patch I sent to Rack. I agree that the difference is pretty negligible. Although I'm able to consistently see one running `benchmark/ips` ``` require 'benchmark/ips' STRING = "foo" Benchmark.ips do |x| x.report("freeze") { case STRING; when "foo".freeze; end } x.report("no-freeze") { case STRING; when "foo"; end } end ``` So i figured it was fine to leave it in. I'm not sure the best way to benchmak/compare this patch this to trunk. I wrote an artificial benchmark: https://gist.github.com/schneems/3f36765108a5a4d8cb00 ``` Calculating ------------------------------------- trunk 8.175k i/100ms patch 8.521k i/100ms ------------------------------------------------- trunk 89.772k (�� 9.6%) i/s - 449.625k patch 92.331k (��10.1%) i/s - 460.134k ``` I found the object allocations in Pathname with an experimental library I wrote https://github.com/schneems/let_it_go I was able to eliminate about 1k of object allocations per request in Rails using the same script: https://github.com/rails/rails/pull/20946. You're right about the overall performance gains. It's really hard to get consistent numbers of performance improvements with "".freeze. Currently I'm able to allocate 10,000 `"REQUEST_METHOD"` strings in a Rails app and hit it 1000 times. ``` user system total real 1000 requests184.870000 1.710000 186.580000 (192.105027) ``` When I try the same thing with frozen strings: ``` user system total real 1000 requests191.650000 1.810000 193.460000 (199.347186) ``` Which is ~7.2 seconds saved or 0.0072 seconds per request. While it does take a significant number of string allocations to have a large impact on performance I think this proposed patch to pathname.rb is minor enough that it is worth being applied. I'm happy to look into other ways to decrease memory use or increase speed. The speed impact depends entirely on how you're using the stdlib, so I think it should be as fast as possible while still maintaining readability and maintainability. I also found a few other places where strings could be optimized in stdlib, but wanted to submit a smaller diff first: ``` 56) /Users/richardschneeman/.rubies/ruby-2.2.2/lib/ruby/2.2.0/pathname.rb - 28) Array#fill on line 519 - 28) Array#include? on line 516 20) /Users/richardschneeman/.rubies/ruby-2.2.2/lib/ruby/2.2.0/ipaddr.rb - 5) String#split on line 561 - 5) String#split on line 562 - 5) String#count on line 552 - 4) String#split on line 480 - 1) String#split on line 480 4) /Users/richardschneeman/.rubies/ruby-2.2.2/lib/ruby/2.2.0/base64.rb - 2) String#unpack on line 73 - 1) String#unpack on line 73 - 1) String#unpack on line 73 3) /Users/richardschneeman/.rubies/ruby-2.2.2/lib/ruby/2.2.0/psych/scalar_scanner.rb - 3) String#gsub on line 105 2) /Users/richardschneeman/.rubies/ruby-2.2.2/lib/ruby/2.2.0/securerandom.rb - 1) String#unpack on line 173 - 1) String#unpack on line 288 ``` I would appreciate any comments on https://github.com/schneems/let_it_go if you have any. I looked over your proposed patch. I'm still very junior when it comes to Ruby C internal changes, and I wasn't 100% able to follow, the patch is quite large. I'm interested in going deeper down that rabbit hole, but right now I don't feel qualified to comment on it directly. Thanks for your work in this area, I imagine that took quite a bit of time. I am curious in general how other languages deal with this issue. It looks like Java http://java-performance.info/java-string-deduplication/ allocates every string literal as a frozen string and then unfreezes when someone tries to modify it. Like a CoW string pool? ---------------------------------------- Feature #11375: Decreased Object Allocation in Pathname.rb https://bugs.ruby-lang.org/issues/11375#change-53531 * Author: Richard Schneeman * Status: Open * Priority: Normal * Assignee: ---------------------------------------- Pathname.rb has many string literals that are not mutated while being called. We can reduce object allocation and increase program speed by freezing these string literals. I've attached a patch that adds `.freeze` to all non-mutated string literals in `ext/pathname/lib/pathname.rb`. Tests on `test/pathname/test_pathname.rb` pass ---Files-------------------------------- ruby-changes.patch (6.42 KB) -- https://bugs.ruby-lang.org/