bootsnap 1.1.0.pre → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 ![
|
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
|
-
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
|