Feature #5767

Cache expanded_load_path to reduce startup time

Added by Yura Sokolov over 2 years ago. Updated over 1 year ago.

[ruby-core:41672]
Status:Closed
Priority:Normal
Assignee:Nobuyoshi Nakada
Category:-
Target version:-

Description

This patch add caching of expanded load path.
It reduces rails startup time by 33%
(patch against 1.9.3-p0 and simple performance test is here https://gist.github.com/1480404 )

cache_expanded_load_path.patch Magnifier (5.67 KB) Yura Sokolov, 12/15/2011 06:18 PM

cache_expanded_load_path.patch Magnifier - more atomic access to cache (6.88 KB) Yura Sokolov, 12/16/2011 04:10 PM

find_file_safe_and_cache.patch Magnifier - make find_file_safe and find_file_ext_safe concerning about cache (5.34 KB) Yura Sokolov, 12/17/2011 09:07 PM

cache_expanded_load_path.patch Magnifier - final version, `rb_find_file_safe` included, tests fixed. (14.4 KB) Yura Sokolov, 12/19/2011 04:07 AM

cache_expanded_load_path.patch Magnifier - refactor methods a bit. (15.4 KB) Yura Sokolov, 12/19/2011 03:57 PM

History

#1 Updated by Nikolai Weibull over 2 years ago

On Thu, Dec 15, 2011 at 10:18, Yura Sokolov funny.falcon@gmail.com wrote:

Issue #5767 has been reported by Yura Sokolov.


Feature #5767: Cache expandedloadpath to reduce startup time
http://redmine.ruby-lang.org/issues/5767

Author: Yura Sokolov
Status: Open
Priority: Normal
Assignee:
Category:
Target version:

This patch add caching of expanded load path.
It reduces rails startup time by 33%
(patch against 1.9.3-p0 and simple performance test is here https://gist.github.com/1480404 )

Is it only me, or is treating $LOADPATH like an array hurting
possible optimizations? I mean, how sane is it to allow
$LOAD
PATH.map!{ … }?

#2 Updated by Shyouhei Urabe over 2 years ago

Nikolai Weibull wrote:

On Thu, Dec 15, 2011 at 10:18, Yura Sokolov funny.falcon@gmail.com wrote:

Issue #5767 has been reported by Yura Sokolov.


Feature #5767: Cache expandedloadpath to reduce startup time
http://redmine.ruby-lang.org/issues/5767

Author: Yura Sokolov
Status: Open
Priority: Normal
Assignee:
Category:
Target version:

This patch add caching of expanded load path.
It reduces rails startup time by 33%
(patch against 1.9.3-p0 and simple performance test is here https://gist.github.com/1480404 )

Is it only me, or is treating $LOADPATH like an array hurting
possible optimizations? I mean, how sane is it to allow
$LOAD
PATH.map!{ … }?

$LOAD_PATH determines the order to search required files. At least it must be ordered linearly.

#3 Updated by Yura Sokolov over 2 years ago

Nikolai Weibull wrote:

Is it only me, or is treating $LOADPATH like an array hurting
possible optimizations? I mean, how sane is it to allow
$LOAD
PATH.map!{ … }?

I think, you right. $LOADPATH and $LOADEDFEATURES should be restricted.
But currently they not.
When I trying to improve $LOADED_FEATURES at #5427, I remove dangerous methods.

In this patch, it just invalidates cache when complex self modifying method is called,
and keeps cache valid in case of simple methods, like push, pop, <<

#4 Updated by Yura Sokolov over 2 years ago

Cosmetic update to patch: more atomic cache access.

#6 Updated by Yura Sokolov over 2 years ago

There is report about 47% startup time reduction https://gist.github.com/1480404#gistcomment-69769

#7 Updated by Luis Lavena over 2 years ago

For those interested here are some raw performance numbers and comparison between default (no patch) and other patches combined:

https://gist.github.com/1490555

#10 Updated by Yura Sokolov over 2 years ago

I removed messing with file.c.
Instead rbgetload_path returns expanded paths when optimization is enabled.

I have updated pull request, so that it contains one commit.

https://github.com/ruby/ruby/pull/68.patch
https://github.com/ruby/ruby/pull/68

#11 Updated by Yura Sokolov about 2 years ago

https://gist.github.com/1688857

Most of success of that gist is cause of this issue.
Cites from comments:

Thanks for sharing that. Indeed the speed increase is quite impressive! I've tested the time it take to run some rspec test before and after. Here are the results:

Before: Finished in 402.79 seconds (3521 examples, 3 failures, 39 pending)
After: Finished in 222,82 seconds (3521 examples, 3 failures, 39 pending). WOOW!


Obligatory benchmarks:

Test Suite on 1.9.3-p0 proper : 2m06s
Rails boot time : 9.1s

Suite on 1.9.3-p0-perf : 1m32s
Rails boot time : 6.5s

Not bad.


$ time rake

before:
real 0m37.919s
user 0m6.474s
sys 0m0.919s

after:
real 0m34.236s
user 0m3.367s
sys 0m0.848s

$ time rails runner "Time.now"

before:
real 0m4.589s
user 0m3.871s
sys 0m0.629s

after:
real 0m2.437s
user 0m1.889s
sys 0m0.534s


5.5 secs instead of 8.8 secs for rails runner "puts \"omfg\""
rspec . 15.1 seconds instead of 18.2 seconds


One of my Rails apps, boot time (measured with ./bin/rails runner 'puts 3'

1.9.3-perf:  5.1 seconds
1.9.3-p0:    8.1 seconds
1.9.2-p290: 18.2 seconds

My rake parallel:spec went down from 68 to 38sec!!!!!!!!!! That's 44% cut off! Fantastic! THANK YOU!


API spec tests ~30% faster!


time bundle exec rake environment

Before:
14.60s user 1.26s system 100% cpu 15.861 total

After:
5.11s user 1.10s system 99% cpu 6.212 total

60.8% speedup!!!!!!


#12 Updated by Yusuke Endoh about 2 years ago

  • Status changed from Open to Assigned
  • Assignee set to Nobuyoshi Nakada

Sorry I don't catch up the discussion.

What's the status?
The proposal is COMPLETELY compatible?
It may be helpful for me to create a short summary of the proposal and discussion.

I tentatively assign this to nobu.
Any other committer is interested in this issue?

Yusuke Endoh mame@tsg.ne.jp

#13 Updated by Yura Sokolov about 2 years ago

The proposal is COMPLETELY compatible?

This proposal is completely compatible, since LOAD_PATH remains the same array, methods are overridden only to keep cache in sync.

Proposal is about keeping result of expanding LOADPATH entries in a 'invisible' cache.
This cache is lazy invalidated on changing directory and filesystem encoding, so that
the whole semantic of LOAD
PATH remains the same.
Methods of LOADPATH overridden to keep cache in sync, so that there is no need to expand
all paths again if entries were only appended to any side of LOAD
PATH, or removed from any side.

It saves up to 35% of big application's startup time and still brings slight improvement
for small scripts.

(Only Jeremy Evan's sequel use self crafted super fast load system which does not gain improvement from this patch)

I didn't check it against current trunk, but believe there could not be big problems.

There is still small room for improvement this patch: make chached expanded paths class to be
subclass of String, and then test against it in a fileexpandpath, so that to not expand it
twice in calls from rbfindfileextsafe and rbfindfile_safe.

Yura aka funny_falcon

#14 Updated by Thomas Sawyer about 2 years ago

Does this have any effect on https://bugs.ruby-lang.org/issues/4969 (scroll down to post #7).

#15 Updated by Yura Sokolov about 2 years ago

Does this have any effect on https://bugs.ruby-lang.org/issues/4969 (scroll down to post #7).

Thomas Sawyer, this proposal has no any effect on #4969 because it doesn't change require semantic
in any way. It only improve performance.

I leave my comment at #4969 and I still take that point: #4969 is about making game more tangled but easier to win instead of playing by the rules, imho.

#16 Updated by Hiroshi Shirosaki over 1 year ago

  • Status changed from Assigned to Closed

Fixed by #7158.

Also available in: Atom PDF