bootsnap 1.1.0.pre → 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 +4 -4
- data/CHANGELOG.md +2 -0
- data/README.md +15 -14
- data/bootsnap.gemspec +0 -1
- data/ext/bootsnap/bootsnap.c +29 -0
- data/lib/bootsnap/compile_cache/iseq.rb +3 -18
- data/lib/bootsnap/load_path_cache/cache.rb +11 -1
- data/lib/bootsnap/load_path_cache/path.rb +2 -0
- data/lib/bootsnap/version.rb +1 -1
- metadata +4 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbdf0cc19b09b396571d9d38cb037cebfcdab7b2
|
4
|
+
data.tar.gz: f07f07ec071dbffe3a48e1ae324457729a11ca61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9db4ab87163f7c05a7b5c62fe17617149ec5acdc1caf186013c334222a4ad0a2087c5992b44fcf424201dd5b12448ce25826ccb4f99f495e450437aa90d0a0ae
|
7
|
+
data.tar.gz: 84714b27f6a3be1650807af151309dc789390944c1a317ec9c246067c2f4299184c182aa878c8eb5715da989c1c768a3d86992af02ab9d974f1d26d09bb2d170
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
# Bootsnap ](https://travis-ci.org/Shopify/bootsnap)
|
2
2
|
|
3
3
|
**Beta-quality. See [the last section of this README](#trustworthiness).**
|
4
4
|
|
5
|
-
Bootsnap is a library that plugs into
|
6
|
-
|
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
|
-
####
|
8
|
+
#### Performance
|
9
9
|
- [Discourse](https://github.com/discourse/discourse) reports a boot time reduction of approximately 50%, from roughly 6 to 3 seconds on one machine;
|
10
10
|
- One of our smaller internal apps also sees a reduction of 50%, from 3.6 to 1.8 seconds;
|
11
11
|
- The core Shopify platform -- a rather large monolithic application -- boots about 75% faster, dropping from around 25s to 6.5s.
|
@@ -32,14 +32,15 @@ this is loaded, the sooner it can start optimizing things)
|
|
32
32
|
|
33
33
|
```ruby
|
34
34
|
require 'bootsnap'
|
35
|
+
env = ENV['RAILS_ENV'] || "development"
|
35
36
|
Bootsnap.setup(
|
36
|
-
cache_dir: 'tmp/cache',
|
37
|
-
development_mode:
|
38
|
-
load_path_cache: true,
|
39
|
-
autoload_paths_cache: true,
|
40
|
-
disable_trace:
|
41
|
-
compile_cache_iseq: true,
|
42
|
-
compile_cache_yaml: true
|
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
|
43
44
|
)
|
44
45
|
```
|
45
46
|
|
@@ -49,8 +50,7 @@ will help optimize boot time further if you have an extremely large `$LOAD_PATH`
|
|
49
50
|
|
50
51
|
## How does this work?
|
51
52
|
|
52
|
-
Bootsnap
|
53
|
-
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
|
54
54
|
into two broad categories:
|
55
55
|
|
56
56
|
* [Path Pre-Scanning](#path-pre-scanning)
|
@@ -110,7 +110,8 @@ entries do not expire -- once their contents has been scanned, it is assumed to
|
|
110
110
|
|
111
111
|
The only directories considered "stable" are things under the Ruby install prefix
|
112
112
|
(`RbConfig::CONFIG['prefix']`, e.g. `/usr/local/ruby` or `~/.rubies/x.y.z`), and things under the
|
113
|
-
`Gem.path` (e.g. `~/.gem/ruby/x.y.z`). Everything else is considered
|
113
|
+
`Gem.path` (e.g. `~/.gem/ruby/x.y.z`) or `Bundler.bundle_path`. Everything else is considered
|
114
|
+
"volatile".
|
114
115
|
|
115
116
|
In addition to the [`Bootsnap::LoadPathCache::Cache`
|
116
117
|
source](https://github.com/Shopify/bootsnap/blob/master/lib/bootsnap/load_path_cache/cache.rb),
|
data/bootsnap.gemspec
CHANGED
@@ -34,7 +34,6 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_development_dependency 'rake-compiler', '~> 0'
|
35
35
|
spec.add_development_dependency "minitest", "~> 5.0"
|
36
36
|
spec.add_development_dependency "mocha", "~> 1.2"
|
37
|
-
spec.add_development_dependency "ffi-xattr", "~> 0.1.2"
|
38
37
|
|
39
38
|
spec.add_runtime_dependency "msgpack", "~> 1.0"
|
40
39
|
end
|
data/ext/bootsnap/bootsnap.c
CHANGED
@@ -18,7 +18,9 @@
|
|
18
18
|
#include <errno.h>
|
19
19
|
#include <fcntl.h>
|
20
20
|
#include <sys/stat.h>
|
21
|
+
#ifndef _WIN32
|
21
22
|
#include <sys/utsname.h>
|
23
|
+
#endif
|
22
24
|
|
23
25
|
/* 1000 is an arbitrary limit; FNV64 plus some slashes brings the cap down to
|
24
26
|
* 981 for the cache dir */
|
@@ -109,6 +111,15 @@ struct s2o_data;
|
|
109
111
|
struct i2o_data;
|
110
112
|
struct i2s_data;
|
111
113
|
|
114
|
+
/* https://bugs.ruby-lang.org/issues/13667 */
|
115
|
+
extern VALUE rb_get_coverages(void);
|
116
|
+
static VALUE
|
117
|
+
bs_rb_coverage_running(VALUE self)
|
118
|
+
{
|
119
|
+
VALUE cov = rb_get_coverages();
|
120
|
+
return RTEST(cov) ? Qtrue : Qfalse;
|
121
|
+
}
|
122
|
+
|
112
123
|
/*
|
113
124
|
* Ruby C extensions are initialized by calling Init_<extname>.
|
114
125
|
*
|
@@ -129,6 +140,7 @@ Init_bootsnap(void)
|
|
129
140
|
|
130
141
|
uncompilable = rb_intern("__bootsnap_uncompilable__");
|
131
142
|
|
143
|
+
rb_define_module_function(rb_mBootsnap_CompileCache_Native, "coverage_running?", bs_rb_coverage_running, 0);
|
132
144
|
rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch, 3);
|
133
145
|
rb_define_module_function(rb_mBootsnap_CompileCache_Native, "compile_option_crc32=", bs_compile_option_crc32_set, 1);
|
134
146
|
}
|
@@ -176,6 +188,9 @@ fnv1a_64(const char *str)
|
|
176
188
|
static uint32_t
|
177
189
|
get_os_version(void)
|
178
190
|
{
|
191
|
+
#ifdef _WIN32
|
192
|
+
return (uint32_t)GetVersion();
|
193
|
+
#else
|
179
194
|
uint64_t hash;
|
180
195
|
struct utsname utsname;
|
181
196
|
|
@@ -185,6 +200,7 @@ get_os_version(void)
|
|
185
200
|
hash = fnv1a_64(utsname.version);
|
186
201
|
|
187
202
|
return (uint32_t)(hash >> 32);
|
203
|
+
#endif
|
188
204
|
}
|
189
205
|
|
190
206
|
/*
|
@@ -265,6 +281,9 @@ open_current_file(char * path, struct bs_cache_key * key)
|
|
265
281
|
|
266
282
|
fd = open(path, O_RDONLY);
|
267
283
|
if (fd < 0) return fd;
|
284
|
+
#ifdef _WIN32
|
285
|
+
setmode(fd, O_BINARY);
|
286
|
+
#endif
|
268
287
|
|
269
288
|
if (fstat(fd, &statbuf) < 0) {
|
270
289
|
close(fd);
|
@@ -321,6 +340,9 @@ open_cache_file(const char * path, struct bs_cache_key * key)
|
|
321
340
|
if (errno == ENOENT) return CACHE_MISSING_OR_INVALID;
|
322
341
|
return ERROR_WITH_ERRNO;
|
323
342
|
}
|
343
|
+
#ifdef _WIN32
|
344
|
+
setmode(fd, O_BINARY);
|
345
|
+
#endif
|
324
346
|
|
325
347
|
res = bs_read_key(fd, key);
|
326
348
|
if (res < 0) {
|
@@ -393,7 +415,11 @@ mkpath(char * file_path, mode_t mode)
|
|
393
415
|
char * p;
|
394
416
|
for (p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) {
|
395
417
|
*p = '\0';
|
418
|
+
#ifdef _WIN32
|
419
|
+
if (mkdir(file_path) == -1) {
|
420
|
+
#else
|
396
421
|
if (mkdir(file_path, mode) == -1) {
|
422
|
+
#endif
|
397
423
|
if (errno != EEXIST) {
|
398
424
|
*p = '/';
|
399
425
|
return -1;
|
@@ -428,6 +454,9 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data)
|
|
428
454
|
fd = open(tmp_path, O_WRONLY | O_CREAT, 0644);
|
429
455
|
if (fd < 0) return -1;
|
430
456
|
}
|
457
|
+
#ifdef _WIN32
|
458
|
+
setmode(fd, O_BINARY);
|
459
|
+
#endif
|
431
460
|
|
432
461
|
key->data_size = RSTRING_LEN(data);
|
433
462
|
nwrite = write(fd, key, KEY_SIZE);
|
@@ -12,12 +12,6 @@ module Bootsnap
|
|
12
12
|
RubyVM::InstructionSequence.compile_file(path).to_binary
|
13
13
|
rescue SyntaxError
|
14
14
|
raise Uncompilable, 'syntax error'
|
15
|
-
rescue RuntimeError => e
|
16
|
-
if e.message == 'should not compile with coverage'
|
17
|
-
raise Uncompilable, 'coverage is enabled'
|
18
|
-
else
|
19
|
-
raise
|
20
|
-
end
|
21
15
|
end
|
22
16
|
|
23
17
|
def self.storage_to_output(binary)
|
@@ -37,6 +31,9 @@ module Bootsnap
|
|
37
31
|
|
38
32
|
module InstructionSequenceMixin
|
39
33
|
def load_iseq(path)
|
34
|
+
# Having coverage enabled prevents iseq dumping/loading.
|
35
|
+
return nil if defined?(Coverage) && Bootsnap::CompileCache::Native.coverage_running?
|
36
|
+
|
40
37
|
Bootsnap::CompileCache::Native.fetch(
|
41
38
|
Bootsnap::CompileCache::ISeq.cache_dir,
|
42
39
|
path.to_s,
|
@@ -47,18 +44,6 @@ module Bootsnap
|
|
47
44
|
puts "unmatched platform for file #{path}"
|
48
45
|
end
|
49
46
|
raise
|
50
|
-
rescue Errno::ERANGE
|
51
|
-
STDERR.puts <<~EOF
|
52
|
-
\x1b[31mError loading ISeq from cache for \x1b[1;34m#{path}\x1b[0;31m!
|
53
|
-
You can likely fix this by running:
|
54
|
-
\x1b[1;32mxattr -c #{path}
|
55
|
-
\x1b[0;31m...but, first, please make sure \x1b[1;34m@burke\x1b[0;31m knows you ran into this bug!
|
56
|
-
He will want to see the results of:
|
57
|
-
\x1b[1;32m/bin/ls -l@ #{path}
|
58
|
-
\x1b[0;31mand:
|
59
|
-
\x1b[1;32mxattr -p user.aotcc.key #{path}\x1b[0m
|
60
|
-
EOF
|
61
|
-
raise
|
62
47
|
end
|
63
48
|
|
64
49
|
def compile_option=(hash)
|
@@ -48,7 +48,7 @@ module Bootsnap
|
|
48
48
|
def find(feature)
|
49
49
|
reinitialize if (@has_relative_paths && dir_changed?) || stale?
|
50
50
|
feature = feature.to_s
|
51
|
-
return feature if
|
51
|
+
return feature if absolute_path?(feature)
|
52
52
|
return File.expand_path(feature) if feature.start_with?('./')
|
53
53
|
@mutex.synchronize do
|
54
54
|
x = search_index(feature)
|
@@ -85,6 +85,16 @@ module Bootsnap
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
89
|
+
def absolute_path?(path)
|
90
|
+
path[1] == ':'
|
91
|
+
end
|
92
|
+
else
|
93
|
+
def absolute_path?(path)
|
94
|
+
path.start_with?(SLASH)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
88
98
|
def unshift_paths(sender, *paths)
|
89
99
|
return unless sender == @path_obj
|
90
100
|
@mutex.synchronize { unshift_paths_locked(*paths) }
|
@@ -99,6 +99,8 @@ module Bootsnap
|
|
99
99
|
@stability ||= begin
|
100
100
|
if Gem.path.detect { |p| expanded_path.start_with?(p.to_s) }
|
101
101
|
STABLE
|
102
|
+
elsif expanded_path.start_with?(Bundler.bundle_path.to_s)
|
103
|
+
STABLE
|
102
104
|
elsif expanded_path.start_with?(RUBY_LIBDIR) && !expanded_path.start_with?(RUBY_SITEDIR)
|
103
105
|
STABLE
|
104
106
|
else
|
data/lib/bootsnap/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootsnap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.2'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: ffi-xattr
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: 0.1.2
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 0.1.2
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: msgpack
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -163,9 +149,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
163
149
|
version: 2.0.0
|
164
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
151
|
requirements:
|
166
|
-
- - "
|
152
|
+
- - ">="
|
167
153
|
- !ruby/object:Gem::Version
|
168
|
-
version:
|
154
|
+
version: '0'
|
169
155
|
requirements: []
|
170
156
|
rubyforge_project:
|
171
157
|
rubygems_version: 2.6.10
|