bootsnap 0.2.15 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b0de1ff4a8bdd4478f422a07fba3981778828604
4
- data.tar.gz: d9b7d5cc09e58be7bc31382be47d72870c60bf7f
3
+ metadata.gz: fbdf0cc19b09b396571d9d38cb037cebfcdab7b2
4
+ data.tar.gz: f07f07ec071dbffe3a48e1ae324457729a11ca61
5
5
  SHA512:
6
- metadata.gz: f153d3e9591eb2fb8d2efecb958cbe21f61d93040f891ef63809285418cf76b3883d5490b3aa60d656bd066f96d7489317b13833bdf465058f7a339547177f6c
7
- data.tar.gz: be2f217b2481c5d3eb44226d9861d2890dc7901143ab056e0d1f2fbd5e4f152ef497fb1cd67481ae44c4723dc5b0c93a6f6f6faebd705f4ce321aa0e5949bd2f
6
+ metadata.gz: 9db4ab87163f7c05a7b5c62fe17617149ec5acdc1caf186013c334222a4ad0a2087c5992b44fcf424201dd5b12448ce25826ccb4f99f495e450437aa90d0a0ae
7
+ data.tar.gz: 84714b27f6a3be1650807af151309dc789390944c1a317ec9c246067c2f4299184c182aa878c8eb5715da989c1c768a3d86992af02ab9d974f1d26d09bb2d170
data/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ # 1.1.0
2
+
3
+ * Add `bootsnap/setup`
4
+ * Support jruby (without compile caching features)
5
+ * Better deoptimization when Coverage is enabled
6
+ * Consider `Bundler.bundle_path` to be stable
7
+
8
+ # 1.0.0
9
+
10
+ * (none)
11
+
12
+ # 0.3.2
13
+
14
+ * Minor performance savings around checking validity of cache in the presence of relative paths.
15
+ * When coverage is enabled, skips optimization instead of exploding.
16
+
17
+ # 0.3.1
18
+
19
+ * Don't whitelist paths under `RbConfig::CONFIG['prefix']` as stable; instead use `['libdir']` (#41).
20
+ * Catch `EOFError` when reading load-path-cache and regenerate cache.
21
+ * Support relative paths in load-path-cache.
22
+
23
+ # 0.3.0
24
+
25
+ * Migrate CompileCache from xattr as a cache backend to a cache directory
26
+ * Adds support for Linux and FreeBSD
27
+
1
28
  # 0.2.15
2
29
 
3
30
  * Support more versions of ActiveSupport (`depend_on`'s signature varies; don't reiterate it)
data/README.md CHANGED
@@ -1,39 +1,46 @@
1
- # Bootsnap ![CI status](https://travis-ci.org/Shopify/bootsnap.svg?branch=master)
1
+ # Bootsnap [![Build Status](https://travis-ci.org/Shopify/bootsnap.svg?branch=master)](https://travis-ci.org/Shopify/bootsnap)
2
2
 
3
3
  **Beta-quality. See [the last section of this README](#trustworthiness).**
4
4
 
5
- **`compile_cache_*` features are only supported on MacOS (extremely likely to error on Linux;
6
- won't even compile on other platforms).**
5
+ Bootsnap is a library that plugs into Ruby, with optional support for `ActiveSupport` and `YAML`,
6
+ to optimize and cache expensive computations. See [How Does This Work](#how-does-this-work).
7
7
 
8
- Bootsnap is a library that plugs into a number of Ruby and (optionally) `ActiveSupport` and `YAML`
9
- methods to optimize and cache expensive computations. See [the How Does This Work section](#how-does-this-work) for more information.
10
-
11
- #### Quick Performance Overview
8
+ #### Performance
12
9
  - [Discourse](https://github.com/discourse/discourse) reports a boot time reduction of approximately 50%, from roughly 6 to 3 seconds on one machine;
13
10
  - One of our smaller internal apps also sees a reduction of 50%, from 3.6 to 1.8 seconds;
14
11
  - The core Shopify platform -- a rather large monolithic application -- boots about 75% faster, dropping from around 25s to 6.5s.
15
12
 
16
13
  ## Usage
17
14
 
15
+ This gem works on MacOS and Linux.
16
+
18
17
  Add `bootsnap` to your `Gemfile`:
19
18
 
20
19
  ```ruby
21
20
  gem 'bootsnap'
22
21
  ```
23
22
 
24
- Next, add this to your boot setup immediately after `require 'bundler/setup'` (i.e. as early as
25
- possible: the sooner this is loaded, the sooner it can start optimizing things)
23
+ If you are using rails, add this to `config/boot.rb` immediately after `require 'bundler/setup'`:
24
+
25
+ ```ruby
26
+ require 'bootsnap/setup'
27
+ ```
28
+
29
+ If you are not using rails, or if you are but want more control over things, add this to your
30
+ application setup immediately after `require 'bundler/setup'` (i.e. as early as possible: the sooner
31
+ this is loaded, the sooner it can start optimizing things)
26
32
 
27
33
  ```ruby
28
34
  require 'bootsnap'
35
+ env = ENV['RAILS_ENV'] || "development"
29
36
  Bootsnap.setup(
30
- cache_dir: 'tmp/cache', # Path to your cache
31
- development_mode: ENV['MY_ENV'] == 'development',
32
- load_path_cache: true, # Should we optimize the LOAD_PATH with a cache?
33
- autoload_paths_cache: true, # Should we optimize ActiveSupport autoloads with cache?
34
- disable_trace: false, # Sets `RubyVM::InstructionSequence.compile_option = { trace_instruction: false }`
35
- compile_cache_iseq: true, # Should compile Ruby code into ISeq cache?
36
- compile_cache_yaml: true # Should compile YAML into a cache?
37
+ cache_dir: 'tmp/cache', # Path to your cache
38
+ development_mode: env == 'development', # Current working environment, e.g. RACK_ENV, RAILS_ENV, etc
39
+ load_path_cache: true, # Optimize the LOAD_PATH with a cache
40
+ autoload_paths_cache: true, # Optimize ActiveSupport autoloads with cache
41
+ disable_trace: true, # (Alpha) Set `RubyVM::InstructionSequence.compile_option = { trace_instruction: false }`
42
+ compile_cache_iseq: true, # Compile Ruby code into ISeq cache, breaks coverage reporting.
43
+ compile_cache_yaml: true # Compile YAML into a cache
37
44
  )
38
45
  ```
39
46
 
@@ -43,8 +50,7 @@ will help optimize boot time further if you have an extremely large `$LOAD_PATH`
43
50
 
44
51
  ## How does this work?
45
52
 
46
- Bootsnap is a library that plugs into a number of Ruby and (optionally) `ActiveSupport` and `YAML`
47
- methods. These methods are modified to cache results of expensive computations, and can be grouped
53
+ Bootsnap optimizes methods to cache results of expensive computations, and can be grouped
48
54
  into two broad categories:
49
55
 
50
56
  * [Path Pre-Scanning](#path-pre-scanning)
@@ -104,7 +110,8 @@ entries do not expire -- once their contents has been scanned, it is assumed to
104
110
 
105
111
  The only directories considered "stable" are things under the Ruby install prefix
106
112
  (`RbConfig::CONFIG['prefix']`, e.g. `/usr/local/ruby` or `~/.rubies/x.y.z`), and things under the
107
- `Gem.path` (e.g. `~/.gem/ruby/x.y.z`). Everything else is considered "volatile".
113
+ `Gem.path` (e.g. `~/.gem/ruby/x.y.z`) or `Bundler.bundle_path`. Everything else is considered
114
+ "volatile".
108
115
 
109
116
  In addition to the [`Bootsnap::LoadPathCache::Cache`
110
117
  source](https://github.com/Shopify/bootsnap/blob/master/lib/bootsnap/load_path_cache/cache.rb),
@@ -120,7 +127,8 @@ result too, raising a `LoadError` without touching the filesystem at all.
120
127
 
121
128
  ### Compilation Caching
122
129
 
123
- *(A simpler implementation of this concept can be found in [yomikomu](https://github.com/ko1/yomikomu)).*
130
+ *(A more readable implementation of this concept can be found in
131
+ [yomikomu](https://github.com/ko1/yomikomu)).*
124
132
 
125
133
  Ruby has complex grammar and parsing it is not a particularly cheap operation. Since 1.9, Ruby has
126
134
  translated ruby source to an internal bytecode format, which is then executed by the Ruby VM. Since
@@ -134,9 +142,8 @@ implementation. We use the same strategy of compilation caching for YAML documen
134
142
  equivalent of Ruby's "bytecode" format being a MessagePack document (or, in the case of YAML
135
143
  documents with types unsupported by MessagePack, a Marshal stream).
136
144
 
137
- These compilation results are stored using `xattr`s on the source files. This is likely to change in
138
- the future, as it has some limitations (notably precluding Linux support except where the user feels
139
- like changing mount flags). However, this is a very performant implementation.
145
+ These compilation results are stored in a cache directory, with filenames generated by taking a hash
146
+ of the full expanded path of the input file (FNV1a-64).
140
147
 
141
148
  Whereas before, the sequence of syscalls generated to `require` a file would look like:
142
149
 
@@ -158,32 +165,36 @@ With bootsnap, we get:
158
165
  ```
159
166
  open /c/foo.rb -> n
160
167
  fstat64 n
161
- fgetxattr n
162
- fgetxattr n
168
+ close n
169
+ open /c/foo.rb -> n
170
+ fstat64 n
171
+ open (cache) -> m
172
+ read m
173
+ read m
174
+ close m
163
175
  close n
164
176
  ```
165
177
 
166
- Bootsnap writes two `xattrs` attached to each file read:
178
+ This may look worse at a glance, but underlies a large performance difference.
167
179
 
168
- * `user.aotcc.value`, the binary compilation result; and
169
- * `user.aotcc.key`, a cache key to determine whether `user.aotcc.value` is still valid.
180
+ *(The first three syscalls in both listings -- `open`, `fstat64`, `close` -- are not inherently
181
+ useful. [This ruby patch](https://bugs.ruby-lang.org/issues/13378) optimizes them out when coupled
182
+ with bootsnap.)*
170
183
 
171
- The key includes several fields:
184
+ Bootsnap writes a cache file containing a 64 byte header followed by the cache contents. The header
185
+ is a cache key including several fields:
172
186
 
173
187
  * `version`, hardcoded in bootsnap. Essentially a schema version;
188
+ * `os_version`, A hash of the current kernel version (on macOS, BSD) or glibc version (on Linux);
174
189
  * `compile_option`, which changes with `RubyVM::InstructionSequence.compile_option` does;
175
- * `data_size`, the number of bytes in `user.aotcc.value`, which we need to read it into a buffer
176
- using `fgetxattr(2)`;
177
- * `ruby_revision`, the version of Ruby this was compiled with; and
178
- * `mtime`, the last-modification timestamp of the source file when it was compiled.
190
+ * `ruby_revision`, the version of Ruby this was compiled with;
191
+ * `size`, the size of the source file;
192
+ * `mtime`, the last-modification timestamp of the source file when it was compiled; and
193
+ * `data_size`, the number of bytes following the header, which we need to read it into a buffer.
179
194
 
180
195
  If the key is valid, the result is loaded from the value. Otherwise, it is regenerated and clobbers
181
196
  the current cache.
182
197
 
183
- This diagram may help illustrate how it works:
184
-
185
- ![Compilation Caching](https://burkelibbey.s3.amazonaws.com/bootsnap-compile-cache.png)
186
-
187
198
  ### Putting it all together
188
199
 
189
200
  Imagine we have this file structure:
@@ -227,8 +238,13 @@ With bootsnap, we get:
227
238
  ```
228
239
  open /c/foo.rb -> n
229
240
  fstat64 n
230
- fgetxattr n
231
- fgetxattr n
241
+ close n
242
+ open /c/foo.rb -> n
243
+ fstat64 n
244
+ open (cache) -> m
245
+ read m
246
+ read m
247
+ close m
232
248
  close n
233
249
  ```
234
250
 
@@ -253,8 +269,8 @@ open /c/nope.bundle -> -1
253
269
 
254
270
  We use the `*_path_cache` features in production and haven't experienced any issues in a long time.
255
271
 
256
- The `compile_cache_*` features work well for us in development on macOS, but probably don't work on
257
- Linux at all.
272
+ The `compile_cache_*` features work well for us in development on macOS. It should work on Linux,
273
+ and we intend to deploy it in production, but we haven't yet.
258
274
 
259
275
  `disable_trace` should be completely safe, but we don't really use it because some people like to
260
276
  use tools that make use of `trace` instructions.
@@ -264,5 +280,5 @@ use tools that make use of `trace` instructions.
264
280
  | `load_path_cache` | everywhere |
265
281
  | `autoload_path_cache` | everywhere |
266
282
  | `disable_trace` | nowhere, but it's safe unless you need tracing |
267
- | `compile_cache_iseq` | development, unlikely to work on Linux |
268
- | `compile_cache_yaml` | development, unlikely to work on Linux |
283
+ | `compile_cache_iseq` | development, but probably safe to use everywhere |
284
+ | `compile_cache_yaml` | development, but probably safe to use everywhere |
data/bootsnap.gemspec CHANGED
@@ -18,19 +18,22 @@ Gem::Specification.new do |spec|
18
18
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
19
  f.match(%r{^(test|spec|features)/})
20
20
  end
21
- spec.bindir = "exe"
22
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
21
  spec.require_paths = ["lib"]
24
- spec.extensions = ['ext/bootsnap/extconf.rb']
25
22
 
26
- spec.required_ruby_version = '>= 2.3.0'
23
+ spec.required_ruby_version = '>= 2.0.0'
24
+
25
+ if RUBY_PLATFORM =~ /java/
26
+ spec.platform = 'java'
27
+ else
28
+ spec.platform = Gem::Platform::RUBY
29
+ spec.extensions = ['ext/bootsnap/extconf.rb']
30
+ end
27
31
 
28
32
  spec.add_development_dependency "bundler", '~> 1'
29
33
  spec.add_development_dependency 'rake', '~> 10.0'
30
34
  spec.add_development_dependency 'rake-compiler', '~> 0'
31
35
  spec.add_development_dependency "minitest", "~> 5.0"
32
36
  spec.add_development_dependency "mocha", "~> 1.2"
33
- spec.add_development_dependency "ffi-xattr", "~> 0.1.2"
34
37
 
35
38
  spec.add_runtime_dependency "msgpack", "~> 1.0"
36
39
  end