better gaming

This commit is contained in:
nora 2025-09-29 20:41:20 +02:00
parent bcfaf55513
commit d57e076267
2 changed files with 165 additions and 29 deletions

View file

@ -25,7 +25,8 @@
<div class="reveal">
<div class="slides">
<section>
<h2>how rust compiles</h2>
<h2>how Rust compiles</h2>
<h4>i promise it's actually doing something useful while you wait</h4>
</section>
<section style="height: 100%">
<div style="display: flex; align-items: flex-start; height: 100%">
@ -34,7 +35,7 @@
<iframe
height="600"
width="800"
src="https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=aa4567f7a97dd255dc4f314ae2b5d63c"
src="https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=7ac62650fd0b942ae5952b0027e0c1ce"
referrerpolicy="no-referrer"
></iframe>
</details>
@ -58,7 +59,7 @@
<p>cargo vs rustc</p>
<div style="display: grid; grid-template-columns: 2fr 1fr 2fr">
<pre><code data-trim>
$ cargo build
$ cargo build -v
</code></pre>
<div style="display: flex; align-items: center">cargo</div>
<div style="display: flex; flex-direction: column; align-items: flex-start">
@ -70,11 +71,11 @@
</div>
</section>
<section>
<h2>so you want to compile a crate</h2>
<h2>what does rustc like, do?</h2>
<h4>a quick overview of the compilation phases</h4>
</section>
<section>
<h2>so you want to compile a crate</h2>
<p>source code:</p>
<h2>it all starts at the source</h2>
<pre><code data-trim>
#[no_mangle]
pub fn add(a: u8, b: u8) -> u8 {
@ -82,6 +83,38 @@
}
</code></pre>
</section>
<section>
<h2>the frontend and the backend</h2>
<div class="mermaid">
<pre>
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
flowchart LR
subgraph compiler
frontend --> backend
end
source --> frontend
backend --> binary
</pre>
</div>
</section>
<section>
<h2>lex, parse, resolve, typecheck, all these fancy things</h2>
<div class="mermaid">
<pre>
%%{init: {'theme': 'dark', 'themeVariables': { 'darkMode': true, 'fontSize': '25px' }}}%%
flowchart TB
function --> return
function --> params
params --> a_def[a]
params --> b_def[b]
function --> body
body --> cl["method call"]
cl --> a_use[a]
cl --> wrapping_add
cl --> b_use[b]
</pre>
</div>
</section>
<section>
<h2>so you want to compile a crate</h2>
<p>MIR</p>
@ -114,6 +147,20 @@
```
</textarea>
</section>
<section data-markdown>
<textarea data-template>
## but compiling a ton of crates can't be that simple!
- yes
</textarea>
</section>
<section data-markdown>
<textarea data-template>
## backend orchestration
- the how, what, and when of invoking LLVM
</textarea>
</section>
<section>
<h2>codegen units</h2>
<pre><code>
@ -129,7 +176,7 @@ fn main() {}
mainll["main (LLVM IR)"]
end
mycgu1 --> mycgu1.rcgu.o
mycgu1 --> |LLVM| mycgu1.rcgu.o
mainmir --> mainll
@ -311,18 +358,6 @@ fn main() { math::add() }
</pre>
</div>
</section>
<section data-markdown>
<textarea data-template>
## instantiation modes
the two ways to instantiate MIR:
- in the definition crate (Globally Shared)
- in the using crate (Local Copy)
- generic functions
- `#[inline]` functions
</textarea>
</section>
<section data-markdown>
<textarea data-template>
## inlining
@ -341,7 +376,7 @@ fn main() { math::add() }
</section>
<section data-markdown>
<textarea data-template>
## inlining
## let's inline it
```rust
fn add(a: u8, b: u8) -> u8 {
@ -364,13 +399,13 @@ fn main() { math::add() }
## cross-crate inlining
```rust
fn add(a: u8, b: u8) -> u8 {
pub fn add(a: u8, b: u8) -> u8 {
a + b
}
```
```rust
fn main() {
let x = add(1, 4); // what is the body?...
let x = math::add(1, 4); // what is the body?...
println!("{x}");
}
```
@ -382,13 +417,13 @@ fn main() { math::add() }
```rust
#[inline]
fn add(a: u8, b: u8) -> u8 {
pub fn add(a: u8, b: u8) -> u8 {
a + b
}
```
```rust
fn main() {
let x = add(1, 4); // 💡 it's a + b
let x = math::add(1, 4); // 💡 it's a + b
println!("{x}");
}
```
@ -398,13 +433,13 @@ fn main() { math::add() }
<div style="display: flex; flex-direction: row; gap: 16px">
<pre><code data-trim class="language-rust">
#[inline]
fn add(a: u8, b: u8) -> u8 {
pub fn add(a: u8, b: u8) -> u8 {
a + b
}
</code></pre>
<pre><code data-trim class="language-rust">
fn main() {
let x = add(1, 4);
let x = math::add(1, 4);
println!("{x}");
}
</code></pre>
@ -441,7 +476,7 @@ fn main() { math::add() }
## `#[inline]`
- `#[inline]` enables cross-crate inlining of non-generic functions
- for very small functions, this happens automatically
- for other functions, it doesn't, because it would be slow
- for other functions, it doesn't, because it would be slow (try with `-Zcross-crate-inline-threshold=always`)
- don't over-apply it in a library, but also don't forget about it
- benchmark!
</textarea>
@ -542,11 +577,11 @@ fn main() { math::add() }
<textarea data-template>
## linker-plugin-lto
- "original" LTO
- like fat LTO
- fat LTO style and thin LTO style
- the merging is not done by rustc but by the linker
- works across languages (Rust (rustc) + C (clang))
- great for FFI
- annoying to set up
</textarea>
</section>
</div>

101
slides/speaker-notes.md Normal file
View file

@ -0,0 +1,101 @@
# how rust compiles
- welcome to my talk about how rust compiles
- we'll take a look at rusts compilation model
- before we get started
- example of confusing behavior arising from the model
- me
- behind cargo build
- we use cargo
- one cargo many rustc per crate
- use -v
- what does rustc do
- source example
- add function that adds
- frontend and backend
- frontend in a single slide
- parse into AST
- resolve, typecheck
- MIR
- intermediate representation
- CFG
- borrow checker
- LLVM IR
- LLVM backend
- clang, swift, julia
- IR to assembly
- optimizes
- Assembly
- machine code
- it's not that simple
- backend orchestration
- how, what, and when invoking LLVM
- codegen unit
- LLVM module/object file
- group of functions
- linked together
- more codegen units
- three functions into two codegen units
- functions grouped into codegen units is complicated
- codegen units cross crate
- a great add function
- add into cgu in math crate
- object file into rlibs
- generics
- mono
- instantiating generics
- MIR to LLVM IR
- generics cross crate
- math crate only MIR
- instantiated in our own crate
- read MIR from rlib
- inlining
- a function call
- inefficient call
- maybe just turn it into 5
- inlining
- very good
- everywhere, or very slow
- cross crate inlining catch
- access to the body
- #[inline]
- why?
- #[inline]
- like a generic function
- instantiated downstream
- #[inline]
- non-generic
- automatically for small
- not for others
- cross-crate-inline-threshold=always
- dont always use it because its slow
- dont forget about it
- benchmark
- if you dont want to worry about this as an application
- LTO
- no cross-crate-inline-threshold
- LTO
- applies optimizations once for everything at the end
- breaks crate boundaries
- slow
- fat LTO
- LLVM IR instead of machine code in libs
- combines all LLVM IR
- this CGU is huge, not parallel
- see everything
- not all optimizations for larger programs
- thin LTO
- confusing name
- try both
- LLVM IR for libs
- for generics, just in instantiating crate
- combine for summary
- summary of function (size and where to find it)
- many different units in parallel
- look at the summary for inlining
- linker plugin LTO
- fat LTO or thin LTO
- not by rustc, but by the linker
- across languages
- LLVM IR from Rust, LLVM IR from clang
- annoying to set up