load

initialize

A quick look at load.setup shows us that the load method takes a small amount of time 0.0016739999991841614s. This means the bulk of the time is spent in setup.

setup

This method took about 0.6628200000268407s to run.

diagram image

As we can see, specs = groups.any? ? @definition.specs_for(groups) : requested_specs takes the most time (about 85% of the time).

Let’s break that down a bit. I’ll just change the turnary to an if/else and see what that produces.

diagram image

As we can see, @definition.specs_for(groups) is not even called. All the time is spent in requested_specs.

requested_specs

It seems this delegates to definition.

In definition, this is the result:

diagram image

Let’s look at specs_for

specs_for

diagram image

specs.for(expand_dependencies(deps)) takes the most time, but is it the specs.for part, or the expand_dependencies part?

It is the specs.for part:

diagram image

specs.for

diagram image

specs

diagram image

As we can see, about 3/4 of the time is spent making the specs, and 1/4 of the time processing with for.

specs

diagram image

This line does quite a lot (resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : requested_dependencies)), so let’s split it up.

diagram image

As we can see, resolve and materialize take the most time.


Materializing

line num_calls time (s)
resolve 73 0.05524000007426366
materialize 1 0.1665900000371039
materialize 374 0.15040999941993505
specs 374 0.13627100008307025
rubygems spec 296 0.03416500013554469
git specs 293 0.09133500000461936
search 596 0.012452999944798648

diagram image

git-based specs

diagram image

We can see that we load 82 gemspecs - which takes the most time. Can we cache loading those gemspecs? They aren’t going to change in between loads.

Globbing the filesystem also takes a chunk of time (Dir['#{expanded_path}/#{@glob}'].sort_by {|p| -p.split(File::SEPARATOR).size }) - about 15% of 91ms to be exact.

load_gemspec

diagram image

load_gemspec_uncached

diagram image