rails/rails — pull request #12976 by tmm1 (2013-11-21 00:26:17+00:00)
Title: Faster String#blank?

Our rails app spends 2-3% of production cpu time in this method:

```
$ stackprof data/stackprof-cpu-3975-1384979644.dump --method "String#blank?"
String#blank? (ruby/2.1.0/gems/activesupport-2.3.14.github30/lib/active_support/core_ext/object/blank.rb:80)
samples: 305 self (2.9%) / 317 total (3.0%)
callers:
158 ( 49.8%) Object#present?
24 ( 7.6%) ActionController::Response#content_type
24 ( 7.6%) block in ActiveRecord::Base.merge_conditions
22 ( 6.9%) UrlHelper#escape_url_path
16 ( 5.0%) ActionView::Helpers::AssetTagHelper#compute_public_path
9 ( 2.8%) ActiveRecord::Base.sanitize_sql_for_conditions
8 ( 2.5%) ActionController::Response#nonempty_ok_response?
6 ( 1.9%) ActiveRecord::Base.add_conditions!
callees (12 total):
12 ( 100.0%) String#encoding_aware?
code:
| 80 | def blank?
67 (0.6%) / 67 (0.6%) | 81 | return true if empty?
| 82 |
| 83 | # 1.8 does not takes [:space:] properly
16 (0.1%) / 4 (0.0%) | 84 | if encoding_aware?
232 (2.2%) / 232 (2.2%) | 85 | self !~ /[^[:space:]]/
| 86 | else
2 (0.0%) / 2 (0.0%) | 87 | self !~ NON_WHITESPACE_REGEXP
| 88 | end
```

This pull request optimizes the regex in this method slightly by removing the double negative.

``` ruby
require 'benchmark'

iterations = 500_000
strings = ['', ' ', ' ', ' ', ' ', 'test']

Benchmark.bmbm(40) do |b|
b.report('str !~ /[^[:space:]]/') do
iterations.times{ strings.each{ |str| str !~ /[^[:space:]]/ } }
end
b.report('!!(str =~ /[^[:space:]]/)') do
iterations.times{ strings.each{ |str| !!(str =~ /[^[:space:]]/) } }
end
b.report('str =~ /\A[[:space:]]*\z/') do
iterations.times{ strings.each{ |str| str =~ /\A[[:space:]]*\z/ } }
end
b.report('str =~ /\A\s*\z/') do
iterations.times{ strings.each{ |str| str =~ /\A\s*\z/ } }
end
b.report('str.empty? || str == " " || str =~ /\A\s*\z/') do
iterations.times{ strings.each{ |str| str.empty? || str == " " || str =~ /\A\s*\z/ } }
end
end

__END__

Rehearsal --------------------------------------------------------------------------------
str !~ /[^[:space:]]/ 3.340000 0.010000 3.350000 ( 3.349366)
!!(str =~ /[^[:space:]]/) 2.610000 0.000000 2.610000 ( 2.614685)
str =~ /\A[[:space:]]*\z/ 2.470000 0.000000 2.470000 ( 2.483112)
str =~ /\A\s*\z/ 2.520000 0.010000 2.530000 ( 2.523422)
str.empty? || str == " " || str =~ /\A\s*\z/ 2.690000 0.000000 2.690000 ( 2.701668)
---------------------------------------------------------------------- total: 13.650000sec

user system total real
str !~ /[^[:space:]]/ 3.360000 0.000000 3.360000 ( 3.376225)
!!(str =~ /[^[:space:]]/) 2.580000 0.010000 2.590000 ( 2.592369)
str =~ /\A[[:space:]]*\z/ 2.480000 0.000000 2.480000 ( 2.482733)
str =~ /\A\s*\z/ 2.420000 0.000000 2.420000 ( 2.419532)
str.empty? || str == " " || str =~ /\A\s*\z/ 2.680000 0.010000 2.690000 ( 2.684017)
```