Move the implementation of programs/benchfn.c into rust/src/benchfn.rs and wire benchmark mode (-b/-e/-i) into the Rust CLI frontend, which previously rejected those options as not yet implemented. `zstd -b1 -i0 FILE` and range runs like `zstd -b5e6 -i0 FILE` work again, including the synthetic-sample benchmark when no file is given. benchfn.rs is a faithful port of the run/timing state machine: BMK_benchFunction keeps the exact loop accounting (first-loop blockResults and errorFn checks, dstSize summed on the first loop only, 0xE5 warm-up of result buffers, nbLoops minimum of 1) and BMK_benchTimedFn keeps the same convergence behavior (x10 workload growth for short runs, budget-based nbLoops estimation, runs below half the run budget re-tried rather than reported, best qualifying run returned). Arithmetic that C leaves to unsigned wrap-around uses wrapping operations so debug builds cannot panic where release C would wrap. ABI notes: BMK_runTime_t and BMK_runOutcome_t are returned by value across the C boundary and BMK_benchParams_t is passed by value, so all three are repr(C) mirrors of benchfn.h; their field offsets are pinned by const asserts in Rust and matching C static asserts in the benchfn.c shim, which is now declaration-only. BMK_timedFnState_t stays opaque, fits the 64-byte BMK_timedFnState_shell (compile-time checked), and is malloc/free-managed so creation and destruction remain interchangeable with C callers. The CLI parses -b (bench mode), -e (range end, digits attach directly, defaulting to 0 like readU32FromChar) and -i (duration in seconds), then dispatches through a new ZSTD_rust_cli_bench bridge in the zstdcli.c shim. The bridge exists because benchmark availability is a C preprocessor property (ZSTD_NOBENCH): orchestration and reporting stay in C benchzstd.c, stripped variants (zstd-small, zstd-compress, zstd-decompress) compile the stub branch and report "benchmark mode is not available in this build", and the Rust side never references benchmark symbols directly. Level clamping against ZSTD_maxCLevel() happens in the bridge, where the symbol is guaranteed to exist whenever benchmarking is compiled in. -T selects the worker count, defaulting to single-threaded like the C bench path; -S (separate files) and --priority=rt remain unimplemented. Makefile updates only extend the Rust source prerequisite lists with benchfn.rs; the helpers-archive plumbing from the timefn commit already links fullbench(-lib/-dll/32) and paramgrill, the benchfn consumers among the C tests. Original C test sources are untouched. Known pre-existing issues, unchanged by this commit: tests/fullbench-lib fails to link at the base commit too (libzstd.a precedes fullbench.c in its link line), and the cli-tests basic/help.sh, compression/levels.sh, compression/golden.sh, and decompression/pass-through.sh scripts fail identically with a base-commit binary because the Rust CLI frontend is still a partial reimplementation. Test Plan: - cd rust && cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test --all-targets && cargo build --release - cd rust/cli && cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test --all-targets; repeat tests with --no-default-features plus features compression / decompression / (none) - make -C programs zstd; ./programs/zstd -b1 -i0 lib/common/xxhash.c; ./programs/zstd -b5e6 -i0 programs/fileio.c; ./programs/zstd -b1 -i0 (synthetic); echo roundtrip via zstd | zstd -d - make -C programs zstd-small zstd-compress zstd-decompress zstd-nolegacy zstd-dictBuilder; zstd-small -b reports benchmark unavailable; compress/ decompress roundtrip across the split binaries - make -C tests fullbench fuzzer zstreamtest paramgrill decodecorpus poolTests fullbench32 fuzzer32; ./tests/fullbench -i0 (exercises Rust BMK_benchTimedFn from C); ./tests/fullbench32 -i0; ./tests/fuzzer -i1 --no-big-tests; ./tests/poolTests; make -C tests test-rust-lib-smoke - cli-tests subset: basic/version.sh, compression/basic.sh, compression/multiple-files.sh pass; failing scripts match the base commit Refs: rust/README.md
78 lines
3.3 KiB
C
78 lines
3.3 KiB
C
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under both the BSD-style license (found in the
|
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
|
* in the COPYING file in the root directory of this source tree).
|
|
* You may select, at your option, one of the above-listed licenses.
|
|
*/
|
|
|
|
/* The CLI parser and control flow live in rust/src/zstd_cli.rs. Keep this
|
|
* translation unit as the stable C entry point used by program launchers. */
|
|
#include <stddef.h> /* size_t */
|
|
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */
|
|
#include "../lib/zstd.h"
|
|
#ifndef ZSTD_NOBENCH
|
|
# include "benchzstd.h" /* BMK_benchFilesAdvanced, BMK_syntheticTest */
|
|
#endif
|
|
|
|
int ZSTD_rust_cli_main(int argCount, const char* const argv[]);
|
|
const char* ZSTD_rust_cli_expected_version(void);
|
|
int ZSTD_rust_cli_bench(const char* const* fileNames, unsigned nbFiles,
|
|
const char* dictFileName,
|
|
int startCLevel, int endCLevel,
|
|
const ZSTD_compressionParameters* compressionParams,
|
|
int displayLevel, unsigned nbSeconds,
|
|
size_t blockSize, int nbWorkers);
|
|
|
|
const char* ZSTD_rust_cli_expected_version(void)
|
|
{
|
|
return ZSTD_VERSION_STRING;
|
|
}
|
|
|
|
/* Benchmark bridge for the Rust CLI. Whether benchmarking exists is a C
|
|
* preprocessor property (ZSTD_NOBENCH), so the decision stays in this shim:
|
|
* the Rust frontend calls in unconditionally, and stripped program variants
|
|
* never reference benchmark symbols.
|
|
* @return the benchmark result code (>= 0), or -1 when unavailable. */
|
|
int ZSTD_rust_cli_bench(const char* const* fileNames, unsigned nbFiles,
|
|
const char* dictFileName,
|
|
int startCLevel, int endCLevel,
|
|
const ZSTD_compressionParameters* compressionParams,
|
|
int displayLevel, unsigned nbSeconds,
|
|
size_t blockSize, int nbWorkers)
|
|
{
|
|
#ifndef ZSTD_NOBENCH
|
|
BMK_advancedParams_t advancedParams = BMK_initAdvancedParams();
|
|
int startLevel = startCLevel;
|
|
int endLevel = endCLevel;
|
|
advancedParams.nbSeconds = nbSeconds;
|
|
advancedParams.blockSize = blockSize;
|
|
advancedParams.nbWorkers = nbWorkers;
|
|
if (startLevel > ZSTD_maxCLevel()) startLevel = ZSTD_maxCLevel();
|
|
if (endLevel > ZSTD_maxCLevel()) endLevel = ZSTD_maxCLevel();
|
|
if (endLevel < startLevel) endLevel = startLevel;
|
|
if (nbFiles == 0) {
|
|
/* No input file: benchmark a synthetic sample (lorem generator). */
|
|
return BMK_syntheticTest(-1.0, startLevel, endLevel,
|
|
compressionParams, displayLevel,
|
|
&advancedParams);
|
|
}
|
|
return BMK_benchFilesAdvanced(fileNames, nbFiles, dictFileName,
|
|
startLevel, endLevel,
|
|
compressionParams, displayLevel,
|
|
&advancedParams);
|
|
#else
|
|
(void)fileNames; (void)nbFiles; (void)dictFileName;
|
|
(void)startCLevel; (void)endCLevel; (void)compressionParams;
|
|
(void)displayLevel; (void)nbSeconds; (void)blockSize; (void)nbWorkers;
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int main(int argCount, const char* argv[])
|
|
{
|
|
return ZSTD_rust_cli_main(argCount, argv);
|
|
}
|