<!doctype html><htmllang=endir=ltrclass="blog-wrapper blog-post-page plugin-blog plugin-id-default"data-has-hydrated=false><metacharset=UTF-8><metaname=generatorcontent="Docusaurus v3.6.1"><titledata-rh=true>Allocations in Rust: Compiler optimizations | The Old Speice Guy</title><metadata-rh=truename=viewportcontent="width=device-width,initial-scale=1.0"><metadata-rh=truename=twitter:cardcontent=summary_large_image><metadata-rh=trueproperty=og:urlcontent=https://speice.io/2019/02/08/compiler-optimizations><metadata-rh=trueproperty=og:localecontent=en><metadata-rh=truename=docusaurus_localecontent=en><metadata-rh=truename=docusaurus_tagcontent=default><metadata-rh=truename=docsearch:languagecontent=en><metadata-rh=truename=docsearch:docusaurus_tagcontent=default><metadata-rh=trueproperty=og:titlecontent="Allocations in Rust: Compiler optimizations | The Old Speice Guy"><metadata-rh=truename=descriptioncontent="A lot. The answer is a lot."><metadata-rh=trueproperty=og:descriptioncontent="A lot. The answer is a lot."><metadata-rh=trueproperty=og:typecontent=article><metadata-rh=trueproperty=article:published_timecontent=2019-02-08T12:00:00.000Z><linkdata-rh=truerel=iconhref=/img/favicon.ico><linkdata-rh=truerel=canonicalhref=https://speice.io/2019/02/08/compiler-optimizations><linkdata-rh=truerel=alternatehref=https://speice.io/2019/02/08/compiler-optimizationshreflang=en><linkdata-rh=truerel=alternatehref=https://speice.io/2019/02/08/compiler-optimizationshreflang=x-default><scriptdata-rh=truetype=application/ld+json>{"@context":"https://schema.org","@id":"https://speice.io/2019/02/08/compiler-optimizations","@type":"BlogPosting","author":[],"dateModified":"2024-11-10T02:05:00.000Z","datePublished":"2019-02-08T12:00:00.000Z","description":"A lot. The answer is a lot.","headline":"Allocations in Rust: Compiler optimizations","isPartOf":{"@id":"https://speice.io/","@type":"Blog","name":"Blog"},"keywords":[],"mainEntityOfPage":"https://speice.io/2019/02/08/compiler-optimizations","name":"Allocations in Rust: Compiler optimizations","url":"https://speice.io/2019/02/08/compiler-optimizations"}</script><linkrel=alternatetype=application/rss+xmlhref=/rss.xmltitle="The Old Speice Guy RSS Feed"><linkrel=alternatetype=application/atom+xmlhref=/atom.xmltitle="The Old Speice Guy Atom Feed"><linkrel=stylesheethref=/katex/katex.min.css><linkrel=stylesheethref=/assets/css/styles.16c3428d.css><scriptsrc=/assets/js/runtime~main.29a27dcf.jsdefer></script><scriptsrc=/assets/js/main.d461af80.jsdefer></script><bodyclass=navigation-with-keyboard><script>!function(){vart,e=function(){try{returnnewURLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{returnwindow.localStorage.getItem("theme")}catch(t){}}();t=null!==e?e:"light",document.documentElement.setAttribute("data-theme",t)}(),function(){try{for(var[t,e]ofnewURLSearchParams(window.location.search).entries())if(t.startsWith("docusaurus-data-")){vara=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><divid=__docusaurus><divrole=regionaria-label="Skip to main content"><aclass=skipToContent_fXgnhref=#__docusaurus_skipToContent_fallback>Skip to main content</a></div><navaria-label=Mainclass="navbar navbar--fixed-top"><divclass=navbar__inner><divclass=navbar__items><buttonaria-label="Toggle navigation bar"aria-expanded=falseclass="navbar__toggle clean-btn"type=button><svgwidth=30height=30viewBox="0 0 30 30"aria-hidden=true><pathstroke=currentColorstroke-linecap=roundstroke-miterlimit=10stroke-width=2d="M4 7h22M4 15h22M4 23h22"/></svg></button><aclass=navbar__brandhref=/><divclass=navbar__logo><imgsrc=/img/logo.svgalt="Sierpinski Gasket"class="themedComponent_mlkZ themedComponent--light_NVdE"><imgsrc=/img/logo-dark.svgalt="Sierpinski Gasket"class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><bclass="navbar__title text--truncate">The Old Speice Guy</b></a></div><divclass="navb
rules that are mostly right for small chunks of code. We've spent time showing how those rules work
themselves out in practice, and become familiar with reading the assembly code needed to see each
memory type (global, stack, heap) in action.</p>
<p>Throughout the series so far, we've put a handicap on the code. In the name of consistent and
understandable results, we've asked the compiler to pretty please leave the training wheels on. Now
is the time where we throw out all the rules and take off the kid gloves. As it turns out, both the
Rust compiler and the LLVM optimizers are incredibly sophisticated, and we'll step back and let them
do their job.</p>
<p>Similar to
<ahref="https://www.youtube.com/watch?v=bSkpMdDe4g4"target=_blankrel="noopener noreferrer">"What Has My Compiler Done For Me Lately?"</a>, we're
focusing on interesting things the Rust language (and LLVM!) can do with memory management. We'll
still be looking at assembly code to understand what's going on, but it's important to mention
again: <strong>please use automated tools like <ahref=https://crates.io/crates/alloc_countertarget=_blankrel="noopener noreferrer">alloc-counter</a> to
double-check memory behavior if it's something you care about</strong>. It's far too easy to mis-read
assembly in large code sections, you should always verify behavior if you care about memory usage.</p>
<p>The guiding principal as we move forward is this: <em>optimizing compilers won't produce worse programs
than we started with.</em> There won't be any situations where stack allocations get moved to heap
allocations. There will, however, be an opera of optimization.</p>
<p><strong>Update 2019-02-10</strong>: When debugging a
<ahref=https://gitlab.com/sio4/code/alloc-counter/issues/1target=_blankrel="noopener noreferrer">related issue</a>, it was discovered that the
original code worked because LLVM optimized out the entire function, rather than just the allocation
segments. The code has been updated with proper use of
<ahref=https://doc.rust-lang.org/std/ptr/fn.read_volatile.htmltarget=_blankrel="noopener noreferrer"><code>read_volatile</code></a>, and a previous section
on vector capacity has been removed.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=the-case-of-the-disappearing-box>The Case of the Disappearing Box<ahref=#the-case-of-the-disappearing-boxclass=hash-linkaria-label="Direct link to The Case of the Disappearing Box"title="Direct link to The Case of the Disappearing Box"></a></h2>
<p>Our first optimization comes when LLVM can reason that the lifetime of an object is sufficiently
short that heap allocations aren't necessary. In these cases, LLVM will move the allocation to the
stack instead! The way this interacts with <code>#[inline]</code> attributes is a bit opaque, but the important
part is that LLVM can sometimes do better than the baseline Rust language:</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=dr-array-or-how-i-learned-to-love-the-optimizer>Dr. Array or: how I learned to love the optimizer<ahref=#dr-array-or-how-i-learned-to-love-the-optimizerclass=hash-linkaria-label="Direct link to Dr. Array or: how I learned to love the optimizer"title="Direct link to Dr. Array or: how I learned to love the optimizer"></a></h2>
<p>Finally, this isn't so much about LLVM figuring out different memory behavior, but LLVM stripping
out code that doesn't do anything. Optimizations of this type have a lot of nuance to them; if
you're not careful, they can make your benchmarks look
<ahref="https://www.youtube.com/watch?v=nXaxk27zwlk&feature=youtu.be&t=1199"target=_blankrel="noopener noreferrer">impossibly good</a>. In Rust, the
<code>black_box</code> function (implemented in both
<ahref=https://doc.rust-lang.org/1.1.0/test/fn.black_box.htmltarget=_blankrel="noopener noreferrer"><code>libtest</code></a> and
<ahref=https://docs.rs/criterion/0.2.10/criterion/fn.black_box.htmltarget=_blankrel="noopener noreferrer"><code>criterion</code></a>) will tell the compiler
to disable this kind of optimization. But if you let LLVM remove unnecessary code, you can end up
running programs that previously caused errors:</p>