Skip to content

Commit af1c507

Browse files
committed
feat(max_perf): enable fast_lzma
1 parent c39fdcb commit af1c507

File tree

4 files changed

+45
-3
lines changed

4 files changed

+45
-3
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ As a proof of concept, chd-rs implements an *extremely* basic reimplementation o
126126
The results from rchdman should be identical from chdman. rchdman is intended to be basic and does not implement multithreading or other functions, so in general it is slower than chdman. There are
127127
no plans to implement write-operations into rchdman.
128128

129+
## Performance
130+
By default, chd-rs uses pure Rust codecs but if maximum performance is needed, `max_perf` can be enabled. This enables the zlib-ng backend of [flate2](https://crates.io/crates/flate2)
131+
as well as using experimental APIs in a custom [lzma-rs fork](https://github.com/SnowflakePowered/lzma-rs/tree/feature-perf-experiments) for some improvements in
132+
performance at the expense of higher memory usage. Combined with `codegen-units=1` and [Profile Guided Optimization](https://github.com/vadimcn/cargo-pgo), chd-rs is within 1% of libchdr performance.
133+
134+
Without `max_perf`, chd-rs is already within 15% of libchdr without needing to link with C libraries like zlib-ng.
135+
129136
## `libchdr` API
130137
⚠️*The C API has not been heavily tested. Use at your own risk.* ⚠️
131138

chd-rs/src/compression/lzma.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ impl CompressionCodecType for LzmaCodec {
100100
}
101101
}
102102

103+
#[cfg(not(feature = "fast_lzma"))]
103104
impl CodecImplementation for LzmaCodec {
104105
fn new(hunk_size: u32) -> Result<Self> {
105106
Ok(LzmaCodec {
@@ -129,3 +130,37 @@ impl CodecImplementation for LzmaCodec {
129130
Ok(DecompressResult::new(len, read.position() as usize))
130131
}
131132
}
133+
134+
#[cfg(feature = "fast_lzma")]
135+
impl CodecImplementation for LzmaCodec {
136+
fn new(hunk_size: u32) -> Result<Self> {
137+
let dict_size = get_lzma_dict_size(9, hunk_size);
138+
Ok(LzmaCodec {
139+
engine: LzmaDecoder::new_with_buffer(
140+
LzmaParams::new(
141+
LzmaProperties {
142+
lc: 3,
143+
lp: 0,
144+
pb: 2,
145+
},
146+
dict_size,
147+
None,
148+
),
149+
None,
150+
vec![0; dict_size as usize],
151+
)
152+
.map_err(|_| Error::DecompressionError)?,
153+
})
154+
}
155+
156+
fn decompress(&mut self, input: &[u8], mut output: &mut [u8]) -> Result<DecompressResult> {
157+
use lzma_rs::decompress::raw::LzAccumBuffer;
158+
let mut read = Cursor::new(input);
159+
let len = output.len();
160+
self.engine.reset(Some(Some(len as u64)));
161+
self.engine
162+
.decompress_with_buffer::<LzAccumBuffer<_>, _, _>(&mut read, &mut output)
163+
.map_err(|_| Error::DecompressionError)?;
164+
Ok(DecompressResult::new(len, read.position() as usize))
165+
}
166+
}

rchdman/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ edition = "2021"
55
publish = false
66

77
[dependencies]
8-
chd = { path = "../chd-rs", features = ["unstable_lending_iterators"]}
8+
chd = { path = "../chd-rs", features = ["unstable_lending_iterators", "max_perf"]}
99
clap = { version = "3", features = ["derive"] }
1010
anyhow = "1"
1111
thousands = "0.2.0"

rchdman/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use anyhow::anyhow;
22
use chd::header::{CodecType, Header};
33
use chd::iter::LendingIterator;
4-
use chd::map::{CompressionTypeLegacy, MapEntry, CompressionTypeV5};
4+
use chd::map::{CompressionTypeLegacy, CompressionTypeV5, MapEntry};
5+
use chd::metadata::Metadata;
56
use chd::Chd;
67
use clap::{Parser, Subcommand};
78
use num_traits::cast::FromPrimitive;
@@ -12,7 +13,6 @@ use std::io::{BufReader, BufWriter, Read, Seek, Write};
1213
use std::path::{Path, PathBuf};
1314
use std::time::Instant;
1415
use thousands::Separable;
15-
use chd::metadata::Metadata;
1616

1717
fn validate_file_exists(s: &OsStr) -> Result<PathBuf, std::io::Error> {
1818
let path = PathBuf::from(s);

0 commit comments

Comments
 (0)