This repository has been archived by the owner on Jul 10, 2018. It is now read-only.
forked from rubinius/rubinius
/
index.html
312 lines (248 loc) · 13.2 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
<!DOCTYPE html>
<html>
<head>
<title>Making Rubinius .rbc Files Disappear - Rubinius</title>
<meta content='text/html;charset=utf-8' http-equiv='content-type'>
<meta content='en' http-equiv='content-language'>
<meta content='Rubinius is an implementation of the Ruby programming language. The Rubinius bytecode virtual machine is written in C++. The bytecode compiler is written in pure Ruby. The vast majority of the core library is also written in Ruby, with some supporting primitives that interact with the VM directly.' name='description'>
<meta content='Less Than Three. <3. http://less.thanthree.com' name='author'>
<link href='/' rel='home'>
<link href='/' rel='start'>
<link href='/feed/atom.xml' rel='alternate' type='application/atom+xml' title='Rubinius Blog' />
<!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script><![endif]-->
<script src="/javascripts/jquery-1.3.2.js" type="text/javascript"></script>
<script src="/javascripts/paging_keys.js" type="text/javascript"></script>
<script src="/javascripts/application.js" type="text/javascript"></script>
<style>article, aside, dialog, figure, footer, header, hgroup, menu, nav, section { display: block; }</style>
<link href="/stylesheets/blueprint/screen.css" media="screen" rel="stylesheet" type="text/css" />
<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
<link href="/stylesheets/blueprint/print.css" media="print" rel="stylesheet" type="text/css" />
<!--[if IE]><link href="/stylesheets/blueprint/ie.css" media="screen" rel="stylesheet" type="text/css" /><![endif]-->
<!--[if IE]><link href="/stylesheets/ie.css" media="screen" rel="stylesheet" type="text/css" /><![endif]-->
<link href="/stylesheets/pygments.css" media="screen" rel="stylesheet" type="text/css" />
</head>
<body>
<div class='container'>
<div class='span-21 blog_menu'>
<header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a id="blog" href="/blog/">Blog</a></li>
<li><a id="documentation" href="/doc/en/">Documentation</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/roadmap/">Roadmap</a></li>
<li><a href="/releases/">Releases</a></li>
</ul>
</nav>
</header>
</div>
<div class='span-3 last'>
<div id='version'>
<a href="/releases/1.2.3">1.2.3</a>
</div>
</div>
</div>
<div class="container posts_nav">
<nav>
<a href="/blog/posts_index/">Index of Posts</a>
<a id="feed_icon" href="/feed/atom.xml"><img alt="subscribe" src="/images/feed-icon16x16.png" /></a>
</nav>
</div>
<div class="container blog_posts">
<h2 class="post_title">Making Rubinius .rbc Files Disappear</h2>
<div class="by_line">
<p><span class="author">Brian Ford</span>
<span class="date">11 March 2011</span>
</p>
</div>
<p>Rubinius is rather unusual as a Ruby implementation. It both compiles Ruby
source code to bytecode <em>and</em> saves the compiled code to a cache so it does
not need to recompile unless the source code changes. This can be great for
utilities that are run often from the command line (including IRB). Rubinius
merely reloads the cached file and runs the bytecode directly rather than
needing to parse and compile the file. Sounds like a real win!</p>
<p>Unfortunately, it is not that simple. We need some place to store that cache
and this is where the thorns on that pretty rose start poking us in the
thumbs. The solution we have been using since forever is to store the cached
file alongside the source file in the same directory, like so:</p>
<pre><code>$ echo 'puts "hello!"' > hello.rb
$ ls hello.*
hello.rb
$ rbx hello.rb
hello!
$ ls hello.*
hello.rb hello.rbc
</code></pre>
<p>That doesn’t look too crazy, but it can get more complicated:</p>
<pre><code>$ mv hello.rb hello
$ rbx hello
$ ls hello.*
hello.compiled.rbc hello.rbc
</code></pre>
<p>Whoa, what is <code>hello.compiled.rbc</code>? Since <code>hello</code> did not have an extension,
we add that longer <code>compiled.rbc</code> to make it clear which file the cache is
for. Also, note that we have that <code>hello.rbc</code> hanging about even though the
original <code>hello.rb</code> is gone.</p>
<p>To summarize the issues with our caching scheme:</p>
<ol>
<li>It requires an additional file for every Ruby source file.</li>
<li>It requires some potentially complicated naming scheme to associate the
cache file with the source and not clash with other names.</li>
<li>Removing or renaming the Ruby source file leaves the cache file behind.</li>
</ol>
<p>Again, the advantage of the cache file is that you do not have to wait for
Rubinius to recompile the file if you have not changed the source. Let’s see
if we can get all the advantages with none of the disadvantages. That old
saying comes to mind, <em>Having your cake and eating it, too</em>, so we may not
be successful, but it is worth a shot.</p>
<p>First, let’s take a step back. This issue is not unique to Rubinius. Python
has <code>.pyc</code> and <code>.pyo</code> files. Java has <code>.class</code> files. C/C++ has <code>.o</code> files.
Lots of things need a place to store a compiled or cached representation of
some data. Every SCM worth mention has some mechanism to ignore the files you
don’t want to track. The same is generally true of editors. So in some sense,
this is a solved problem. However, we have always received complaints about
the <code>.rbc</code> files, so we thought we would try to make other, hopefully better,
solutions available.</p>
<h3 id="solution-1-no-cache">Solution 1: No Cache</h3>
<p>One simple solution is just to never ever ever create the compiled cache files
in any form anywhere. We have an option for that:</p>
<pre><code>$ ls hello.*
hello.rb
$ rbx -Xcompiler.no_rbc hello.rb
hello!
$ ls hello.*
hello.rb
</code></pre>
<p>Win! Not one lousy <code>.rbc</code> file in sight. Although, that’s quite the option to
type. Never fear, we have a solution to that below.</p>
<p>Here is our scorecard for solution 1:</p>
<p><strong>Use Case:</strong> Use when you never want any compiler cache files created. For
example, on a server where startup time is not really a concern.</p>
<p><strong>Pros:</strong> No <code>.rbc</code> files at all.</p>
<p><strong>Cons:</strong> Startup will be slightly slower depending on what Ruby code you are
running. It will be more noticeable in a Rails application, for example.
However, the Rubinius bytecode compiler is several times faster than it was a
couple years ago so it may not be an issue for you.</p>
<h3 id="solution-2-cache-database">Solution 2: Cache Database</h3>
<p>What if we could put all the compilation data in a single cache location,
something like a database? We have an option for that.</p>
<p>This option is a little more complex, so let’s take it in two steps.</p>
<pre><code>$ ls hello.*
hello.rb
$ rbx -Xrbc.db hello.rb
hello!
$ ls hello.*
hello.rb
$ ls -R .rbx
60
.rbx/60:
60c091c3ed34c1b93ffbb33d82d810772902d3f9
</code></pre>
<p>Success! No <code>.rbc</code> files here. But what’s with all the numbers in the <code>.rbx</code>
directory and how did that directory get there?</p>
<p>The <code>-Xrbc.db</code> option without any argument will store the compilation cache in
the <code>.rbx</code> directory in the current working directory. The cache files
themselves are split into subdirectories to avoid creating too many entries
for the file system to handle in one directory.</p>
<p>What if you have a special location where you would prefer all compilation
cache files be saved? No problem, just give <code>-Xrbc.db</code> a path as follows:</p>
<pre><code>$ ls hello.*
hello.rb
$ rbx -Xrbc.db=$HOME/.my_special_place hello.rb
hello!
$ ls hello.*
hello.rb
$ ls -R $HOME/.my_special_place
60
/Users/brian/.my_special_place/60:
60c091c3ed34c1b93ffbb33d82d810772902d3f9
</code></pre>
<p>If you primarily work with projects, putting the <code>.rbx</code> directory in the
current working directory may be the best solution because it keeps the
compilation cache with the project. It is easy to add an SCM ignore for the
directory and easy to remove the directory to clear the cache (e.g. in a clean
task).</p>
<p>However, if you are frequently running scripts in many directories, you may
not want to litter <code>.rbx</code> directories everywhere. In this case, putting the
directory in your <code>$HOME</code> dir or <code>/tmp</code> may be preferable. Additionally,
<code>/tmp</code> may be cleared on every reboot so you will not accumulate many stale
cache files.</p>
<p>Note that, right now, Rubinius does not clear the cache directory. It will
happily continue adding to it indefinitely. However, this may not be an issue
unless you are cycling through a bunch of Ruby files, for example, working on
a number of Ruby projects in series. In that case, using a per-project (per
current working directory) cache is probably the best option.</p>
<p>Here is how solution 2 shakes out:</p>
<p><strong>Use Case:</strong> You want to combine all compilation cache files in one location.</p>
<p><strong>Pros:</strong> No <code>.rbc</code> files mixed in with the rest of your files.</p>
<p><strong>Cons:</strong> You may still need a per-project or per-working-directory cache
directory. However, you can easily specify where to put that directory.</p>
<h3 id="using-rbxopt-for-options">Using RBXOPT for Options</h3>
<p>As mentioned above, the <code>-X</code> options can get a little long and you certainly
don’t want to retype them constantly. We have added support for the <code>RBXOPT</code>
environment variable, which is an analog of the <code>RUBYOPT</code> environment variable
that we already support.</p>
<p>Use <code>RBXOPT</code> to specify <code>-X</code> options that Rubinius should use. For example:</p>
<pre><code>export RBXOPT=-Xrbc.db=/path/to/dir
</code></pre>
<p>You can check out all the <code>-X</code> options with <code>rbx -Xconfig.print</code> or <code>rbx
-Xconfig.print=2</code> for more verbose output. If you want to use multiple <code>-X</code>
options in <code>RBXOPT</code>, use quotes and separate the options with a space:</p>
<pre><code>export RBXOPT='-Xrbc.db -Xagent.start'
</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>Rubinius saves a compilation cache for compiled Ruby code to avoid wasting
time and resources recompiling source that has not changed. However, we need
some place to store the cache. Rubinius provides options for omitting the
cache altogether or for storing it in a directory of your choosing. Note that
the format of the compilation cache is an implementation detail and we reserve
the right to change it at any time, so please don’t rely on it being in any
particular format.</p>
<p>We have not turned on <code>-Xrbc.db</code> by default yet because we don’t know what a
good default is. So give us feedback on your use cases and what you would find
most useful.</p>
<p>Finally, whenever we discuss the compilation cache we are inevitably asked if
you can run directly from the cache and not use the Ruby source at all after
it has been compiled. The short answer is “Yes”, the long answer is “It
depends”. I will be writing a post exploring this question in detail shortly.
For now, get out there and write more Ruby code!</p>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = 'rubinius';
var disqus_identifier = '/2011/03/11/making-rubinius-rbc-files-disappear/';
var disqus_url = 'http://rubini.us/2011/03/11/making-rubinius-rbc-files-disappear/';
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
<footer>
<div class='container'>
<nav>
<ul>
<li><a href="http://twitter.com/rubinius">Follow Rubinius on Twitter</a></li>
<li><a href="http://github.com/evanphx/rubinius">Fork Rubinius on github</a></li>
<li><a href="http://engineyard.com">An Engine Yard project</a></li>
<li id='credit'>
Site design by
<a href="http://less.thanthree.com">Less Than Three</a>
</li>
</ul>
</nav>
</div>
</footer>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-12328521-1");
pageTracker._trackPageview();
} catch(err) {}</script>
</body>
</html>