Skip to content

Commit 87e0726

Browse files
authored
blocks: split macro into multiple functions, fast! (#267)
Improves fix for #184, whereas #255 reduced optimizations, we now address the underlying compiler limitation and split out the one massive lazy_static! initialization function, into one function per block in the block_registration_functions module. Previous build time, with opt-level=1: % time cargo build --release Compiling steven_blocks v0.0.1 Finished release [optimized] target(s) in 21.24s cargo build --release 31.80s user 0.71s system 152% cpu 21.276 total With this change, opt-level=3 and the function splitting fix: % time cargo build --release Compiling steven_blocks v0.0.1 Finished release [optimized] target(s) in 30.80s cargo build --release 40.26s user 0.86s system 133% cpu 30.850 total Full optimizations are expectedly slightly slower, but this is still much much _much_ faster than before this refactoring, where this crate would take up to an unbelievable 5 hours (and tens of GB of RAM). Long story short, we're now back to full optimizations and stable Rust. Thanks to dtolnay on the Rust programming language forum for suggesting this technique, https://users.rust-lang.org/t/5-hours-to-compile-macro-what-can-i-do/36508/2
1 parent 643de31 commit 87e0726

File tree

6 files changed

+57
-41
lines changed

6 files changed

+57
-41
lines changed

.build.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ tasks:
1212
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh
1313
sh ./rustup.sh -y
1414
source $HOME/.cargo/env
15-
rustup install nightly
16-
cargo +nightly --version
15+
cargo --version
1716
- build: |
1817
source $HOME/.cargo/env
1918
cd stevenarella
20-
cargo +nightly build
21-
cargo +nightly test
19+
cargo build
20+
cargo test

Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ path = "src/main.rs"
1717
# Use an -O1 optimization level strikes a good compromise between build and program performance.
1818
opt-level = 1
1919

20-
[profile.release.package.steven_blocks]
21-
opt-level = 1
22-
2320
[dependencies]
2421
cfg-if = "0.1.9"
2522
wasm-bindgen = "0.2.44"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ The Visual Studio 2017 Redistributable is required to run these builds.
6666

6767
## Building
6868

69-
Requires Rust nightly version `rustc 1.42.0-nightly (760ce94c6 2020-01-04)` or newer to build.
69+
Requires Rust stable version 1.40.0 or newer to build.
7070

7171
Compile and run:
7272
```bash

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ build_script:
2121
2222
appveyor AddMessage "Platform rust: %RUST_INSTALL%"
2323
24-
appveyor DownloadFile "https://static.rust-lang.org/dist/rust-nightly-%RUST_INSTALL%.exe" -FileName rust-install.exe
24+
appveyor DownloadFile "https://static.rust-lang.org/dist/rust-1.40.0-%RUST_INSTALL%.exe" -FileName rust-install.exe
2525
2626
"./rust-install.exe" /VERYSILENT /NORESTART /DIR="C:\Rust\"
2727

blocks/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ version = "0.0.1"
44
authors = [ "Thinkofdeath <[email protected]>" ]
55
edition = "2018"
66

7-
[profile.release]
8-
opt-level = 1
9-
107
[dependencies]
118
lazy_static = "1.4.0"
129
cgmath = "0.17.0"

blocks/src/lib.rs

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -288,15 +288,18 @@ macro_rules! define_blocks {
288288
}
289289
}
290290

291-
lazy_static! {
292-
static ref VANILLA_ID_MAP: VanillaIDMap = {
293-
let mut blocks_flat = vec![];
294-
let mut blocks_hier = vec![];
295-
let mut blocks_modded: HashMap<String, [Option<Block>; 16]> = HashMap::new();
296-
let mut flat_id = 0;
297-
let mut last_internal_id = 0;
298-
let mut hier_block_id = 0;
299-
$({
291+
mod block_registration_functions {
292+
use super::*;
293+
$(
294+
#[allow(non_snake_case)]
295+
pub fn $name(
296+
blocks_flat: &mut Vec<Option<Block>>,
297+
blocks_hier: &mut Vec<Option<Block>>,
298+
blocks_modded: &mut HashMap<String, [Option<Block>; 16]>,
299+
flat_id: &mut usize,
300+
last_internal_id: &mut usize,
301+
hier_block_id: &mut usize,
302+
) {
300303
#[allow(non_camel_case_types, dead_code)]
301304
struct CombinationIter<$($fname),*> {
302305
first: bool,
@@ -391,28 +394,28 @@ macro_rules! define_blocks {
391394
let hier_data: Option<usize> = block.get_hierarchical_data();
392395
if let Some(modid) = block.get_modid() {
393396
let hier_data = hier_data.unwrap();
394-
if !blocks_modded.contains_key(modid) {
395-
blocks_modded.insert(modid.to_string(), [None; 16]);
397+
if !(*blocks_modded).contains_key(modid) {
398+
(*blocks_modded).insert(modid.to_string(), [None; 16]);
396399
}
397-
let block_from_data = blocks_modded.get_mut(modid).unwrap();
400+
let block_from_data = (*blocks_modded).get_mut(modid).unwrap();
398401
block_from_data[hier_data] = Some(block);
399402
continue
400403
}
401404

402405
let vanilla_id =
403406
if let Some(hier_data) = hier_data {
404-
if internal_id != last_internal_id {
405-
hier_block_id += 1;
407+
if internal_id != *last_internal_id {
408+
*hier_block_id += 1;
406409
}
407-
last_internal_id = internal_id;
408-
Some((hier_block_id << 4) + hier_data)
410+
*last_internal_id = internal_id;
411+
Some((*hier_block_id << 4) + hier_data)
409412
} else {
410413
None
411414
};
412415

413416
let offset = block.get_flat_offset();
414417
if let Some(offset) = offset {
415-
let id = flat_id + offset;
418+
let id = *flat_id + offset;
416419
/*
417420
if let Some(vanilla_id) = vanilla_id {
418421
debug!("{} block state = {:?} hierarchical {}:{} offset={}", id, block, vanilla_id >> 4, vanilla_id & 0xF, offset);
@@ -424,17 +427,17 @@ macro_rules! define_blocks {
424427
last_offset = offset as isize;
425428
}
426429

427-
if blocks_flat.len() <= id {
428-
blocks_flat.resize(id + 1, None);
430+
if (*blocks_flat).len() <= id {
431+
(*blocks_flat).resize(id + 1, None);
429432
}
430-
if blocks_flat[id].is_none() {
431-
blocks_flat[id] = Some(block);
433+
if (*blocks_flat)[id].is_none() {
434+
(*blocks_flat)[id] = Some(block);
432435
} else {
433436
panic!(
434437
"Tried to register {:#?} to {} but {:#?} was already registered",
435438
block,
436439
id,
437-
blocks_flat[id]
440+
(*blocks_flat)[id]
438441
);
439442
}
440443
}
@@ -446,27 +449,47 @@ macro_rules! define_blocks {
446449
}
447450
*/
448451

449-
if blocks_hier.len() <= vanilla_id {
450-
blocks_hier.resize(vanilla_id + 1, None);
452+
if (*blocks_hier).len() <= vanilla_id {
453+
(*blocks_hier).resize(vanilla_id + 1, None);
451454
}
452-
if blocks_hier[vanilla_id].is_none() {
453-
blocks_hier[vanilla_id] = Some(block);
455+
if (*blocks_hier)[vanilla_id].is_none() {
456+
(*blocks_hier)[vanilla_id] = Some(block);
454457
} else {
455458
panic!(
456459
"Tried to register {:#?} to {} but {:#?} was already registered",
457460
block,
458461
vanilla_id,
459-
blocks_hier[vanilla_id]
462+
(*blocks_hier)[vanilla_id]
460463
);
461464
}
462465
}
463466
}
464467

465468
#[allow(unused_assignments)]
466469
{
467-
flat_id += (last_offset + 1) as usize;
470+
*flat_id += (last_offset + 1) as usize;
468471
}
469-
})+
472+
}
473+
)+
474+
}
475+
476+
lazy_static! {
477+
static ref VANILLA_ID_MAP: VanillaIDMap = {
478+
let mut blocks_flat = vec![];
479+
let mut blocks_hier = vec![];
480+
let mut blocks_modded: HashMap<String, [Option<Block>; 16]> = HashMap::new();
481+
let mut flat_id = 0;
482+
let mut last_internal_id = 0;
483+
let mut hier_block_id = 0;
484+
485+
$(
486+
block_registration_functions::$name(&mut blocks_flat,
487+
&mut blocks_hier,
488+
&mut blocks_modded,
489+
&mut flat_id,
490+
&mut last_internal_id,
491+
&mut hier_block_id);
492+
)+
470493

471494
VanillaIDMap { flat: blocks_flat, hier: blocks_hier, modded: blocks_modded }
472495
};

0 commit comments

Comments
 (0)