feat(compress): aggregate MT frame progression in Rust
Move the arithmetic aggregation in ZSTDMT_getFrameProgression across the existing C/Rust boundary. C still owns MT state traversal, mutex locking, jobIDMask ordering, nextJobID plus jobReady handling, error normalization, and the flushed <= produced assertion. Rust constructs the base result and folds each compact, C-normalized job snapshot into the complete repr(C) ZSTD_frameProgression, preserving size_t-to-U64 wrapping and active-worker counting without exposing private job or mutex layouts. Focused Rust tests cover zero jobs, a ready job, completed jobs, normalized error output, and mixed active/completed aggregation. Test Plan: - All three compression clippy commands passed before formatting. - cargo +nightly fmt --manifest-path rust/Cargo.toml -- passed. - All three compression clippy commands passed after formatting. - cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression -- 332 passed. - make -B -C lib -j2 lib-mt -- passed. - make -B -C lib -j2 lib-nomt -- passed. - make -B -C tests -j2 test-zstream -- passed: 84 named, 6,004, and 8,392 randomized cases. - git diff --check and git diff --cached --check -- passed. The zstream build retained the pre-existing warning at tests/zstreamtest.c:1899 about an unterminated initializer string.
This commit is contained in:
@@ -157,6 +157,12 @@ size_t ZSTDMT_rust_sizeofCCtx(size_t mtctxSize, size_t factorySize,
|
||||
size_t bufferPoolSize, size_t jobsSize,
|
||||
size_t cctxPoolSize, size_t seqPoolSize,
|
||||
size_t cdictSize, size_t roundBuffSize);
|
||||
ZSTD_frameProgression ZSTDMT_rust_frameProgression(
|
||||
unsigned long long consumed, size_t inBuffFilled,
|
||||
unsigned long long produced, unsigned currentJobID);
|
||||
ZSTD_frameProgression ZSTDMT_rust_frameProgressionAddJob(
|
||||
ZSTD_frameProgression progression, size_t srcSize, size_t consumed,
|
||||
size_t produced, size_t flushed);
|
||||
|
||||
typedef struct ZSTDMT_bufferPool_s {
|
||||
ZSTDMT_RustBufferPool* rustPool;
|
||||
@@ -1101,13 +1107,10 @@ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_p
|
||||
* Note : mutex will be acquired during statistics collection inside workers. */
|
||||
ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
|
||||
{
|
||||
ZSTD_frameProgression fps;
|
||||
ZSTD_frameProgression fps = ZSTDMT_rust_frameProgression(
|
||||
mtctx->consumed, mtctx->inBuff.filled, mtctx->produced,
|
||||
mtctx->nextJobID);
|
||||
DEBUGLOG(5, "ZSTDMT_getFrameProgression");
|
||||
fps.ingested = mtctx->consumed + mtctx->inBuff.filled;
|
||||
fps.consumed = mtctx->consumed;
|
||||
fps.produced = fps.flushed = mtctx->produced;
|
||||
fps.currentJobID = mtctx->nextJobID;
|
||||
fps.nbActiveWorkers = 0;
|
||||
{ unsigned jobNb;
|
||||
unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1);
|
||||
DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)",
|
||||
@@ -1120,11 +1123,8 @@ ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
|
||||
size_t const produced = ZSTD_isError(cResult) ? 0 : cResult;
|
||||
size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed;
|
||||
assert(flushed <= produced);
|
||||
fps.ingested += jobPtr->src.size;
|
||||
fps.consumed += jobPtr->consumed;
|
||||
fps.produced += produced;
|
||||
fps.flushed += flushed;
|
||||
fps.nbActiveWorkers += (jobPtr->consumed < jobPtr->src.size);
|
||||
fps = ZSTDMT_rust_frameProgressionAddJob(
|
||||
fps, jobPtr->src.size, jobPtr->consumed, produced, flushed);
|
||||
}
|
||||
ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ use std::os::raw::{c_int, c_uint, c_void};
|
||||
use std::ptr;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::zstd_compress::ZSTD_frameProgression;
|
||||
|
||||
const ZSTDMT_JOBLOG_MAX: c_uint = if mem::size_of::<usize>() == 4 { 29 } else { 30 };
|
||||
const ZSTD_WINDOWLOG_MAX: c_uint = if mem::size_of::<usize>() == 4 { 30 } else { 31 };
|
||||
|
||||
@@ -146,6 +148,65 @@ pub extern "C" fn ZSTDMT_rust_computeOverlapSize(
|
||||
compute_overlap_size(windowLog, chainLog, strategy, overlapLog, enableLdm)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn frame_progression(
|
||||
consumed: u64,
|
||||
in_buff_filled: usize,
|
||||
produced: u64,
|
||||
current_job_id: c_uint,
|
||||
) -> ZSTD_frameProgression {
|
||||
ZSTD_frameProgression {
|
||||
// C's usual arithmetic conversions promote size_t to U64 before wrapping.
|
||||
ingested: consumed.wrapping_add(in_buff_filled as u64),
|
||||
consumed,
|
||||
produced,
|
||||
flushed: produced,
|
||||
currentJobID: current_job_id,
|
||||
nbActiveWorkers: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn frame_progression_add_job(
|
||||
mut progression: ZSTD_frameProgression,
|
||||
src_size: usize,
|
||||
consumed: usize,
|
||||
produced: usize,
|
||||
flushed: usize,
|
||||
) -> ZSTD_frameProgression {
|
||||
progression.ingested = progression.ingested.wrapping_add(src_size as u64);
|
||||
progression.consumed = progression.consumed.wrapping_add(consumed as u64);
|
||||
progression.produced = progression.produced.wrapping_add(produced as u64);
|
||||
progression.flushed = progression.flushed.wrapping_add(flushed as u64);
|
||||
progression.nbActiveWorkers = progression
|
||||
.nbActiveWorkers
|
||||
.wrapping_add((consumed < src_size) as c_uint);
|
||||
progression
|
||||
}
|
||||
|
||||
/// Construct the base MT frame progression from C-owned scalar state.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ZSTDMT_rust_frameProgression(
|
||||
consumed: u64,
|
||||
in_buff_filled: usize,
|
||||
produced: u64,
|
||||
current_job_id: c_uint,
|
||||
) -> ZSTD_frameProgression {
|
||||
frame_progression(consumed, in_buff_filled, produced, current_job_id)
|
||||
}
|
||||
|
||||
/// Add one C-normalized, mutex-protected job snapshot to MT frame progression.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ZSTDMT_rust_frameProgressionAddJob(
|
||||
progression: ZSTD_frameProgression,
|
||||
src_size: usize,
|
||||
consumed: usize,
|
||||
produced: usize,
|
||||
flushed: usize,
|
||||
) -> ZSTD_frameProgression {
|
||||
frame_progression_add_job(progression, src_size, consumed, produced, flushed)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn rolling_hash_append(mut hash: u64, input: *const u8, size: usize) -> u64 {
|
||||
for pos in 0..size {
|
||||
@@ -1093,6 +1154,77 @@ mod tests {
|
||||
assert_eq!(ZSTDMT_rust_rollingHashPrimePower(0), 0x12A9_3A33_31E0_3D4B);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_progression_zero_jobs_keeps_mt_base_values() {
|
||||
assert_eq!(
|
||||
ZSTDMT_rust_frameProgression(11, 7, 13, 4),
|
||||
ZSTD_frameProgression {
|
||||
ingested: 18,
|
||||
consumed: 11,
|
||||
produced: 13,
|
||||
flushed: 13,
|
||||
currentJobID: 4,
|
||||
nbActiveWorkers: 0,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_progression_one_ready_job_counts_as_active() {
|
||||
let base = ZSTDMT_rust_frameProgression(100, 20, 300, 9);
|
||||
assert_eq!(
|
||||
ZSTDMT_rust_frameProgressionAddJob(base, 80, 17, 42, 10),
|
||||
ZSTD_frameProgression {
|
||||
ingested: 200,
|
||||
consumed: 117,
|
||||
produced: 342,
|
||||
flushed: 310,
|
||||
currentJobID: 9,
|
||||
nbActiveWorkers: 1,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_progression_completed_job_is_not_active() {
|
||||
let base = ZSTDMT_rust_frameProgression(100, 20, 300, 9);
|
||||
let progression = ZSTDMT_rust_frameProgressionAddJob(base, 80, 80, 42, 42);
|
||||
|
||||
assert_eq!(progression.nbActiveWorkers, 0);
|
||||
assert_eq!(progression.ingested, 200);
|
||||
assert_eq!(progression.consumed, 180);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_progression_error_job_uses_normalized_zero_output() {
|
||||
let base = ZSTDMT_rust_frameProgression(100, 20, 300, 9);
|
||||
let progression = ZSTDMT_rust_frameProgressionAddJob(base, 80, 0, 0, 0);
|
||||
|
||||
assert_eq!(progression.produced, 300);
|
||||
assert_eq!(progression.flushed, 300);
|
||||
assert_eq!(progression.nbActiveWorkers, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_progression_aggregates_active_and_completed_jobs() {
|
||||
let base = ZSTDMT_rust_frameProgression(100, 20, 300, 9);
|
||||
let progression = ZSTDMT_rust_frameProgressionAddJob(base, 80, 17, 42, 10);
|
||||
let progression = ZSTDMT_rust_frameProgressionAddJob(progression, 30, 30, 8, 8);
|
||||
let progression = ZSTDMT_rust_frameProgressionAddJob(progression, 40, 5, 7, 6);
|
||||
|
||||
assert_eq!(
|
||||
progression,
|
||||
ZSTD_frameProgression {
|
||||
ingested: 270,
|
||||
consumed: 152,
|
||||
produced: 357,
|
||||
flushed: 324,
|
||||
currentJobID: 9,
|
||||
nbActiveWorkers: 2,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fn call_synchronization_point(
|
||||
input: &[u8],
|
||||
input_pos: usize,
|
||||
|
||||
Reference in New Issue
Block a user