Merge pull request #706 from Knogle/further-additions-for-auto-selection-for-prng-and-benchmark-no-gui-option

Further additions for auto selection for prng and benchmark no gui option
This commit is contained in:
PartialVolume
2026-01-04 13:58:13 +00:00
committed by GitHub
4 changed files with 199 additions and 33 deletions

View File

@@ -385,10 +385,17 @@ int main( int argc, char** argv )
nwipe_prng_bench_result_t results[16];
memset( results, 0, sizeof( results ) );
/* ------------------------------------------------------------
* --prng-benchmark-only path
* (keep output clean: no live "Testing..." lines by default)
* ------------------------------------------------------------ */
if( nwipe_options.prng_benchmark_only )
{
int n = nwipe_prng_benchmark_all(
seconds, io_block, results, (int) ( sizeof( results ) / sizeof( results[0] ) ) );
const int live_print = 0; /* set to 1 if you also want live here */
int n = nwipe_prng_benchmark_all_live(
seconds, io_block, results, (int) ( sizeof( results ) / sizeof( results[0] ) ), live_print );
if( n <= 0 )
{
nwipe_log( NWIPE_LOG_ERROR, "PRNG benchmark failed (no results)." );
@@ -435,11 +442,31 @@ int main( int argc, char** argv )
exit( 0 );
}
/* --prng=auto path */
/* ------------------------------------------------------------
* --prng=auto path
* (THIS is the path where live output matters for “GUI delay”)
* ------------------------------------------------------------ */
if( nwipe_options.prng_auto )
{
/* live_print=1: prints:
* - "Analysing PRNG performance:" immediately (with spinner)
* - "Testing <PRNG> performance..." per PRNG
* - "<PRNG> -> xx.x MB/s" immediately after each PRNG
*/
const int live_print = 1;
/* Option A (preferred): make select_fastest call the live benchmark internally.
* best = nwipe_prng_select_fastest(seconds, io_block, results, count);
* and inside select_fastest use nwipe_prng_benchmark_all_live(..., 1)
*
* Option B: benchmark here (live), then choose best locally.
* Since you already have nwipe_prng_select_fastest(), stick with Option A.
*/
const nwipe_prng_t* best = nwipe_prng_select_fastest(
seconds, io_block, results, (int) ( sizeof( results ) / sizeof( results[0] ) ) );
seconds, io_block, results, (int) ( sizeof( results ) / sizeof( results[0] ) ) /* results_count */
/* ensure select_fastest uses nwipe_prng_benchmark_all_live(..., live_print) */
);
if( best != NULL )
{

View File

@@ -141,7 +141,7 @@ int nwipe_options_parse( int argc, char** argv )
nwipe_options.autonuke = 0;
nwipe_options.autopoweroff = 0;
nwipe_options.method = &nwipe_random;
nwipe_options.prng_auto = 0;
nwipe_options.prng_auto = 1; /* by default the PRNG is selected through the benchmark selection */
nwipe_options.prng_benchmark_only = 0;
nwipe_options.prng_bench_seconds = 1.0; /* default for interactive / manual */
@@ -758,12 +758,25 @@ int nwipe_options_parse( int argc, char** argv )
case 'p': /* PRNG option. */
/* Default behaviour is auto now, but allow explicit opt-out */
if( strcmp( optarg, "auto" ) == 0 )
{
nwipe_options.prng_auto = 1;
/* keep current default as fallback until autoselect runs */
break;
}
/* NEW: disable auto and keep compiled-in default selection */
if( strcmp( optarg, "default" ) == 0 || strcmp( optarg, "manual" ) == 0 )
{
nwipe_options.prng_auto = 0;
/* keep nwipe_options.prng as chosen by CPU heuristics above */
break;
}
/* Any explicit PRNG selection implies auto off */
nwipe_options.prng_auto = 0;
if( strcmp( optarg, "mersenne" ) == 0 || strcmp( optarg, "twister" ) == 0 )
{
nwipe_options.prng = &nwipe_twister;
@@ -781,16 +794,19 @@ int nwipe_options_parse( int argc, char** argv )
nwipe_options.prng = &nwipe_isaac64;
break;
}
if( strcmp( optarg, "add_lagg_fibonacci_prng" ) == 0 )
{
nwipe_options.prng = &nwipe_add_lagg_fibonacci_prng;
break;
}
if( strcmp( optarg, "xoroshiro256_prng" ) == 0 )
{
nwipe_options.prng = &nwipe_xoroshiro256_prng;
break;
}
if( strcmp( optarg, "aes_ctr_prng" ) == 0 )
{
if( has_aes_ni() )
@@ -807,7 +823,6 @@ int nwipe_options_parse( int argc, char** argv )
break;
}
/* Else we do not know this PRNG. */
fprintf( stderr, "Error: Unknown prng '%s'.\n", optarg );
exit( EINVAL );
@@ -1023,10 +1038,16 @@ void display_help()
puts( " If set to \"noPDF\" no PDF reports are written.\n" );
puts( " -p, --prng=METHOD PRNG option "
"(mersenne|twister|isaac|isaac64|add_lagg_fibonacci_prng|xoroshiro256_prng|aes_ctr_prng)\n" );
puts( " --prng=auto" );
puts( " --prng=auto (default)" );
puts( " Automatically benchmark all available PRNGs at startup and" );
puts( " select the fastest one for the current hardware." );
puts( "" );
puts( " --prng=default" );
puts( " Disable auto-selection and use the built-in default PRNG choice" );
puts( " (CPU-based heuristic; no benchmarking)." );
puts( " Alias: --prng=manual" );
puts( "" );
puts( " --prng-benchmark" );
puts( " Run a RAM-only PRNG throughput benchmark and exit." );
puts( " Prints a sorted leaderboard (MB/s). No wipe is performed." );

View File

@@ -723,11 +723,73 @@ static void* nwipe_prng_alloc_aligned( size_t alignment, size_t size )
return p;
}
/* --- live spinner state ------------------------------------------------- */
typedef struct
{
int enabled;
int is_tty;
int spin_idx;
double last_tick;
/* message currently shown with spinner (includes current PRNG label) */
char msg[160];
} nwipe_prng_live_t;
static void nwipe_prng_live_clear_line( nwipe_prng_live_t* live )
{
if( !live || !live->enabled || !live->is_tty )
return;
printf( "\r\033[K" );
fflush( stdout );
}
static void nwipe_prng_live_set_msg_for_prng( nwipe_prng_live_t* live, const nwipe_prng_t* prng )
{
if( !live || !live->enabled )
return;
if( prng && prng->label )
snprintf( live->msg, sizeof( live->msg ), "Testing %s performance", prng->label );
else
snprintf( live->msg, sizeof( live->msg ), "Testing PRNG performance" );
}
static void nwipe_prng_live_render_spinner( nwipe_prng_live_t* live, int advance )
{
static const char spin[] = "-\\|/";
if( !live || !live->enabled || !live->is_tty )
return;
if( advance )
live->spin_idx = ( live->spin_idx + 1 ) & 3;
printf( "\r\033[K%s %c", live->msg, spin[live->spin_idx] );
fflush( stdout );
}
static void nwipe_prng_live_tick_if_due( nwipe_prng_live_t* live, double now )
{
if( !live || !live->enabled || !live->is_tty )
return;
/* ~10 Hz */
if( ( now - live->last_tick ) >= 0.10 )
{
live->last_tick = now;
nwipe_prng_live_render_spinner( live, /*advance=*/1 );
}
}
/* --- bench one PRNG (unchanged except it ticks spinner) ----------------- */
static void nwipe_prng_bench_one( const nwipe_prng_t* prng,
nwipe_prng_bench_result_t* out,
void* io_buf,
size_t io_block,
double seconds_per_prng )
double seconds_per_prng,
nwipe_prng_live_t* live )
{
void* state = NULL;
@@ -755,6 +817,12 @@ static void nwipe_prng_bench_one( const nwipe_prng_t* prng,
const double t0 = nwipe_prng_monotonic_seconds();
double now = t0;
if( live && live->enabled && live->is_tty )
{
live->last_tick = now;
nwipe_prng_live_render_spinner( live, /*advance=*/0 );
}
while( ( now - t0 ) < seconds_per_prng )
{
rc = prng->read( &state, io_buf, io_block );
@@ -766,27 +834,30 @@ static void nwipe_prng_bench_one( const nwipe_prng_t* prng,
out->bytes += (unsigned long long) io_block;
now = nwipe_prng_monotonic_seconds();
/* rotate cursor while running */
nwipe_prng_live_tick_if_due( live, now );
}
out->seconds = now - t0;
if( out->rc == 0 && out->seconds > 0.0 )
{
out->mbps = ( (double) out->bytes / ( 1024.0 * 1024.0 ) ) / out->seconds;
}
if( state )
free( state );
}
int nwipe_prng_benchmark_all( double seconds_per_prng,
size_t io_block_bytes,
nwipe_prng_bench_result_t* results,
size_t results_count )
/* --- benchmark all with live current-PRNG spinner ----------------------- */
int nwipe_prng_benchmark_all_live( double seconds_per_prng,
size_t io_block_bytes,
nwipe_prng_bench_result_t* results,
size_t results_count,
int live_print )
{
if( results == NULL || results_count == 0 )
return 0;
/* Anzahl PRNGs begrenzen auf results_count */
size_t max = sizeof( all_prngs ) / sizeof( all_prngs[0] );
if( results_count < max )
max = results_count;
@@ -798,42 +869,76 @@ int nwipe_prng_benchmark_all( double seconds_per_prng,
return -1;
}
nwipe_prng_live_t live;
memset( &live, 0, sizeof( live ) );
live.enabled = ( live_print ? 1 : 0 );
live.is_tty = ( live.enabled ? ( isatty( fileno( stdout ) ) ? 1 : 0 ) : 0 );
live.spin_idx = 0;
live.last_tick = nwipe_prng_monotonic_seconds();
snprintf( live.msg, sizeof( live.msg ), "Testing PRNG performance" );
for( size_t i = 0; i < max; i++ )
{
nwipe_prng_bench_result_t* r = &results[i];
memset( r, 0, sizeof( *r ) );
nwipe_prng_bench_one( all_prngs[i], r, io_buf, io_block_bytes, seconds_per_prng );
const nwipe_prng_t* prng = all_prngs[i];
if( live.enabled )
{
if( live.is_tty )
{
/* single status line with spinner showing current PRNG */
nwipe_prng_live_set_msg_for_prng( &live, prng );
live.last_tick = nwipe_prng_monotonic_seconds();
nwipe_prng_live_render_spinner( &live, /*advance=*/0 );
}
}
nwipe_prng_bench_one( prng, r, io_buf, io_block_bytes, seconds_per_prng, &live );
if( live.enabled && live.is_tty )
nwipe_prng_live_clear_line( &live );
/* print result immediately after each PRNG */
if( live.enabled )
{
if( r->rc == 0 )
printf( "%-22s -> %8.1f MB/s\n", r->prng->label, r->mbps );
else
printf( "%-22s -> (failed: rc=%d)\n", r->prng->label, r->rc );
fflush( stdout );
}
}
if( live.enabled && live.is_tty )
nwipe_prng_live_clear_line( &live );
free( io_buf );
return (int) max;
}
/* keep old API intact (no live output) */
int nwipe_prng_benchmark_all( double seconds_per_prng,
size_t io_block_bytes,
nwipe_prng_bench_result_t* results,
size_t results_count )
{
return nwipe_prng_benchmark_all_live( seconds_per_prng, io_block_bytes, results, results_count, /*live_print=*/0 );
}
/* --- select fastest: now uses live benchmark so printing is not delayed -- */
const nwipe_prng_t* nwipe_prng_select_fastest( double seconds_per_prng,
size_t io_block_bytes,
nwipe_prng_bench_result_t* results,
size_t results_count )
{
int n = nwipe_prng_benchmark_all( seconds_per_prng, io_block_bytes, results, results_count );
/* live_print=1 => prints per PRNG immediately (plus spinner) */
int n = nwipe_prng_benchmark_all_live( seconds_per_prng, io_block_bytes, results, results_count, /*live_print=*/1 );
if( n <= 0 )
return NULL;
printf( "Analysing PRNG performance:\n" );
fflush( stdout );
for( int i = 0; i < n; i++ )
{
if( results[i].prng == NULL )
continue;
if( results[i].rc == 0 )
printf( "%-22s -> %8.1f MB/s\n", results[i].prng->label, results[i].mbps );
else
printf( "%-22s -> (failed: rc=%d)\n", results[i].prng->label, results[i].rc );
fflush( stdout );
}
const nwipe_prng_t* best = NULL;
double best_mbps = 0.0;

View File

@@ -54,11 +54,24 @@ typedef struct
int rc;
} nwipe_prng_bench_result_t;
/* Existing API (kept for compatibility: no live output) */
int nwipe_prng_benchmark_all( double seconds_per_prng,
size_t io_block_bytes,
nwipe_prng_bench_result_t* results,
size_t results_count );
/* New API: live output (spinner + per-PRNG immediate prints)
* live_print:
* 0 = behave like old benchmark (silent, just fills results[])
* 1 = print "Analysing PRNG performance:" immediately, rotate cursor,
* print "Testing <PRNG>..." before each PRNG, and print result right after.
*/
int nwipe_prng_benchmark_all_live( double seconds_per_prng,
size_t io_block_bytes,
nwipe_prng_bench_result_t* results,
size_t results_count,
int live_print );
const nwipe_prng_t* nwipe_prng_select_fastest( double seconds_per_prng,
size_t io_block_bytes,
nwipe_prng_bench_result_t* results,