geolith vs Planetiler
geolith was benchmarked head-to-head against Planetiler (Java) on identical input data and region bounds.
Test Configuration
| Parameter | Value |
|---|---|
| Region | Western India (67.67,14.39,80.92,24.72) |
| Max zoom | 15 |
| OSM PBF | western-zone-latest.osm.pbf (196 MB) |
| Overture | Buildings + Divisions (hive-partitioned GeoParquet) |
| India boundary | GeoJSON |
| Natural Earth | SQLite |
| Land polygons | Shapefile (EPSG:3857) |
| Water polygons | Shapefile (EPSG:3857) |
| Machine | Apple M2 Max, 96 GB RAM, NVMe SSD |
Both tools processed the same layers: earth, water, boundaries, landuse, roads, transit, buildings, places, pois, and divisions. Planetiler additionally processed daylight landcover (0.3s wall time, negligible impact).
Results
| Metric | geolith (Rust) | Planetiler (Java) |
|---|---|---|
| Wall time | 5:15 | 6:20 |
| CPU time (user) | 709s | 3,343s |
| CPU utilization | 297% | 895% |
| Output size | 2.0 GB | 3.4 GB |
| Peak memory | ~2 GB | 25 GB (-Xmx24g) |
| Tiles written | 1,612,666 | — |
Summary
- 17% faster wall time (5:15 vs 6:20)
- 4.7x less CPU time (709s vs 3,343s)
- 41% smaller output (2.0 GB vs 3.4 GB)
- ~12x less memory (~2 GB vs 25 GB heap)
geolith achieves competitive performance with significantly lower resource usage. The smaller output is primarily due to tile content deduplication and efficient MVT encoding.
Phase Breakdown (geolith)
| Phase | Duration | Details |
|---|---|---|
| Phase 1: Overture GeoParquet | ~52s | 6.4M features read, 66.3M tile features |
| Phase 1: OSM PBF (2-pass) | ~25s | 31.8M nodes, 3.8M features |
| Phase 1: Natural Earth | <1s | 18,939 features from 12 tables |
| Phase 1: Land polygons | ~78s | 833K polygons from shapefile |
| Phase 1: Water polygons | ~90s | 14.5K polygons from shapefile |
| Phase 1: India boundary | ~2s | 1 GeoJSON feature |
| Phase 2: External sort | <1s | 34 LZ4-compressed chunks, k-way merge |
| Phase 3: Tile encode | ~50s | 1,612,666 tiles, gzip compressed |
| Total | 5:15 | 9.5M input features, 77.5M tile features |
geolith CLI
geolith \
--data ./overture-data/ \
--osm-pbf western-zone-latest.osm.pbf \
--natural-earth natural_earth_vector.sqlite \
--land-polygons ./land-polygons-split-3857/ \
--water-polygons ./water-polygons-split-3857/ \
--india-boundary india-boundary.geojson \
--output western-zone.pmtiles \
--bbox 67.67,14.39,80.92,24.72 \
--max-zoom 15 \
--node-cache
Planetiler CLI
java -Xmx24g -jar protomaps-basemap-HEAD-with-deps.jar \
--osm-path=western-zone-latest.osm.pbf \
--output=western-zone-planetiler.pmtiles \
--bounds=67.67,14.39,80.92,24.72 \
--buildings_source=overture \
--overture_buildings_path=./overture-buildings/ \
--divisions_source=overture \
--overture_divisions_path=./overture-divisions/ \
--india_boundary_path=india-boundary.geojson \
--nodemap-type=sparsearray --nodemap-storage=mmap \
--download --force
Expected Performance
| Dataset | Size | Zoom | Time | Output | Machine |
|---|---|---|---|---|---|
| Regional (western India) | ~196 MB OSM + Overture | 15 | ~5 min | ~2 GB PMTiles | M2 Max, 96 GB RAM |
| Regional (India full) | ~5 GB OSM + Overture | 15 | ~15–25 min | ~5–8 GB PMTiles | M2 Max, 96 GB RAM |
| Planet (all themes) | ~70 GB OSM + ~290 GB Overture | 15 | TBD | TBD | 32 cores, 64 GB RAM, NVMe |
Planet-scale benchmarks are planned. The regional result above demonstrates geolith already outperforms Planetiler on identical workloads.
Bottlenecks
Performance is typically bound by one of three factors:
- Disk I/O — Reading GeoParquet/PBF input and writing temporary sort files. Use NVMe SSDs for the data directory and
--tmpdir. - CPU — Feature processing (projection, clipping, simplification) is parallelized via rayon. More cores = faster processing.
- Memory — External sort keeps memory usage bounded. The main memory consumers are the Parquet reader buffers and the OSM node store.
Tuning Recommendations
| Factor | Recommendation |
|---|---|
| Disk speed | NVMe SSD for --data, --tmpdir, and --output paths |
| Thread count | Default (all cores) is usually optimal. Reduce with --threads if sharing the machine. |
| Temp directory | Place on the fastest available disk. Avoid network mounts. |
| Max zoom | Each additional zoom level roughly quadruples tile count. See Output Tuning. |
| Node cache | Use --node-cache to skip OSM pass 1 on subsequent runs with the same PBF. |
Running Micro-Benchmarks
# Run the full benchmark suite
cargo bench
# Run a specific benchmark file
cargo bench --bench tile_encode
# Filter by benchmark name
cargo bench -- "encode_tile"
Micro-benchmarks use Criterion.rs for statistical analysis. Results include confidence intervals and regression detection. Reports are saved to target/criterion/ with HTML visualizations.