feat(compress): move trace record construction to Rust
Keep the compression context extraction and the weak trace hook adapter in C, where the private CCtx layout and platform-specific tracing declarations remain available. Project only the scalar trace inputs and callback through an explicit ABI-checked boundary so Rust owns the enabled check, stable record layout, version field, compression-only null fields, and end-of-trace policy. The C entry point still clears traceCtx after Rust returns, preserving the old single-use lifecycle and keeping trace-disabled builds free of weak-hook calls. Test Plan: - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo check --manifest-path rust/Cargo.toml --tests - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040; CARGO_BUILD_JOBS=1 make -j1 - ulimit -v 41943040; make -j1 -C tests test
This commit is contained in:
@@ -7284,23 +7284,72 @@ size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*ZSTD_rust_traceEnd_f)(
|
||||||
|
void* context, unsigned long long traceCtx, const void* trace);
|
||||||
|
typedef struct {
|
||||||
|
void* callbackContext;
|
||||||
|
unsigned long long traceCtx;
|
||||||
|
int streaming;
|
||||||
|
unsigned dictionaryID;
|
||||||
|
size_t dictionarySize;
|
||||||
|
size_t uncompressedSize;
|
||||||
|
size_t compressedSize;
|
||||||
|
const void* params;
|
||||||
|
const void* cctx;
|
||||||
|
ZSTD_rust_traceEnd_f traceEnd;
|
||||||
|
} ZSTD_rust_traceEndState;
|
||||||
|
typedef char ZSTD_rust_trace_end_state_layout[
|
||||||
|
(offsetof(ZSTD_rust_traceEndState, callbackContext) == 0
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, traceCtx) == sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, streaming)
|
||||||
|
== sizeof(void*) + sizeof(unsigned long long)
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, dictionaryID)
|
||||||
|
== sizeof(void*) + sizeof(unsigned long long) + sizeof(int)
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, dictionarySize)
|
||||||
|
== sizeof(void*) + sizeof(unsigned long long) + 2 * sizeof(int)
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, uncompressedSize)
|
||||||
|
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + sizeof(size_t)
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, compressedSize)
|
||||||
|
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 2 * sizeof(size_t)
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, params)
|
||||||
|
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 3 * sizeof(size_t)
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, cctx)
|
||||||
|
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 4 * sizeof(size_t)
|
||||||
|
&& offsetof(ZSTD_rust_traceEndState, traceEnd)
|
||||||
|
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 5 * sizeof(size_t)
|
||||||
|
&& sizeof(ZSTD_rust_traceEndState)
|
||||||
|
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 6 * sizeof(size_t))
|
||||||
|
? 1 : -1];
|
||||||
|
void ZSTD_rust_traceEnd(const ZSTD_rust_traceEndState* state);
|
||||||
|
|
||||||
|
#if ZSTD_TRACE
|
||||||
|
static void ZSTD_rust_traceEnd_callback(void* context,
|
||||||
|
unsigned long long traceCtx, const void* trace)
|
||||||
|
{
|
||||||
|
(void)context;
|
||||||
|
if (ZSTD_trace_compress_end != NULL) {
|
||||||
|
ZSTD_trace_compress_end((ZSTD_TraceCtx)traceCtx,
|
||||||
|
(ZSTD_Trace const*)trace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)
|
void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)
|
||||||
{
|
{
|
||||||
#if ZSTD_TRACE
|
#if ZSTD_TRACE
|
||||||
if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) {
|
ZSTD_rust_traceEndState state;
|
||||||
int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0;
|
state.callbackContext = cctx;
|
||||||
ZSTD_Trace trace;
|
state.traceCtx = cctx->traceCtx;
|
||||||
ZSTD_memset(&trace, 0, sizeof(trace));
|
state.streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0
|
||||||
trace.version = ZSTD_VERSION_NUMBER;
|
|| cctx->appliedParams.nbWorkers > 0;
|
||||||
trace.streaming = streaming;
|
state.dictionaryID = cctx->dictID;
|
||||||
trace.dictionaryID = cctx->dictID;
|
state.dictionarySize = cctx->dictContentSize;
|
||||||
trace.dictionarySize = cctx->dictContentSize;
|
state.uncompressedSize = cctx->consumedSrcSize;
|
||||||
trace.uncompressedSize = cctx->consumedSrcSize;
|
state.compressedSize = cctx->producedCSize + extraCSize;
|
||||||
trace.compressedSize = cctx->producedCSize + extraCSize;
|
state.params = &cctx->appliedParams;
|
||||||
trace.params = &cctx->appliedParams;
|
state.cctx = cctx;
|
||||||
trace.cctx = cctx;
|
state.traceEnd = ZSTD_rust_traceEnd_callback;
|
||||||
ZSTD_trace_compress_end(cctx->traceCtx, &trace);
|
ZSTD_rust_traceEnd(&state);
|
||||||
}
|
|
||||||
cctx->traceCtx = 0;
|
cctx->traceCtx = 0;
|
||||||
#else
|
#else
|
||||||
(void)cctx;
|
(void)cctx;
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ use crate::zstd_compress_stats::{
|
|||||||
ZSTD_rust_validateSeqStore, ZSTD_LLT_LITERAL_LENGTH, ZSTD_LLT_MATCH_LENGTH,
|
ZSTD_rust_validateSeqStore, ZSTD_LLT_LITERAL_LENGTH, ZSTD_LLT_MATCH_LENGTH,
|
||||||
};
|
};
|
||||||
use crate::zstd_compress_superblock::ZSTD_rust_compressSuperBlock;
|
use crate::zstd_compress_superblock::ZSTD_rust_compressSuperBlock;
|
||||||
|
use crate::zstd_common::ZSTD_VERSION_NUMBER;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::mem::{offset_of, size_of, MaybeUninit};
|
use std::mem::{offset_of, size_of, MaybeUninit};
|
||||||
use std::os::raw::{c_int, c_longlong, c_uint};
|
use std::os::raw::{c_int, c_longlong, c_uint};
|
||||||
@@ -2796,6 +2797,105 @@ pub unsafe extern "C" fn ZSTD_rust_compressContinue(
|
|||||||
|
|
||||||
type CompressEndTraceFn = unsafe extern "C" fn(*mut c_void, usize);
|
type CompressEndTraceFn = unsafe extern "C" fn(*mut c_void, usize);
|
||||||
|
|
||||||
|
type CompressTraceEndFn = unsafe extern "C" fn(*mut c_void, u64, *const c_void);
|
||||||
|
|
||||||
|
/// ABI-compatible compression trace record. The weak trace hook remains a C
|
||||||
|
/// callback, but Rust owns construction of the record and its enabled/reset
|
||||||
|
/// policy.
|
||||||
|
#[repr(C)]
|
||||||
|
struct ZSTD_Trace {
|
||||||
|
version: c_uint,
|
||||||
|
streaming: c_int,
|
||||||
|
dictionary_id: c_uint,
|
||||||
|
dictionary_is_cold: c_int,
|
||||||
|
dictionary_size: usize,
|
||||||
|
uncompressed_size: usize,
|
||||||
|
compressed_size: usize,
|
||||||
|
params: *const c_void,
|
||||||
|
cctx: *const c_void,
|
||||||
|
dctx: *const c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
assert!(offset_of!(ZSTD_Trace, version) == 0);
|
||||||
|
assert!(offset_of!(ZSTD_Trace, streaming) == size_of::<c_uint>());
|
||||||
|
assert!(offset_of!(ZSTD_Trace, dictionary_id) == size_of::<c_uint>() + size_of::<c_int>());
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_Trace, dictionary_is_cold)
|
||||||
|
== 2 * size_of::<c_uint>() + size_of::<c_int>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_Trace, dictionary_size)
|
||||||
|
== 2 * size_of::<c_uint>() + 2 * size_of::<c_int>()
|
||||||
|
);
|
||||||
|
assert!(offset_of!(ZSTD_Trace, uncompressed_size) == offset_of!(ZSTD_Trace, dictionary_size) + size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_Trace, compressed_size) == offset_of!(ZSTD_Trace, dictionary_size) + 2 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_Trace, params) == offset_of!(ZSTD_Trace, dictionary_size) + 3 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_Trace, cctx) == offset_of!(ZSTD_Trace, dictionary_size) + 4 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_Trace, dctx) == offset_of!(ZSTD_Trace, dictionary_size) + 5 * size_of::<usize>());
|
||||||
|
assert!(size_of::<ZSTD_Trace>() == offset_of!(ZSTD_Trace, dictionary_size) + 6 * size_of::<usize>());
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Inputs for Rust-owned compression trace construction.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ZSTD_rust_traceEndState {
|
||||||
|
callback_context: *mut c_void,
|
||||||
|
trace_ctx: u64,
|
||||||
|
streaming: c_int,
|
||||||
|
dictionary_id: c_uint,
|
||||||
|
dictionary_size: usize,
|
||||||
|
uncompressed_size: usize,
|
||||||
|
compressed_size: usize,
|
||||||
|
params: *const c_void,
|
||||||
|
cctx: *const c_void,
|
||||||
|
trace_end: CompressTraceEndFn,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
assert!(size_of::<CompressTraceEndFn>() == size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, callback_context) == 0);
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, trace_ctx) == size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, streaming) == size_of::<usize>() + size_of::<u64>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, dictionary_id) == size_of::<usize>() + size_of::<u64>() + size_of::<c_int>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, dictionary_size) == size_of::<usize>() + size_of::<u64>() + 2 * size_of::<c_int>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, uncompressed_size) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, compressed_size) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 2 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, params) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 3 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, cctx) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 4 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_traceEndState, trace_end) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 5 * size_of::<usize>());
|
||||||
|
assert!(size_of::<ZSTD_rust_traceEndState>() == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 6 * size_of::<usize>());
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Construct and publish a compression trace record, if tracing is enabled.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ZSTD_rust_traceEnd(state: *const ZSTD_rust_traceEndState) {
|
||||||
|
let Some(state) = (unsafe { state.as_ref() }) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if state.trace_ctx == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let trace = ZSTD_Trace {
|
||||||
|
version: ZSTD_VERSION_NUMBER as c_uint,
|
||||||
|
streaming: state.streaming,
|
||||||
|
dictionary_id: state.dictionary_id,
|
||||||
|
dictionary_is_cold: 0,
|
||||||
|
dictionary_size: state.dictionary_size,
|
||||||
|
uncompressed_size: state.uncompressed_size,
|
||||||
|
compressed_size: state.compressed_size,
|
||||||
|
params: state.params,
|
||||||
|
cctx: state.cctx,
|
||||||
|
dctx: ptr::null(),
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
(state.trace_end)(
|
||||||
|
state.callback_context,
|
||||||
|
state.trace_ctx,
|
||||||
|
(&trace as *const ZSTD_Trace).cast(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Explicit projection for the public end-of-frame orchestration.
|
/// Explicit projection for the public end-of-frame orchestration.
|
||||||
///
|
///
|
||||||
/// Rust owns callback ordering, output offset/capacity accounting, and
|
/// Rust owns callback ordering, output offset/capacity accounting, and
|
||||||
|
|||||||
Reference in New Issue
Block a user