| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
| |
References f92ac24.
|
|\
| |
| |
| |
| | |
phiggins/remove-dynamic-send-on-built-in-callbacks
Reduce allocations when running AR callbacks.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Inspired by @tenderlove's work in
c363fff29f060e6a2effe1e4bb2c4dd4cd805d6e, this reduces the number of
strings allocated when running callbacks for ActiveRecord instances. I
measured that using this script:
```
require 'objspace'
require 'active_record'
require 'allocation_tracer'
ActiveRecord::Base.establish_connection adapter: "sqlite3",
database: ":memory:"
ActiveRecord::Base.connection.instance_eval do
create_table(:articles) { |t| t.string :name }
end
class Article < ActiveRecord::Base; end
a = Article.create name: "foo"
a = Article.find a.id
N = 10
result = ObjectSpace::AllocationTracer.trace do
N.times { Article.find a.id }
end
result.sort.each do |k,v|
p k => v
end
puts "total: #{result.values.map(&:first).inject(:+)}"
```
When I run this against master and this branch I get this output:
```
pete@balloon:~/projects/rails/activerecord$ git checkout master
M Gemfile
Switched to branch 'master'
pete@balloon:~/projects/rails/activerecord$ bundle exec ruby benchmark_allocation_with_callback_send.rb > allocations_before
pete@balloon:~/projects/rails/activerecord$ git checkout remove-dynamic-send-on-built-in-callbacks
M Gemfile
Switched to branch 'remove-dynamic-send-on-built-in-callbacks'
pete@balloon:~/projects/rails/activerecord$ bundle exec ruby benchmark_allocation_with_callback_send.rb > allocations_after
pete@balloon:~/projects/rails/activerecord$ diff allocations_before allocations_after
39d38
<
{["/home/pete/projects/rails/activesupport/lib/active_support/callbacks.rb",
81]=>[40, 0, 0, 0, 0, 0]}
42c41
< total: 630
---
> total: 590
```
In addition to this, there are two micro-optimizations present:
* Using `block.call if block` vs `yield if block_given?` when the block was being captured already.
```
pete@balloon:~/projects$ cat benchmark_block_call_vs_yield.rb
require 'benchmark/ips'
def block_capture_with_yield &block
yield if block_given?
end
def block_capture_with_call &block
block.call if block
end
def no_block_capture
yield if block_given?
end
Benchmark.ips do |b|
b.report("block_capture_with_yield") { block_capture_with_yield }
b.report("block_capture_with_call") { block_capture_with_call }
b.report("no_block_capture") { no_block_capture }
end
pete@balloon:~/projects$ ruby benchmark_block_call_vs_yield.rb
Calculating -------------------------------------
block_capture_with_yield
124979 i/100ms
block_capture_with_call
138340 i/100ms
no_block_capture 136827 i/100ms
-------------------------------------------------
block_capture_with_yield
5703108.9 (±2.4%) i/s - 28495212 in 4.999368s
block_capture_with_call
6840730.5 (±3.6%) i/s - 34169980 in 5.002649s
no_block_capture 5821141.4 (±2.8%) i/s - 29144151 in 5.010580s
```
* Defining and calling methods instead of using send.
```
pete@balloon:~/projects$ cat benchmark_method_call_vs_send.rb
require 'benchmark/ips'
class Foo
def tacos
nil
end
end
my_foo = Foo.new
Benchmark.ips do |b|
b.report('send') { my_foo.send('tacos') }
b.report('call') { my_foo.tacos }
end
pete@balloon:~/projects$ ruby benchmark_method_call_vs_send.rb
Calculating -------------------------------------
send 97736 i/100ms
call 151142 i/100ms
-------------------------------------------------
send 2683730.3 (±2.8%) i/s - 13487568 in 5.029763s
call 8005963.9 (±2.7%) i/s - 40052630 in 5.006604s
```
The result of this is making typical ActiveRecord operations slightly faster:
https://gist.github.com/phiggins/e46e51dcc7edb45b5f98
|
|/
|
|
|
|
| |
Hash#keys.each allocates an array of keys; Hash#each_key iterates through the
keys without allocating a new array. This is the reason why Hash#each_key
exists.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
* The assertions in AS::Duration don't actually assert.
* The assertion in Railtie will pass even when `eager_load_namespaces`
doesn't include `AppTemplate::Application` if `Rails.application` is
truthy.
For more details, see here:
* https://github.com/rails/rails/pull/16998
* https://github.com/rails/rails/pull/17000
|
|
|
|
|
| |
Nothing biggie. Skimmed through `ActiveSupport::Concern` docs these days
and this one comment seemed a bit off.
|
|
|
|
| |
Fixes #16956.
|
|\
| |
| | |
Grammar correction in ActiveSupport CHANGELOG [ci skip]
|
| | |
|
|\|
| |
| | |
[ci skip] ActiveSupport CHANGELOG fixes
|
| |
| |
| |
| |
| |
| |
| | |
1. spacing issues
2. spelling correction
3. grammar correction
4. Add missing docs
|
|\ \
| |/
|/|
| |
| |
| |
| |
| |
| | |
Added method `#eql?` to `ActiveSupport::Duration`, in addition to `#==`.
Conflicts:
activesupport/CHANGELOG.md
activesupport/lib/active_support/duration.rb
activesupport/test/core_ext/duration_test.rb
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Currently, the following returns `false`, contrary to expectation:
1.minute.eql?(1.minute)
Adding method `#eql?` will make this behave like expected. Method `#eql?` is
just a bit stricter than `#==`, as it checks whether the argument is also a
uration. Their parts may be different though.
1.minute.eql?(60.seconds) # => true
1.minute.eql?(60) # => false
|
| |
| |
| |
| |
| | |
Ruby 2.2 knows this, and no longer matches it with [[:space:]], so it's
not a good candidate for testing String#squish.
|
| | |
|
| |
| |
| |
| | |
Closes #16392.
|
| | |
|
| |
| |
| |
| |
| | |
Otherwise this will lead to another error later on
when generating a signature:
TypeError (no implicit conversion of nil into String).
|
| | |
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Goals:
1. Default to :random for newly generated applications
2. Default to :sorted for existing applications with a warning
3. Only show the warning once
4. Only show the warning if the app actually uses AS::TestCase
Fixes #16769
|
| |
| |
| |
| |
| |
| | |
Fixes #8015, #9756.
[Fred Wu & Matthew Draper]
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
https://github.com/rails/rails/commit/98b46bf5e201307cae56ee14bf41363a539779c5
did not properly handled out-of-range `:usec`s.
Passing a `:usec` that's out of range now throws an `ArgumentError` as it
should.
Fixes #16759.
|
| | |
|
| |
| |
| |
| |
| |
| |
| |
| |
| | |
We're seeing too many failures to believe otherwise.
This reverts commits bc116a55ca3dd9f63a1f1ca7ade3623885adcc57,
cbde413df3839e06dd14e3c220e9800af91e83ab,
bf0a67931dd8e58f6f878b9510ae818ae1f29a3a, and
2440933fe2c27b27bcafcd9019717800db2641aa.
|
|\ \
| | |
| | |
| | |
| | |
| | | |
tgxworld/dont_swallow_error_when_identifying_constant_from_test_name
Do not swallow exception on NameError within constant.
|
| | |
| | |
| | |
| | | |
Fixes https://github.com/rails/rails/issues/9933.
|
|/ / |
|
| |
| |
| |
| |
| |
| |
| |
| |
| | |
When we are loading a component and we want to know its version, we are
actually not speaking about the constant but the library itself.
[ci skip]
[Godfrey Chan & Xavier Noria]
|
| |
| |
| |
| | |
This was removed by mistake in 5e51bdd
|
| |
| |
| |
| |
| |
| | |
`try` allocates an array on every call, we should avoid calling it in
hotspots. This reduced AttributeMethodsTest#test_setting_time_zone_aware_attribute_with_string
from 18k allocations to 14k
|
| |
| |
| |
| | |
just needed some tenderloving instance_eval to fit the bill
|
| |
| |
| |
| | |
:trollface:
|
| | |
|
| | |
|
| | |
|
|\ \ |
|
| | |
| | |
| | |
| | | |
Otherwise, it's possible for GC to run in between, and fail the test.
|
| | | |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Since Rubinius is relying on #instance_of? for its definition of #eql?
(http://git.io/MtmbbA) but ActiveSupport::Duration should behave like
is_a? it returns true with `Fixnum`.
Thus, for the moment, the last assertion is failing so we have to skip
this test.
|
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
For the sake of backward-compatibility, we need to make #instance_of?
return true for Fixnum. On the other hand, the method should still
give true for ActiveSupport::Duration itself which was not the case
before.
|
| | | |
|
| |\ \
| | | |
| | | | |
Define the Duration#instance_of? method
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Since Duration is extending from ProxyObject which extends itself from
BasicObject, the Duration object doesn't respond to the #instance_of?
method. Thus, the #method_missing hook get triggered, delegating the
method to its `value` attribute.
However, Rubinius' #eql? definition relies on #instance_of?, thus this
will equal to true with a Fixnum (since its `value` attribute is a
Fixnum) while it should not.
The previous behavior was wrong anyway, no matter the implementation.
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Zero has one digit, but Math.log10(0) returns -Infinity. The method
needs to special-case zero.
The patch adds a regression test that is not clearly related to the
underlying issue because digit_count is private and has no coverage.
Gray area.
This bug was uncovered by 60062cf.
|
| |\ \ \
| | | | |
| | | | | |
Move as/test_test to as/test_case_test
|
| | | | | |
|
| | | | | |
|
| |/ / /
| | | |
| | | |
| | | |
| | | | |
Also moved comment for removal above `unless()` to not confuse RDoc with
the documentation for this method.
|
|/ / / |
|