mirror of
https://github.com/martijnvanbrummelen/nwipe.git
synced 2026-02-20 13:42:14 +00:00
prng: print benchmark progress live and show PRNG activity immediately
The PRNG auto-selection benchmark previously ran silently and only printed results at the end. As a result, there was a noticeable delay (several seconds) between starting nwipe and any visible output, making it appear as if the program was stalled. This change moves the output into the benchmark loop itself: - Print "Analysing PRNG performance:" immediately when benchmarking starts - Show a classic rotating cursor (-\|/) while benchmarks are running - Print "Testing <PRNG> performance..." before each PRNG is benchmarked - Print each PRNG’s result (MB/s or failure) immediately after it finishes The existing nwipe_prng_benchmark_all() API is preserved for compatibility. A new nwipe_prng_benchmark_all_live() function provides the live output behaviour and is used for --prng=auto. This makes startup progress visible, improves UX, and aligns behaviour with the original maintainer’s expectations.
This commit is contained in:
35
src/nwipe.c
35
src/nwipe.c
@@ -385,10 +385,17 @@ int main( int argc, char** argv )
|
|||||||
nwipe_prng_bench_result_t results[16];
|
nwipe_prng_bench_result_t results[16];
|
||||||
memset( results, 0, sizeof( results ) );
|
memset( results, 0, sizeof( results ) );
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------
|
||||||
|
* --prng-benchmark-only path
|
||||||
|
* (keep output clean: no live "Testing..." lines by default)
|
||||||
|
* ------------------------------------------------------------ */
|
||||||
if( nwipe_options.prng_benchmark_only )
|
if( nwipe_options.prng_benchmark_only )
|
||||||
{
|
{
|
||||||
int n = nwipe_prng_benchmark_all(
|
const int live_print = 0; /* set to 1 if you also want live here */
|
||||||
seconds, io_block, results, (int) ( sizeof( results ) / sizeof( results[0] ) ) );
|
|
||||||
|
int n = nwipe_prng_benchmark_all_live(
|
||||||
|
seconds, io_block, results, (int) ( sizeof( results ) / sizeof( results[0] ) ), live_print );
|
||||||
|
|
||||||
if( n <= 0 )
|
if( n <= 0 )
|
||||||
{
|
{
|
||||||
nwipe_log( NWIPE_LOG_ERROR, "PRNG benchmark failed (no results)." );
|
nwipe_log( NWIPE_LOG_ERROR, "PRNG benchmark failed (no results)." );
|
||||||
@@ -435,11 +442,31 @@ int main( int argc, char** argv )
|
|||||||
exit( 0 );
|
exit( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --prng=auto path */
|
/* ------------------------------------------------------------
|
||||||
|
* --prng=auto path
|
||||||
|
* (THIS is the path where live output matters for “GUI delay”)
|
||||||
|
* ------------------------------------------------------------ */
|
||||||
if( nwipe_options.prng_auto )
|
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(
|
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 )
|
if( best != NULL )
|
||||||
{
|
{
|
||||||
|
|||||||
176
src/prng.c
176
src/prng.c
@@ -723,11 +723,61 @@ static void* nwipe_prng_alloc_aligned( size_t alignment, size_t size )
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- live spinner state ------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int enabled;
|
||||||
|
int is_tty;
|
||||||
|
int spin_idx;
|
||||||
|
double last_tick;
|
||||||
|
const char* analysing_msg;
|
||||||
|
} nwipe_prng_live_t;
|
||||||
|
|
||||||
|
static void nwipe_prng_live_clear_line( nwipe_prng_live_t* live )
|
||||||
|
{
|
||||||
|
if( !live || !live->enabled || !live->is_tty )
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* clear current line */
|
||||||
|
printf( "\r\033[K" );
|
||||||
|
fflush( stdout );
|
||||||
|
}
|
||||||
|
|
||||||
|
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->analysing_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 (now with optional live spinner ticks) -------------- */
|
||||||
|
|
||||||
static void nwipe_prng_bench_one( const nwipe_prng_t* prng,
|
static void nwipe_prng_bench_one( const nwipe_prng_t* prng,
|
||||||
nwipe_prng_bench_result_t* out,
|
nwipe_prng_bench_result_t* out,
|
||||||
void* io_buf,
|
void* io_buf,
|
||||||
size_t io_block,
|
size_t io_block,
|
||||||
double seconds_per_prng )
|
double seconds_per_prng,
|
||||||
|
nwipe_prng_live_t* live )
|
||||||
{
|
{
|
||||||
void* state = NULL;
|
void* state = NULL;
|
||||||
|
|
||||||
@@ -755,6 +805,13 @@ static void nwipe_prng_bench_one( const nwipe_prng_t* prng,
|
|||||||
const double t0 = nwipe_prng_monotonic_seconds();
|
const double t0 = nwipe_prng_monotonic_seconds();
|
||||||
double now = t0;
|
double now = t0;
|
||||||
|
|
||||||
|
/* ensure spinner is visible right when this PRNG starts doing work */
|
||||||
|
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 )
|
while( ( now - t0 ) < seconds_per_prng )
|
||||||
{
|
{
|
||||||
rc = prng->read( &state, io_buf, io_block );
|
rc = prng->read( &state, io_buf, io_block );
|
||||||
@@ -766,6 +823,9 @@ static void nwipe_prng_bench_one( const nwipe_prng_t* prng,
|
|||||||
|
|
||||||
out->bytes += (unsigned long long) io_block;
|
out->bytes += (unsigned long long) io_block;
|
||||||
now = nwipe_prng_monotonic_seconds();
|
now = nwipe_prng_monotonic_seconds();
|
||||||
|
|
||||||
|
/* keep the classic cursor rotating while the benchmark runs */
|
||||||
|
nwipe_prng_live_tick_if_due( live, now );
|
||||||
}
|
}
|
||||||
|
|
||||||
out->seconds = now - t0;
|
out->seconds = now - t0;
|
||||||
@@ -778,15 +838,18 @@ static void nwipe_prng_bench_one( const nwipe_prng_t* prng,
|
|||||||
free( state );
|
free( state );
|
||||||
}
|
}
|
||||||
|
|
||||||
int nwipe_prng_benchmark_all( double seconds_per_prng,
|
/* --- new: benchmark all with optional live output ----------------------- */
|
||||||
size_t io_block_bytes,
|
|
||||||
nwipe_prng_bench_result_t* results,
|
int nwipe_prng_benchmark_all_live( double seconds_per_prng,
|
||||||
size_t results_count )
|
size_t io_block_bytes,
|
||||||
|
nwipe_prng_bench_result_t* results,
|
||||||
|
size_t results_count,
|
||||||
|
int live_print )
|
||||||
{
|
{
|
||||||
if( results == NULL || results_count == 0 )
|
if( results == NULL || results_count == 0 )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Anzahl PRNGs begrenzen auf results_count */
|
/* limit number of PRNGs to results_count */
|
||||||
size_t max = sizeof( all_prngs ) / sizeof( all_prngs[0] );
|
size_t max = sizeof( all_prngs ) / sizeof( all_prngs[0] );
|
||||||
if( results_count < max )
|
if( results_count < max )
|
||||||
max = results_count;
|
max = results_count;
|
||||||
@@ -798,42 +861,107 @@ int nwipe_prng_benchmark_all( double seconds_per_prng,
|
|||||||
return -1;
|
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();
|
||||||
|
live.analysing_msg = "Analysing PRNG performance:";
|
||||||
|
|
||||||
|
if( live.enabled )
|
||||||
|
{
|
||||||
|
if( live.is_tty )
|
||||||
|
{
|
||||||
|
/* show immediately (user sees activity right away) */
|
||||||
|
nwipe_prng_live_render_spinner( &live, /*advance=*/0 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* non-interactive: just print the header once */
|
||||||
|
printf( "%s\n", live.analysing_msg );
|
||||||
|
fflush( stdout );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for( size_t i = 0; i < max; i++ )
|
for( size_t i = 0; i < max; i++ )
|
||||||
{
|
{
|
||||||
nwipe_prng_bench_result_t* r = &results[i];
|
nwipe_prng_bench_result_t* r = &results[i];
|
||||||
memset( r, 0, sizeof( *r ) );
|
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 )
|
||||||
|
nwipe_prng_live_clear_line( &live );
|
||||||
|
|
||||||
|
/* as requested: print before starting each PRNG */
|
||||||
|
printf( "Testing %s performance...\n", prng->label );
|
||||||
|
fflush( stdout );
|
||||||
|
|
||||||
|
if( live.is_tty )
|
||||||
|
{
|
||||||
|
/* re-show spinner line while the PRNG runs */
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
if( live.is_tty )
|
||||||
|
nwipe_prng_live_clear_line( &live );
|
||||||
|
|
||||||
|
/* print result immediately after each PRNG */
|
||||||
|
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.is_tty )
|
||||||
|
{
|
||||||
|
/* keep spinner visible between PRNGs */
|
||||||
|
live.last_tick = nwipe_prng_monotonic_seconds();
|
||||||
|
nwipe_prng_live_render_spinner( &live, /*advance=*/1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( live.enabled && live.is_tty )
|
||||||
|
{
|
||||||
|
/* remove spinner line before subsequent prints (Selected PRNG, GUI, etc.) */
|
||||||
|
nwipe_prng_live_clear_line( &live );
|
||||||
}
|
}
|
||||||
|
|
||||||
free( io_buf );
|
free( io_buf );
|
||||||
return (int) max;
|
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,
|
const nwipe_prng_t* nwipe_prng_select_fastest( double seconds_per_prng,
|
||||||
size_t io_block_bytes,
|
size_t io_block_bytes,
|
||||||
nwipe_prng_bench_result_t* results,
|
nwipe_prng_bench_result_t* results,
|
||||||
size_t results_count )
|
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 )
|
if( n <= 0 )
|
||||||
return NULL;
|
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;
|
const nwipe_prng_t* best = NULL;
|
||||||
double best_mbps = 0.0;
|
double best_mbps = 0.0;
|
||||||
|
|
||||||
|
|||||||
13
src/prng.h
13
src/prng.h
@@ -54,11 +54,24 @@ typedef struct
|
|||||||
int rc;
|
int rc;
|
||||||
} nwipe_prng_bench_result_t;
|
} nwipe_prng_bench_result_t;
|
||||||
|
|
||||||
|
/* Existing API (kept for compatibility: no live output) */
|
||||||
int nwipe_prng_benchmark_all( double seconds_per_prng,
|
int nwipe_prng_benchmark_all( double seconds_per_prng,
|
||||||
size_t io_block_bytes,
|
size_t io_block_bytes,
|
||||||
nwipe_prng_bench_result_t* results,
|
nwipe_prng_bench_result_t* results,
|
||||||
size_t results_count );
|
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,
|
const nwipe_prng_t* nwipe_prng_select_fastest( double seconds_per_prng,
|
||||||
size_t io_block_bytes,
|
size_t io_block_bytes,
|
||||||
nwipe_prng_bench_result_t* results,
|
nwipe_prng_bench_result_t* results,
|
||||||
|
|||||||
Reference in New Issue
Block a user