Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Short circuit entry check #331

Merged
merged 1 commit into from
Jun 29, 2016
Merged

Conversation

schneems
Copy link
Member

The method match_path_extname is expensive. We know that if the name of the file on disk does not start with the same basename that we're looking for then it won't matter what extensions it's got. This check is pretty fast.

On the example app

https://github.com/nfm/sprockets-3.x-performance-regressions

It reduced asset lookup from 15 seconds to 2.6 seconds. It's still not perfect but it's a 400% + speed increase in the case of looking for an asset in a huge directory.

Related comment #84 (comment)

@schneems
Copy link
Member Author

Turns out it's perhaps faster, but not by 400% made a mistake while benchmarking.

The method `match_path_extname` is expensive. We know that if the name of the file on disk does not start with the same basename that we're looking for then it won't matter what extensions it's got. This check is pretty fast.

On the example app

https://github.com/nfm/sprockets-3.x-performance-regressions

It reduced asset lookup from 15 seconds to 2.6 seconds. It's still not perfect but it's a 400% + speed increase in the case of looking for an asset in a huge directory.

Related comment #84 (comment)
@schneems schneems force-pushed the schneems/short-circuit-entry-check branch from dbe9794 to fb35173 Compare June 28, 2016 17:44
@schneems
Copy link
Member Author

With this PR

2.3.1  ~/documents/projects/tmp/sprockets-3.x-performance-regressions (master)
$ be rake sprockets:benchmark
Running benchmark...
1500 lookups of the same asset took 6.550976
1500 lookups of 1500 different assets took 3.683133

Without this PR

2.3.1  ~/documents/projects/tmp/sprockets-3.x-performance-regressions (3.x)
$ be rake sprockets:benchmark
1500 lookups of the same asset took 18.598093
1500 lookups of 1500 different assets took 19.256265

Versus Sprockets 2.x

$ be rake sprockets:benchmark
Running benchmark...
1500 lookups of the same asset took 0.183741
1500 lookups of 1500 different assets took 9.033849

@schneems
Copy link
Member Author

Note that I removed the rake asset:precompile step of the rake task as that gives an unrealistic result for development for the 2.x case since the presence of a manifest file short circuits the pipeline and it turns into a giant has lookup.

schneems added a commit that referenced this pull request Jun 28, 2016
Instead of iterating every entry in a given path, we only pass in valid mime types and explicitly check for basenames that match the extensions we are looking for (when extensions are sufficiently small). 

For example if we are looking for `foo` with mime of `image/png` instead of looking at EVERY entry in the directory instead we will explicitly look for:

- foo.png

This only works for mime types that have few extensions. It does not scale well for mime types like javascript that would require many many file touches (.coffee, .coffee.erb, .js, .js.erb, .eco, .eco.erb, etc.) even though there may only be a few entries in the directory. When confronted with many extensions (using magic number 3) we go back to the old method of looping through all entries in the directory.

This PR makes searching for files with no transforms very fast. For example images in large directories will be much faster as they will only require one lookup instead of looping through all entries.

Using the same script from #331

```
$ be rake sprockets:benchmark
Running benchmark...
1500 lookups of the same asset took 2.927082
1500 lookups of 1500 different assets took 1.838495
```

Which is a substantial speedup.

In the future if we could imply the user's preferred extension i.e if a user uses `.coffee.erb` for all JS files and never uses `.eco.js` then we could make this even faster. We could record the file extensions that are used when running in the cache, prefer those when available, when not available fall back to this logic and record the file extension.
schneems added a commit that referenced this pull request Jun 28, 2016
Instead of iterating every entry in a given path, we only pass in valid mime types and explicitly check for basenames that match the extensions we are looking for (when extensions are sufficiently small). 

For example if we are looking for `foo` with mime of `image/png` instead of looking at EVERY entry in the directory instead we will explicitly look for:

- foo.png

This only works for mime types that have few extensions. It does not scale well for mime types like javascript that would require many many file touches (.coffee, .coffee.erb, .js, .js.erb, .eco, .eco.erb, etc.) even though there may only be a few entries in the directory. When confronted with many extensions (using magic number 3) we go back to the old method of looping through all entries in the directory.

This PR makes searching for files with no transforms very fast. For example images in large directories will be much faster as they will only require one lookup instead of looping through all entries.

Using the same script from #331

```
$ be rake sprockets:benchmark
Running benchmark...
1500 lookups of the same asset took 1.369423
1500 lookups of 1500 different assets took 2.058736
```

Which is a substantial speedup.

In the future if we could imply the user's preferred extension i.e if a user uses `.coffee.erb` for all JS files and never uses `.eco.js` then we could make this even faster. We could record the file extensions that are used when running in the cache, prefer those when available, when not available fall back to this logic and record the file extension.
@schneems schneems merged commit fb35173 into master Jun 29, 2016
schneems added a commit that referenced this pull request Jun 29, 2016
schneems added a commit that referenced this pull request Jul 1, 2016
With this patch using the benchmark script https://github.com/schneems/sprockets-3.x-performance-regressions:

```
1500 lookups of the same asset took 2.900005
1500 lookups of 1500 different assets took 2.746331
```

Without this patch using the benchmark script:

```
1500 lookups of the same asset took 12.361615
1500 lookups of 1500 different assets took 12.627099
```
schneems added a commit that referenced this pull request Jul 1, 2016
With this patch using the benchmark script https://github.com/schneems/sprockets-3.x-performance-regressions:

```
1500 lookups of the same asset took 2.900005
1500 lookups of 1500 different assets took 2.746331
```

Without this patch using the benchmark script:

```
1500 lookups of the same asset took 12.361615
1500 lookups of 1500 different assets took 12.627099
```

Which is a 4x speed bump.
schneems added a commit that referenced this pull request Jul 1, 2016
With this patch using the benchmark script https://github.com/schneems/sprockets-3.x-performance-regressions:

```
1500 lookups of the same asset took 2.900005
1500 lookups of 1500 different assets took 2.746331
```

Without this patch using the benchmark script:

```
1500 lookups of the same asset took 12.361615
1500 lookups of 1500 different assets took 12.627099
```

Which is a 4x speed bump.
schneems added a commit that referenced this pull request Jul 1, 2016
Backport #331 - Asset lookup 4x Faster in large directories
schneems added a commit that referenced this pull request Jul 21, 2016
With this patch using the benchmark script https://github.com/schneems/sprockets-3.x-performance-regressions:

```
1500 lookups of the same asset took 2.900005
1500 lookups of 1500 different assets took 2.746331
```

Without this patch using the benchmark script:

```
1500 lookups of the same asset took 12.361615
1500 lookups of 1500 different assets took 12.627099
```

Which is a 4x speed bump.
schneems added a commit that referenced this pull request Jul 25, 2016
This reverts commit b6a86f9.

It makes non-pathological cases slower. I want to re-visit this with a clean slate later.
schneems added a commit that referenced this pull request Aug 25, 2016
schneems added a commit that referenced this pull request Aug 25, 2016
@jeremy jeremy deleted the schneems/short-circuit-entry-check branch November 3, 2016 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant