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
This commit is contained in:
parent
643de31073
commit
87e0726f3f
|
@ -12,10 +12,9 @@ tasks:
|
|||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh
|
||||
sh ./rustup.sh -y
|
||||
source $HOME/.cargo/env
|
||||
rustup install nightly
|
||||
cargo +nightly --version
|
||||
cargo --version
|
||||
- build: |
|
||||
source $HOME/.cargo/env
|
||||
cd stevenarella
|
||||
cargo +nightly build
|
||||
cargo +nightly test
|
||||
cargo build
|
||||
cargo test
|
||||
|
|
|
@ -17,9 +17,6 @@ path = "src/main.rs"
|
|||
# Use an -O1 optimization level strikes a good compromise between build and program performance.
|
||||
opt-level = 1
|
||||
|
||||
[profile.release.package.steven_blocks]
|
||||
opt-level = 1
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "0.1.9"
|
||||
wasm-bindgen = "0.2.44"
|
||||
|
|
|
@ -66,7 +66,7 @@ The Visual Studio 2017 Redistributable is required to run these builds.
|
|||
|
||||
## Building
|
||||
|
||||
Requires Rust nightly version `rustc 1.42.0-nightly (760ce94c6 2020-01-04)` or newer to build.
|
||||
Requires Rust stable version 1.40.0 or newer to build.
|
||||
|
||||
Compile and run:
|
||||
```bash
|
||||
|
|
|
@ -21,7 +21,7 @@ build_script:
|
|||
|
||||
appveyor AddMessage "Platform rust: %RUST_INSTALL%"
|
||||
|
||||
appveyor DownloadFile "https://static.rust-lang.org/dist/rust-nightly-%RUST_INSTALL%.exe" -FileName rust-install.exe
|
||||
appveyor DownloadFile "https://static.rust-lang.org/dist/rust-1.40.0-%RUST_INSTALL%.exe" -FileName rust-install.exe
|
||||
|
||||
"./rust-install.exe" /VERYSILENT /NORESTART /DIR="C:\Rust\"
|
||||
|
||||
|
|
|
@ -4,9 +4,6 @@ version = "0.0.1"
|
|||
authors = [ "Thinkofdeath <thinkofdeath@spigotmc.org>" ]
|
||||
edition = "2018"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 1
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
cgmath = "0.17.0"
|
||||
|
|
|
@ -288,15 +288,18 @@ macro_rules! define_blocks {
|
|||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref VANILLA_ID_MAP: VanillaIDMap = {
|
||||
let mut blocks_flat = vec![];
|
||||
let mut blocks_hier = vec![];
|
||||
let mut blocks_modded: HashMap<String, [Option<Block>; 16]> = HashMap::new();
|
||||
let mut flat_id = 0;
|
||||
let mut last_internal_id = 0;
|
||||
let mut hier_block_id = 0;
|
||||
$({
|
||||
mod block_registration_functions {
|
||||
use super::*;
|
||||
$(
|
||||
#[allow(non_snake_case)]
|
||||
pub fn $name(
|
||||
blocks_flat: &mut Vec<Option<Block>>,
|
||||
blocks_hier: &mut Vec<Option<Block>>,
|
||||
blocks_modded: &mut HashMap<String, [Option<Block>; 16]>,
|
||||
flat_id: &mut usize,
|
||||
last_internal_id: &mut usize,
|
||||
hier_block_id: &mut usize,
|
||||
) {
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
struct CombinationIter<$($fname),*> {
|
||||
first: bool,
|
||||
|
@ -391,28 +394,28 @@ macro_rules! define_blocks {
|
|||
let hier_data: Option<usize> = block.get_hierarchical_data();
|
||||
if let Some(modid) = block.get_modid() {
|
||||
let hier_data = hier_data.unwrap();
|
||||
if !blocks_modded.contains_key(modid) {
|
||||
blocks_modded.insert(modid.to_string(), [None; 16]);
|
||||
if !(*blocks_modded).contains_key(modid) {
|
||||
(*blocks_modded).insert(modid.to_string(), [None; 16]);
|
||||
}
|
||||
let block_from_data = blocks_modded.get_mut(modid).unwrap();
|
||||
let block_from_data = (*blocks_modded).get_mut(modid).unwrap();
|
||||
block_from_data[hier_data] = Some(block);
|
||||
continue
|
||||
}
|
||||
|
||||
let vanilla_id =
|
||||
if let Some(hier_data) = hier_data {
|
||||
if internal_id != last_internal_id {
|
||||
hier_block_id += 1;
|
||||
if internal_id != *last_internal_id {
|
||||
*hier_block_id += 1;
|
||||
}
|
||||
last_internal_id = internal_id;
|
||||
Some((hier_block_id << 4) + hier_data)
|
||||
*last_internal_id = internal_id;
|
||||
Some((*hier_block_id << 4) + hier_data)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let offset = block.get_flat_offset();
|
||||
if let Some(offset) = offset {
|
||||
let id = flat_id + offset;
|
||||
let id = *flat_id + offset;
|
||||
/*
|
||||
if let Some(vanilla_id) = vanilla_id {
|
||||
debug!("{} block state = {:?} hierarchical {}:{} offset={}", id, block, vanilla_id >> 4, vanilla_id & 0xF, offset);
|
||||
|
@ -424,17 +427,17 @@ macro_rules! define_blocks {
|
|||
last_offset = offset as isize;
|
||||
}
|
||||
|
||||
if blocks_flat.len() <= id {
|
||||
blocks_flat.resize(id + 1, None);
|
||||
if (*blocks_flat).len() <= id {
|
||||
(*blocks_flat).resize(id + 1, None);
|
||||
}
|
||||
if blocks_flat[id].is_none() {
|
||||
blocks_flat[id] = Some(block);
|
||||
if (*blocks_flat)[id].is_none() {
|
||||
(*blocks_flat)[id] = Some(block);
|
||||
} else {
|
||||
panic!(
|
||||
"Tried to register {:#?} to {} but {:#?} was already registered",
|
||||
block,
|
||||
id,
|
||||
blocks_flat[id]
|
||||
(*blocks_flat)[id]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -446,17 +449,17 @@ macro_rules! define_blocks {
|
|||
}
|
||||
*/
|
||||
|
||||
if blocks_hier.len() <= vanilla_id {
|
||||
blocks_hier.resize(vanilla_id + 1, None);
|
||||
if (*blocks_hier).len() <= vanilla_id {
|
||||
(*blocks_hier).resize(vanilla_id + 1, None);
|
||||
}
|
||||
if blocks_hier[vanilla_id].is_none() {
|
||||
blocks_hier[vanilla_id] = Some(block);
|
||||
if (*blocks_hier)[vanilla_id].is_none() {
|
||||
(*blocks_hier)[vanilla_id] = Some(block);
|
||||
} else {
|
||||
panic!(
|
||||
"Tried to register {:#?} to {} but {:#?} was already registered",
|
||||
block,
|
||||
vanilla_id,
|
||||
blocks_hier[vanilla_id]
|
||||
(*blocks_hier)[vanilla_id]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -464,9 +467,29 @@ macro_rules! define_blocks {
|
|||
|
||||
#[allow(unused_assignments)]
|
||||
{
|
||||
flat_id += (last_offset + 1) as usize;
|
||||
*flat_id += (last_offset + 1) as usize;
|
||||
}
|
||||
})+
|
||||
}
|
||||
)+
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref VANILLA_ID_MAP: VanillaIDMap = {
|
||||
let mut blocks_flat = vec![];
|
||||
let mut blocks_hier = vec![];
|
||||
let mut blocks_modded: HashMap<String, [Option<Block>; 16]> = HashMap::new();
|
||||
let mut flat_id = 0;
|
||||
let mut last_internal_id = 0;
|
||||
let mut hier_block_id = 0;
|
||||
|
||||
$(
|
||||
block_registration_functions::$name(&mut blocks_flat,
|
||||
&mut blocks_hier,
|
||||
&mut blocks_modded,
|
||||
&mut flat_id,
|
||||
&mut last_internal_id,
|
||||
&mut hier_block_id);
|
||||
)+
|
||||
|
||||
VanillaIDMap { flat: blocks_flat, hier: blocks_hier, modded: blocks_modded }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue