|
43 | 43 | #define TPM2_BENCH_DURATION_KEYGEN_SEC 15 |
44 | 44 | static int gUseBase2 = 1; |
45 | 45 |
|
| 46 | +/* Fixed-iteration mode (-iter=N). Zero keeps the default duration mode, where |
| 47 | + * each algorithm runs for a wall-clock budget instead of a set count. */ |
| 48 | +static int gBenchIter = 0; |
| 49 | +/* Per-iteration spread, so a single slow outlier is visible rather than |
| 50 | + * averaged away. Rejection sampling makes ML-DSA signing vary run to run. */ |
| 51 | +static double gIterPrev, gIterMin, gIterMax; |
| 52 | + |
46 | 53 | static inline void bench_stats_start(int* count, double* start) |
47 | 54 | { |
48 | 55 | *count = 0; |
49 | 56 | *start = gettime_secs(1); |
| 57 | + gIterPrev = *start; |
| 58 | + gIterMin = 0; |
| 59 | + gIterMax = 0; |
50 | 60 | } |
51 | 61 |
|
52 | 62 | static inline int bench_stats_check(double start, int* count, double maxDurSec) |
53 | 63 | { |
| 64 | + double now, each; |
| 65 | + |
54 | 66 | (*count)++; |
55 | | - return ((gettime_secs(0) - start) < maxDurSec); |
| 67 | + now = gettime_secs(0); |
| 68 | + each = now - gIterPrev; |
| 69 | + gIterPrev = now; |
| 70 | + if (*count == 1) { |
| 71 | + gIterMin = each; |
| 72 | + gIterMax = each; |
| 73 | + } |
| 74 | + else if (each > gIterMax) { |
| 75 | + gIterMax = each; |
| 76 | + } |
| 77 | + else if (each < gIterMin) { |
| 78 | + gIterMin = each; |
| 79 | + } |
| 80 | + if (gBenchIter > 0) { |
| 81 | + return (*count < gBenchIter); |
| 82 | + } |
| 83 | + return ((now - start) < maxDurSec); |
56 | 84 | } |
57 | 85 |
|
58 | 86 | /* countSz is number of bytes that 1 count represents. Normally bench_size, |
@@ -121,8 +149,13 @@ static void bench_stats_asym_finish(const char* algo, int strength, |
121 | 149 | milliEach = each * 1000; /* milliseconds */ |
122 | 150 |
|
123 | 151 | printf("%-6s %5d %-9s %6d ops took %5.3f sec, avg %5.3f ms," |
124 | | - " %.3f ops/sec\n", algo, strength, desc, |
| 152 | + " %.3f ops/sec", algo, strength, desc, |
125 | 153 | count, total, milliEach, opsSec); |
| 154 | + if (gBenchIter > 0) { |
| 155 | + printf(", min %5.3f ms, max %5.3f ms", |
| 156 | + gIterMin * 1000, gIterMax * 1000); |
| 157 | + } |
| 158 | + printf("\n"); |
126 | 159 | } |
127 | 160 |
|
128 | 161 | /* True if rc means the TPM does not implement the operation (so the bench |
@@ -370,6 +403,9 @@ static void usage(void) |
370 | 403 | printf("* -aes/xor: Use Parameter Encryption\n"); |
371 | 404 | printf("* -maxdur=[ms]: Maximum runtime for each algorithm in milliseconds " |
372 | 405 | "(default %d)\n", TPM2_BENCH_DURATION_SEC*1000); |
| 406 | + printf("* -iter=[n]: Run each algorithm exactly n times and report the\n"); |
| 407 | + printf(" average with the per-iteration min and max, instead of\n"); |
| 408 | + printf(" running for a duration. Overrides -maxdur.\n"); |
373 | 409 | } |
374 | 410 |
|
375 | 411 | /******************************************************************************/ |
@@ -419,6 +455,15 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[]) |
419 | 455 | const char* maxStr = argv[argc-1] + XSTRLEN("-maxdur="); |
420 | 456 | maxKeyGenDurSec = maxDuration = XATOI(maxStr) / 1000.0; |
421 | 457 | } |
| 458 | + else if (XSTRNCMP(argv[argc-1], "-iter=", XSTRLEN("-iter=")) == 0) { |
| 459 | + const char* iterStr = argv[argc-1] + XSTRLEN("-iter="); |
| 460 | + gBenchIter = XATOI(iterStr); |
| 461 | + if (gBenchIter <= 0) { |
| 462 | + printf("Iteration count must be greater than zero\n"); |
| 463 | + usage(); |
| 464 | + return BAD_FUNC_ARG; |
| 465 | + } |
| 466 | + } |
422 | 467 | else { |
423 | 468 | printf("Warning: Unrecognized option: %s\n", argv[argc-1]); |
424 | 469 | } |
|
0 commit comments