Commit Graph

5431 Commits

Author SHA1 Message Date
yui-knk
0c34773bf5
Use original Array#sum to speed up calculating
Use original `Array#sum` when calculating Numeric sum.
This commit is related #24804 issue.
Issue #24804 reports `Array#sum` becomes much slower when
ActiveSupport is included.

This commit tries to use original method as far as possible.

```shell

$ cat array_sum.rb
class Array
  alias core_sum sum
end

require 'benchmark/ips'
require 'active_support/core_ext/enumerable'

ary = [1.0] * 1_000_000

Benchmark.ips do |x|
  x.report("core sum") { ary.core_sum }
  x.report("AS's sum") { ary.sum }

   x.compare!
end

$ bundle exec ruby -v -I lib array_sum.rb
ruby 2.4.0dev (2016-05-01 master 54867) [x86_64-darwin14]
Calculating -------------------------------------
            core sum     4.000  i/100ms
            AS's sum     5.000  i/100ms
-------------------------------------------------
            core sum     50.492  (± 7.9%) i/s -    252.000
            AS's sum     50.116  (± 6.0%) i/s -    250.000

Comparison:
            core sum:       50.5 i/s
            AS's sum:       50.1 i/s - 1.01x slower
```

Signed-off-by: Jeremy Daer <jeremydaer@gmail.com>
2016-05-07 21:57:00 -07:00
Rafael Mendonça França
fbdcf5221a Preparing for 5.0.0.rc1 release 2016-05-06 16:54:40 -05:00
lvl0nax
9262e493d5 Array#split refactoring for case with block
Calculating -------------------------------------
              before    26.319k i/100ms
               after    29.414k i/100ms
-------------------------------------------------
              before    350.623k (± 1.6%) i/s -      1.763M
               after    416.227k (± 1.4%) i/s -      2.088M

Comparison:
               after:   416226.8 i/s
              before:   350622.8 i/s - 1.19x slower
2016-05-06 19:15:51 +03:00
Kenta Murata
a678c47f6d
Fix initial value effects for sum along to ruby 2.4
Signed-off-by: Jeremy Daer <jeremydaer@gmail.com>
2016-04-30 18:33:39 -07:00
Xavier Noria
bbb84a1721 restores the regexp used in String#blank?
This commit undoes 54243fe.

Reason: Further investigation has shown the benefit is not so clear
generally speaking.

There is a long discussion and several benchmarks in the PR #24658
if you are interested in the details.
2016-04-29 23:01:58 +02:00
Vijay Dev
9d1bf059c0 Merge branch 'master' of github.com:rails/docrails
Conflicts:
	guides/source/configuring.md
2016-04-29 16:00:15 +00:00
Andrey Novikov
434df0016e
Change 1.week to create 1 week durations instead of 7 days durations.
This is just to remove astonishment from getting `3600 seconds` from typing `1.hour`.
2016-04-28 03:45:05 +03:00
eileencodes
f7a986012a Prep Rails 5 beta 4 2016-04-27 15:48:47 -05:00
Jeremy Daer
c1ad19c92f
Revert "Change 1.week to create 1 week durations instead of 7 days durations."
Regression: adding minutes/hours to a time would change its time zone

This reverts commit 1bf9fe75a6473cb7501cae544cab772713e68cef.
2016-04-27 14:36:22 -05:00
Jeremy Daer
f03c27cad2
Merge pull request #24723 from lvl0nax/array_split_fix
Little perfomance fix for Array#split.
2016-04-26 11:41:16 -05:00
lvl0nax
ffb1df52c1 Little perfomance fix for Array#split.
Calculating -------------------------------------
before    40.770k i/100ms
after    58.464k i/100ms
-------------------------------------------------
before    629.568k (± 5.0%) i/s -      3.180M
after      1.159M (± 4.5%) i/s -      5.788M
2016-04-26 09:21:56 +03:00
Alexey Shein
420730b10b
Do not cache ActiveSupport::TimeZone#utc_offset
This can be an issue when TZInfo::TimeZone#current_period is refreshed
due to timezone period transition, but it's not reflected in
ActiveSupport::TimeZone object.

For example, on Sun, 26 Oct 2014 22:00 UTC, Moscow changed its TZ from
MSK +04:00 to MSK +03:00 (-1 hour). If ActiveSupport::TimeZone['Moscow']
happens to be initialized just before the timezone transition, it will
cache its stale utc_offset even after the timezone transition.

This commit removes cache and fixes this issue.

Signed-off-by: Jeremy Daer <jeremydaer@gmail.com>
2016-04-25 20:55:33 -05:00
Jason Frey
de601699ba Add require of mattr_accessor since Compatibility relies on it.
Follow up to
c9c5788a52
2016-04-25 12:39:12 -04:00
yui-knk
cd9d5c1150
Remove Array#sum method before override it
To suppress warning ('warning: method redefined; discarding old sum')
remove the method before override it.

Signed-off-by: Jeremy Daer <jeremydaer@gmail.com>
2016-04-24 22:05:24 -05:00
Xavier Noria
7463aa19b1 rewords code comment [ci skip]
This alternative flows better.

[Richard Schneeman & Xavier Noria]
2016-04-24 21:18:21 +02:00
Jeremy Daer
65b6496ee4
Share lock: more accurate livelock fix for aa598f4
Awaken waiting threads even if the current thread (the previously
exclusive thread) hadn't taken a share lock.

This only happens in code that wasn't run within an executor, since that
always take an outermost share lock.
2016-04-24 10:14:53 -07:00
Jeremy Daer
aa598f4f39
Share lock: avoid livelock due to exclusive thread sleeping before waiting threads wake 2016-04-23 15:19:25 -07:00
Vipul A M
abeabdbc88 Follow up of c9c5788a52
[ci skip]
2016-04-24 01:18:15 +05:30
Andrew White
ee5e476aad Make getlocal and getutc always return instances of Time
Previously these methods could return either a DateTime or a Time
depending on how the ActiveSupport::TimeWithZone instance had
been constructed. Changing to always return an instance of Time
eliminates a possible stack level too deep error in to_time where
it was wrapping a DateTime instance.

As a consequence of this the internal time value is now always an
instance of Time in the UTC timezone, whether that's as the UTC
time directly or a representation of the local time in the timezone.

There should be no consequences of this internal change and if
there are it's a bug due to leaky abstractions.
2016-04-23 19:34:54 +01:00
Andrew White
a424bbb242 Add DateTime#subsec
Mirrors the Time#subsec method by returning the fraction
of the second as a Rational.
2016-04-23 19:18:38 +01:00
Andrew White
88d844b278 Change Time#sec_fraction to use subsec
Time instances can have fractional parts smaller than a nanosecond.
2016-04-23 19:11:34 +01:00
Andrew White
dbc7a7cb50 Add additional aliases for DateTime#utc 2016-04-23 18:01:38 +01:00
Andrew White
7fb2a63708 Add Time#sec_fraction
Mirrors the DateTime#sec_fraction method by returning the fraction
of the second as a Rational.
2016-04-23 17:15:26 +01:00
yui-knk
941eee5c8e Move DateTime#getlocal to /core_ext/date_time/calculations.rb
`DateTime#getlocal` is newly added public API.
It's responsible is same as `DateTime#utc`, so `calculations.rb` is
a best plase to define this method.
For keeping consistency with `DateTime#utc`, defines `#localtime` and
defines `getlocal` as an alias method.
2016-04-23 23:51:49 +09:00
Andrew White
c9c5788a52 Add compatibility for Ruby 2.4 to_time changes
In Ruby 2.4 the `to_time` method for both `DateTime` and `Time` will
preserve the timezone of the receiver when converting to an instance
of `Time`. Since Rails 5.0 will support Ruby 2.2, 2.3 and later we
need to introduce a compatibility layer so that apps that upgrade do
not break. New apps will have a config initializer file that defaults
to match the new Ruby 2.4 behavior going forward.

For information about the changes to Ruby see:
https://bugs.ruby-lang.org/issues/12189
https://bugs.ruby-lang.org/issues/12271

Fixes #24617.
2016-04-23 15:03:50 +01:00
Aaron Patterson
4a06cc9edd
fix boot performance issue
Slight refactor to improve boot performance on some Ruby
implementations (for now).
2016-04-22 09:17:05 -07:00
Xavier Noria
9311afcbe8 just say nothing about why this regexp is slower [ci skip]
Further investigation seems to disprove that backtracking is the
reason why the positive variant is slower, see

    https://github.com/rails/rails/pull/24658#issuecomment-213079710

so, just say nothing about it, only assert it is slower.
2016-04-21 21:59:50 +02:00
Xavier Noria
0f8eefa6a5 restores code comments in String#blank? [ci skip]
When you come here without context, it is important to hightlight that
checking the predicate is worthwhile due to the observation that blank
strings are often empty. So you complicate the code (which has a cost
in terms of readability and aesthetics), but statistically makes sense.

Then, you also need to explain why the second operand is so convoluted.

Otherwise, you wonder why this line is written precisely this way. That
is what code comments are for.
2016-04-21 09:25:38 +02:00
Jeremy Daer
fe9e9f4390
Merge pull request #24663 from kamipo/remove_unused_blank_re
Remove unused `BLANK_RE`
2016-04-20 23:05:50 -07:00
Todd Lynam
406047d3ac Update delegate to use newer Ruby syntax
This commit updates `delegate` to use the keyword argument syntax added in Ruby 2. I left the `ArgumentError` when `to` is missing, because it better explains how to correctly use `delegate`.  We could instead rely on the default `ArgumentError` that would be raised if `to` were a required keyword argument.
2016-04-20 18:35:43 -07:00
Ryuta Kamizono
c7617c715a Remove unused BLANK_RE
Follow up to #24658.
2016-04-21 09:22:27 +09:00
schneems
54243fecfc Speed up String#blank? Regex
Follow up on 697384df36 (commitcomment-17184696).

The regex to detect a blank string `/\A[[:space:]]*\z/` will loop through every character in the string to ensure that all of them are a `:space:` type. We can invert this logic and instead look for any non-`:space:` characters. When that happens, we would return on the first character found and the regex engine does not need to keep looking.

Thanks @nellshamrell for the regex talk at LSRC.

By defining a "blank" string as any string that does not have a non-whitespace character (yes, double negative) we can get a substantial speed bump.

Also an inline regex is (barely) faster than a regex in a constant, since it skips the constant lookup. A regex literal is frozen by default.

```ruby
require 'benchmark/ips'

def string_generate
  str = " abcdefghijklmnopqrstuvwxyz\t".freeze
  str[rand(0..(str.length - 1))] * rand(0..23)
end

strings = 100.times.map { string_generate }

ALL_WHITESPACE_STAR = /\A[[:space:]]*\z/

Benchmark.ips do |x|
  x.report('current regex            ') { strings.each {|str| str.empty? || ALL_WHITESPACE_STAR === str } }
  x.report('+ instead of *           ') { strings.each {|str| str.empty? || /\A[[:space:]]+\z/ === str } }
  x.report('not a non-whitespace char') { strings.each {|str| str.empty? || !(/[[:^space:]]/ === str) } }
  x.compare!
end

# Warming up --------------------------------------
# current regex
#                          1.744k i/100ms
# not a non-whitespace char
#                          2.264k i/100ms
# Calculating -------------------------------------
# current regex
#                          18.078k (± 8.9%) i/s -     90.688k
# not a non-whitespace char
#                          23.580k (± 7.1%) i/s -    117.728k

# Comparison:
# not a non-whitespace char:    23580.3 i/s
# current regex            :    18078.2 i/s - 1.30x slower
```

This makes the method roughly 30% faster `(23.580 - 18.078)/18.078 * 100`.

cc/ @fxn
2016-04-20 15:39:45 -05:00
Xavier Noria
697384df36 ~3.5x speedup of String#blank? for empty strings
See the rationale in the comment in this patch.

To benchmark this I ran a number of variations, ultimately narrowing to

    require 'benchmark/ips'

    str = ''
    regexp = /\A[[:space:]]*\z/

    Benchmark.ips do |x|
      x.report('regexp') { regexp === str }
      x.report('empty')  { str.empty? || regexp === str }
      x.compare!
    end

This benchmark has consistently reported speedups around 3.5x:

    Calculating -------------------------------------
                  regexp    69.197k i/100ms
                   empty   115.468k i/100ms
    -------------------------------------------------
                  regexp      2. 6.3%) i/s -     13.839M
                   empty      9. 8.8%) i/s -     47.804M

    Comparison:
                   empty:  9642607.6 i/s
                  regexp:  2768351.9 i/s - 3.48x slower

Sometimes even reaching 4x.

Running the same bechmark on strings of 10 or 100 characters (with
whitespace or present) has shown a slowdown of just about 1.01/1.02.
Marginal, we seem to have a worthwhile trade-off here.
2016-04-20 16:28:54 +02:00
yui-knk
2ef7741305 [ci skip] Aline results of code examples in comments 2016-04-20 10:15:51 +09:00
Andrey Novikov
318ee54130
Add ActiveSupport::TimeZone.country_zones helper
That helper will return time zones for any country that tzdata knows about.
So it will be much simpler for non-US people to list own country time zones
in HTML selects or anywhere.
2016-04-19 21:53:04 +03:00
Justin
b00c69cd1f Change the Hash.to_xml with a lamda example
Update 'foo'.to_xml(lambda { |options, key| options[:builder].b(key) })
to  {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml
2016-04-19 09:49:55 -03:00
Jeremy Daer
1f190c4873
Ruby 2.4 Array#sum: fix non-numeric #sum feature detection 2016-04-19 00:53:37 -07:00
Jeremy Daer
4d635bd6e8
Merge pull request #24552 from yui-knk/raise_argument_error
Raise `ArgumentError` when an invalid form is passed to `Date#to_time`
2016-04-19 00:45:30 -07:00
Jeremy Daer
7ad4690b21
Ruby 2.4: compat with new Array#sum
Ruby 2.4 introduces `Array#sum`, but it only supports numeric elements,
breaking our `Enumerable#sum` which supports arbitrary `Object#+`.
To fix, override `Array#sum` with our compatible implementation.

Native Ruby 2.4:

    %w[ a b ].sum
    # => TypeError: String can't be coerced into Fixnum

With `Enumerable#sum` shim:

    %w[ a b ].sum
    # => 'ab'

We tried shimming the fast path and falling back to the compatible path
if it fails, but that ends up slower even in simple causes due to the cost
of exception handling. Our only choice is to override the native `Array#sum`
with our `Enumerable#sum`.
2016-04-18 22:53:20 -07:00
Arnau Siches, Andrey Novikov
04c512da12
ActiveSupport::Duration supports ISO8601 formatting and parsing.
```ruby
ActiveSupport::Duration.parse('P3Y6M4DT12H30M5S')

(3.years + 3.days).iso8601
```

Inspired by Arnau Siches' [ISO8601 gem](https://github.com/arnau/ISO8601/)
and rewritten by Andrey Novikov with suggestions from Andrew White. Test
data from the ISO8601 gem redistributed under MIT license.

(Will be used to support the PostgreSQL interval data type.)
2016-04-18 16:27:30 -07:00
Jeremy Daer
b39131e8bd
Merge pull request #24577 from mechanicles/fix-fetch-cache-miss
Fix forced cache miss for fetch when called without a block.
2016-04-18 08:35:55 -07:00
Santosh Wadghule
a712acc425 Fix forced cache miss for fetch.
- Raised an argument error if no block is passed to #fetch with
'force: true' option is set.
- Added tests for the same.
2016-04-18 20:25:16 +05:30
Xavier Noria
7d0982e729 Merge pull request #24587 from mechanicles/doc-consistency
Document consistency [ci skip]
2016-04-18 02:34:14 -07:00
Andrey Novikov
1bf9fe75a6
Change 1.week to create 1 week durations instead of 7 days durations.
This is just to remove astonishment from getting `3600 seconds` from typing `1.hour`.
2016-04-18 08:33:40 +03:00
Rafael França
847084e046 Merge pull request #24595 from maclover7/jm-cleanup-2
Specify that behavior will be deprecated in Rails 5.1
2016-04-17 19:25:51 -03:00
Jon Moss
bca2e69b78 Specify that behavior will be deprecated in Rails 5.1 2016-04-17 15:04:10 -04:00
Santosh Wadghule
46269effc3 Document consistency [ci skip] 2016-04-17 16:48:00 +05:30
Vipul A M
58fc343eaa Stop passing unused payloads to instrumentation block in cache 2016-04-17 11:23:30 +05:30
yui-knk
29e876f775 Raise ArgumentError when an invalid form is passed to Date#to_time
Before this commit
`NoMethodError: undefined method `form_name' for Time:Class` is raised
when an invalid argument is passed.
It is better to raise `ArgumentError` and show list of valid arguments
to developers.
2016-04-17 08:23:20 +09:00
Sean Griffin
b0d7ac0ff7 Merge pull request #24517 from estolfo/transform-keys-return-type-master
Restore Hash#transform_keys behavior to always return a Hash instance
2016-04-15 09:25:02 -06:00