minedmap: add support for parallel processing

For now, only RegionProcessor and TileMipmapper are run in parallel.
This commit is contained in:
Matthias Schiffer 2023-08-14 15:48:05 +02:00
parent c1260a63b5
commit 78fe1ec50e
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
6 changed files with 191 additions and 11 deletions

View file

@ -52,6 +52,7 @@ pub struct ProcessedRegion {
}
pub struct Config {
pub num_threads: usize,
pub region_dir: PathBuf,
pub processed_dir: PathBuf,
pub output_dir: PathBuf,
@ -70,16 +71,23 @@ pub enum TileKind {
}
impl Config {
pub fn new(args: super::Args) -> Self {
pub fn new(args: &super::Args) -> Self {
let num_threads = match args.jobs {
Some(0) => num_cpus::get(),
Some(threads) => threads,
None => 1,
};
let region_dir = [&args.input_dir, Path::new("region")].iter().collect();
let processed_dir = [&args.output_dir, Path::new("processed")].iter().collect();
let level_dat_path = [&args.input_dir, Path::new("level.dat")].iter().collect();
let metadata_path = [&args.output_dir, Path::new("info.json")].iter().collect();
Config {
num_threads,
region_dir,
processed_dir,
output_dir: args.output_dir,
output_dir: args.output_dir.clone(),
level_dat_path,
metadata_path,
}

View file

@ -7,7 +7,7 @@ mod tile_renderer;
use std::path::PathBuf;
use anyhow::Result;
use anyhow::{Context, Result};
use clap::Parser;
use common::Config;
@ -18,15 +18,30 @@ use tile_renderer::TileRenderer;
#[derive(Debug, Parser)]
pub struct Args {
/// Number of parallel threads to use for processing
///
/// If not given, only a single thread is used. Pass 0 to
/// use one thread per logical CPU core.
#[arg(short, long)]
pub jobs: Option<usize>,
/// Minecraft save directory
pub input_dir: PathBuf,
/// MinedMap data directory
pub output_dir: PathBuf,
}
fn setup_threads(num_threads: usize) -> Result<()> {
rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
.build_global()
.context("Failed to configure thread pool")
}
fn main() -> Result<()> {
let args = Args::parse();
let config = Config::new(args);
let config = Config::new(&args);
setup_threads(config.num_threads)?;
let regions = RegionProcessor::new(&config).run()?;
TileRenderer::new(&config).run(&regions)?;

View file

@ -1,8 +1,9 @@
use std::{ffi::OsStr, path::Path, time::SystemTime};
use anyhow::{Context, Result};
use indexmap::IndexSet;
use rayon::prelude::*;
use minedmap::{
io::{fs, storage},
resource::{self, Biome},
@ -183,11 +184,11 @@ impl<'a> RegionProcessor<'a> {
fs::create_dir_all(&self.config.processed_dir)?;
fs::create_dir_all(&self.config.tile_dir(TileKind::Lightmap, 0))?;
for &coords in &regions {
regions.par_iter().for_each(|&coords| {
if let Err(err) = self.process_region(coords) {
eprintln!("Failed to process region {:?}: {:?}", coords, err);
}
}
});
Ok(regions)
}

View file

@ -1,4 +1,5 @@
use anyhow::{Context, Result};
use rayon::prelude::*;
use minedmap::{io::fs, types::*};
@ -151,8 +152,8 @@ impl<'a> TileMipmapper<'a> {
let next = Self::map_coords(prev);
for (&z, xs) in &next.0 {
for &x in xs {
next.0.par_iter().try_for_each(|(&z, xs)| {
xs.par_iter().try_for_each(|&x| {
let coords = TileCoords { x, z };
self.render_mipmap::<image::Rgba<u8>>(TileKind::Map, level, coords, prev)?;
self.render_mipmap::<image::LumaA<u8>>(
@ -161,8 +162,9 @@ impl<'a> TileMipmapper<'a> {
coords,
prev,
)?;
}
}
anyhow::Ok(())
})
})?;
tile_stack.push(next);
}