* copyright notice and this permission notice appear in all copies.
*/
-#include <atheme/argon2.h> // ARGON2_*
-#include <atheme/digest.h> // DIGALG_*
-#include <atheme/memory.h> // sreallocarray()
-#include <atheme/pbkdf2.h> // PBKDF2_*
-#include <atheme/stdheaders.h> // (everything else)
-#include <atheme/tools.h> // string_to_uint()
+#include <atheme/argon2.h> // ARGON2_*
+#include <atheme/digest.h> // DIGALG_*
+#include <atheme/memory.h> // sreallocarray()
+#include <atheme/pbkdf2.h> // PBKDF2_*
+#include <atheme/stdheaders.h> // (everything else)
+#include <atheme/sysconf.h> // HAVE_LIBARGON2
+#include <atheme/tools.h> // string_to_uint()
-#include <ext/getopt_long.h> // mowgli_getopt_option_t, mowgli_getopt_long()
+#include <ext/getopt_long.h> // mowgli_getopt_option_t, mowgli_getopt_long()
-#include "benchmark.h" // benchmark_*()
-#include "optimal.h" // do_optimal_benchmarks()
-#include "utils.h" // (everything else)
+#include "benchmark.h" // (everything else)
+#include "optimal.h" // do_optimal_benchmarks()
-#define BENCH_ARRAY_SIZE(x) ((sizeof((x))) / (sizeof((x)[0])))
-#define BENCH_CLOCKTIME_DEFAULT 0.25L
-#define BENCH_MEMLIMIT_DEFAULT ARGON2_MEMCOST_DEF;
+#define BENCH_ARRAY_SIZE(x) ((sizeof((x))) / (sizeof((x)[0])))
-static size_t b_itercounts_default[] = { PBKDF2_ITERCNT_MIN, PBKDF2_ITERCNT_DEF, PBKDF2_ITERCNT_MAX };
-static size_t *b_itercounts = NULL;
-static size_t b_itercounts_count = 0;
+#define BENCH_CLOCKTIME_MIN 0.10L
+#define BENCH_CLOCKTIME_DEF 0.25L
+#define BENCH_CLOCKTIME_MAX 1.00L
-static enum digest_algorithm b_digests_default[] = { DIGALG_SHA1, DIGALG_SHA2_256, DIGALG_SHA2_512 };
-static enum digest_algorithm *b_digests = NULL;
-static size_t b_digests_count = 0;
+#define BENCH_MEMLIMIT_MIN ARGON2_MEMCOST_MIN
+#define BENCH_MEMLIMIT_DEF ARGON2_MEMCOST_DEF
+#define BENCH_MEMLIMIT_MAX ARGON2_MEMCOST_MAX
#ifdef HAVE_LIBARGON2
-static argon2_type b_types_default[] = { Argon2_id };
-static argon2_type *b_types = NULL;
-static size_t b_types_count = 0;
+static argon2_type b_argon2_types_default[] = { Argon2_id };
+static argon2_type *b_argon2_types = NULL;
+static size_t b_argon2_types_count = 0;
-static size_t b_memcosts_default[] = { ARGON2_MEMCOST_MIN, ARGON2_MEMCOST_DEF };
-static size_t *b_memcosts = NULL;
-static size_t b_memcosts_count = 0;
+static size_t b_argon2_memcosts_default[] = { ARGON2_MEMCOST_MIN, ARGON2_MEMCOST_DEF };
+static size_t *b_argon2_memcosts = NULL;
+static size_t b_argon2_memcosts_count = 0;
-static size_t b_timecosts_default[] = { ARGON2_TIMECOST_MIN, ARGON2_TIMECOST_DEF };
-static size_t *b_timecosts = NULL;
-static size_t b_timecosts_count = 0;
+static size_t b_argon2_timecosts_default[] = { ARGON2_TIMECOST_MIN, ARGON2_TIMECOST_DEF };
+static size_t *b_argon2_timecosts = NULL;
+static size_t b_argon2_timecosts_count = 0;
-static size_t b_threads_default[] = { ARGON2_THREADS_DEF };
-static size_t *b_threads = NULL;
-static size_t b_threads_count = 0;
+static size_t b_argon2_threads_default[] = { ARGON2_THREADS_DEF };
+static size_t *b_argon2_threads = NULL;
+static size_t b_argon2_threads_count = 0;
#endif /* HAVE_LIBARGON2 */
-static long double optimal_clocklimit = BENCH_CLOCKTIME_DEFAULT;
-static unsigned int optimal_memlimit = BENCH_MEMLIMIT_DEFAULT;
+static size_t b_pbkdf2_itercounts_default[] = { PBKDF2_ITERCNT_MIN, PBKDF2_ITERCNT_DEF, PBKDF2_ITERCNT_MAX };
+static size_t *b_pbkdf2_itercounts = NULL;
+static size_t b_pbkdf2_itercounts_count = 0;
-static bool run_optimal_benchmarks = false;
-static bool run_argon2_benchmarks = false;
-static bool run_pbkdf2_benchmarks = false;
+static enum digest_algorithm b_pbkdf2_digests_default[] = { DIGALG_SHA1, DIGALG_SHA2_256, DIGALG_SHA2_512 };
+static enum digest_algorithm *b_pbkdf2_digests = NULL;
+static size_t b_pbkdf2_digests_count = 0;
-#ifdef HAVE_LIBARGON2
-static const char bench_short_opts[] = "hvog:l:an:m:t:p:kc:d:";
-#else
-static const char bench_short_opts[] = "hvog:kc:d:";
-#endif
+static long double optimal_clocklimit = BENCH_CLOCKTIME_DEF;
+static unsigned int optimal_memlimit = BENCH_MEMLIMIT_DEF;
+static bool optimal_memlimit_given = false;
+
+static unsigned int run_options = BENCH_RUN_OPTIONS_NONE;
static const mowgli_getopt_option_t bench_long_opts[] = {
- { "help", no_argument, NULL, 'h', 0 },
- { "version", no_argument, NULL, 'v', 0 },
- { "optimal", no_argument, NULL, 'o', 0 },
- { "clocklimit", required_argument, NULL, 'g', 0 },
+
+ { "help", no_argument, NULL, 'h', 0 },
+ { "version", no_argument, NULL, 'v', 0 },
+
+ { "run-optimal-benchmarks", no_argument, NULL, 'o', 0 },
+ { "optimal-clock-limit", required_argument, NULL, 'g', 0 },
#ifdef HAVE_LIBARGON2
- { "memlimit", required_argument, NULL, 'l', 0 },
- { "argon2", no_argument, NULL, 'a', 0 },
- { "type", required_argument, NULL, 'n', 0 },
- { "memory", required_argument, NULL, 'm', 0 },
- { "time", required_argument, NULL, 't', 0 },
- { "threads", required_argument, NULL, 'p', 0 },
+ { "optimal-memory-limit", required_argument, NULL, 'l', 0 },
+ { "run-argon2-benchmarks", no_argument, NULL, 'a', 0 },
+ { "argon2-types", required_argument, NULL, 'n', 0 },
+ { "argon2-memory-costs", required_argument, NULL, 'm', 0 },
+ { "argon2-time-costs", required_argument, NULL, 't', 0 },
+ { "argon2-threads", required_argument, NULL, 'p', 0 },
#endif
- { "pbkdf2", no_argument, NULL, 'k', 0 },
- { "iterations", required_argument, NULL, 'c', 0 },
- { "digests", required_argument, NULL, 'd', 0 },
- { NULL, 0, NULL, 0 , 0 },
+ { "run-pbkdf2-benchmarks", no_argument, NULL, 'k', 0 },
+ { "pbkdf2-iterations", required_argument, NULL, 'c', 0 },
+ { "pbkdf2-digest-algorithms", required_argument, NULL, 'd', 0 },
+
+ { NULL, 0, NULL, 0, 0 },
};
+static inline void
+print_version(void)
+{
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "%s (Cryptographic Benchmarking Utility)\n", PACKAGE_STRING);
+ (void) fprintf(stderr, "Using digest frontend: %s\n", digest_get_frontend_info());
+}
+
static inline void
print_usage(void)
{
(void) fprintf(stderr, "\n"
- " Usage: " PACKAGE_TARNAME "-crypto-benchmark [-h | -v]\n"
- " Usage: " PACKAGE_TARNAME "-crypto-benchmark -o [-g <clocklimit>] [-l <memlimit>]\n"
+ " Usage: " PACKAGE_TARNAME "-crypto-benchmark -h\n"
+ " " PACKAGE_TARNAME "-crypto-benchmark -v\n"
+ " " PACKAGE_TARNAME "-crypto-benchmark -o [-g ...] [-l ...]\n"
#ifdef HAVE_LIBARGON2
- " " PACKAGE_TARNAME "-crypto-benchmark -a [-m ...] [-n ...] [-p ...] [-t ...]\n"
+ " " PACKAGE_TARNAME "-crypto-benchmark -a [-n ...] [-m ...] [-t ...] [-p ...]\n"
#endif
" " PACKAGE_TARNAME "-crypto-benchmark -k [-c ...] [-d ...]\n"
"\n"
- " -h/--help Display this help information and exit\n"
- " -v/--version Display program version and exit\n"
+ " -h/--help Display this help information and exit\n"
+ " -v/--version Display program version and exit\n"
"\n"
- " -o/--optimal Perform an automatic optimal parameter benchmark\n"
- " -g/--clocklimit Wall clock time limit for optimal benchmarking (seconds)\n"
+ " -o/--run-optimal-benchmarks Perform an automatic parameter tuning benchmark:\n"
+ " -g/--optimal-clock-limit Wall clock time limit for optimal benchmarks\n"
+ " (in seconds, fractional values accepted)\n"
#ifdef HAVE_LIBARGON2
- " -l/--memlimit Memory limit for optimal benchmarking (power of 2, in KiB)\n"
- " For example, '-l 16' means 2^16 KiB; 65536 KiB; 64 MiB\n"
+ " -l/--optimal-memory-limit Memory limit for optimal benchmarking\n"
+ " (as a power of 2, in KiB)\n"
+ " For example, '-l 16' means 2^16 KiB; 64 MiB\n"
#else
- " -l/--memlimit Unsupported\n"
+ " -l/--optimal-memory-limit Unsupported\n"
#endif
"\n"
" If one of the above limits are not given, defaults are used.\n"
#ifdef HAVE_LIBARGON2
"\n"
- " -a/--argon2 Benchmark the Argon2 code over a variety of configurations\n"
- " -m/--memory Comma-separated Argon2 memory costs to benchmark\n"
- " -n/--type Comma-separated Argon2 types to benchmark\n"
- " -p/--threads Comma-separated Argon2 thread counts to benchmark\n"
- " -t/--time Comma-separated Argon2 time costs to benchmark\n"
+ " -a/--run-argon2-benchmarks Benchmark the Argon2 code with configurations:\n"
+ " -n/--argon2-types Comma-separated types\n"
+ " -m/--argon2-memory-costs Comma-separated memory costs\n"
+ " -t/--argon2-time-costs Comma-separated time costs\n"
+ " -p/--argon2-threads Comma-separated thread counts\n"
+ "\n"
+ " Valid types are: Argon2d, Argon2i, Argon2id (case-insensitive)\n"
#endif
"\n"
- " -k/--pbkdf2 Benchmark the PBKDF2 code over a variety of configurations\n"
- " -c/--iterations Comma-separated PBKDF2 iteration counts to benchmark\n"
- " -d/--digests Comma-separated PBKDF2 digest algorithms to benchmark\n"
+ " -k/--run-pbkdf2-benchmarks Benchmark the PBKDF2 code with configurations:\n"
+ " -c/--pbkdf2-iterations Comma-separated iteration counts\n"
+ " -d/--pbkdf2-digests Comma-separated digest algorithms\n"
+ "\n"
+ " Valid digests are: MD5, SHA1, SHA2-256, SHA2-512 (case-insensitive)\n"
"\n"
" If one of the comma-separated options are not given, defaults are used.\n"
"\n");
static bool
process_options(int argc, char *argv[])
{
+ char bench_short_opts[BUFSIZE];
+
+ char *ptr = bench_short_opts;
char *opt;
char *tok;
int c;
+ (void) memset(bench_short_opts, 0x00, sizeof bench_short_opts);
+
+ for (size_t x = 0; bench_long_opts[x].name != NULL; x++)
+ {
+ *ptr++ = bench_long_opts[x].val;
+
+ if (bench_long_opts[x].has_arg == no_argument)
+ continue;
+
+ *ptr++ = ':';
+
+ if (bench_long_opts[x].has_arg == optional_argument)
+ *ptr++ = ':';
+ }
+
while ((c = mowgli_getopt_long(argc, argv, bench_short_opts, bench_long_opts, NULL)) != -1)
{
switch (c)
exit(EXIT_SUCCESS);
case 'v':
- (void) fprintf(stderr, "%s\n", PACKAGE_STRING);
+ // Version string was already printed at program startup
exit(EXIT_SUCCESS);
case 'o':
- run_optimal_benchmarks = true;
+ run_options |= BENCH_RUN_OPTIONS_OPTIMAL;
break;
case 'g':
char *end = NULL;
const long double ret = strtold(mowgli_optarg, &end);
- if (! ret || (end && *end))
+ if (! ret || (end && *end) || errno != 0)
{
(void) fprintf(stderr, "'%s' is not a valid value for decimal option '%c'\n",
mowgli_optarg, c);
return false;
}
+ if (ret < BENCH_CLOCKTIME_MIN || ret > BENCH_CLOCKTIME_MAX)
+ {
+ (void) fprintf(stderr, "'%s' is not a valid value for decimal option '%c'\n",
+ mowgli_optarg, c);
+ (void) fprintf(stderr, "range of valid values: %LF to %LF (inclusive)\n",
+ BENCH_CLOCKTIME_MIN, BENCH_CLOCKTIME_MAX);
+ return false;
+ }
optimal_clocklimit = ret;
break;
(void) fprintf(stderr, "'%s' is not a valid value for integer option '%c'\n",
mowgli_optarg, c);
(void) fprintf(stderr, "range of valid values: %u to %u (inclusive)\n",
- ARGON2_MEMCOST_MIN, ARGON2_MEMCOST_MAX);
+ BENCH_MEMLIMIT_MIN, BENCH_MEMLIMIT_MAX);
return false;
}
- if (optimal_memlimit < ARGON2_MEMCOST_MIN || optimal_memlimit > ARGON2_MEMCOST_MAX)
+ if (optimal_memlimit < BENCH_MEMLIMIT_MIN || optimal_memlimit > BENCH_MEMLIMIT_MAX)
{
(void) fprintf(stderr, "'%u' is not a valid value for integer option '%c'\n",
optimal_memlimit, c);
(void) fprintf(stderr, "range of valid values: %u to %u (inclusive)\n",
- ARGON2_MEMCOST_MIN, ARGON2_MEMCOST_MAX);
+ BENCH_MEMLIMIT_MIN, BENCH_MEMLIMIT_MAX);
return false;
}
+ optimal_memlimit_given = true;
break;
case 'a':
- run_argon2_benchmarks = true;
+ run_options |= BENCH_RUN_OPTIONS_ARGON2;
break;
case 'n':
}
while ((tok = strsep(&opt, ",")) != NULL)
{
- const argon2_type b_type = argon2_name_to_type(tok);
+ const argon2_type b_argon2_type = argon2_name_to_type(tok);
- if (! (b_types = sreallocarray(b_types, b_types_count + 1, sizeof b_type)))
+ if (! (b_argon2_types = sreallocarray(b_argon2_types,
+ b_argon2_types_count + 1,
+ sizeof b_argon2_type)))
{
(void) perror("sreallocarray()");
return false;
}
- b_types[b_types_count++] = b_type;
+ b_argon2_types[b_argon2_types_count++] = b_argon2_type;
}
(void) free(opt);
}
case 'm':
- if (! process_uint_option(c, mowgli_optarg, &b_memcosts, &b_memcosts_count,
- ARGON2_MEMCOST_MIN, ARGON2_MEMCOST_MAX))
+ if (! process_uint_option(c, mowgli_optarg, &b_argon2_memcosts,
+ &b_argon2_memcosts_count, ARGON2_MEMCOST_MIN,
+ ARGON2_MEMCOST_MAX))
// This function logs error messages on failure
return false;
break;
case 't':
- if (! process_uint_option(c, mowgli_optarg, &b_timecosts, &b_timecosts_count,
- ARGON2_TIMECOST_MIN, ARGON2_TIMECOST_MAX))
+ if (! process_uint_option(c, mowgli_optarg, &b_argon2_timecosts,
+ &b_argon2_timecosts_count, ARGON2_TIMECOST_MIN,
+ ARGON2_TIMECOST_MAX))
// This function logs error messages on failure
return false;
break;
case 'p':
- if (! process_uint_option(c, mowgli_optarg, &b_threads, &b_threads_count,
- ARGON2_THREADS_MIN, ARGON2_THREADS_MAX))
+ if (! process_uint_option(c, mowgli_optarg, &b_argon2_threads,
+ &b_argon2_threads_count, ARGON2_THREADS_MIN,
+ ARGON2_THREADS_MAX))
// This function logs error messages on failure
return false;
#endif /* HAVE_LIBARGON2 */
case 'k':
- run_pbkdf2_benchmarks = true;
+ run_options |= BENCH_RUN_OPTIONS_PBKDF2;
break;
case 'c':
- if (! process_uint_option(c, mowgli_optarg, &b_itercounts, &b_itercounts_count,
- PBKDF2_ITERCNT_MIN, PBKDF2_ITERCNT_MAX))
+ if (! process_uint_option(c, mowgli_optarg, &b_pbkdf2_itercounts,
+ &b_pbkdf2_itercounts_count, PBKDF2_ITERCNT_MIN,
+ PBKDF2_ITERCNT_MAX))
// This function logs error messages on failure
return false;
}
while ((tok = strsep(&opt, ",")) != NULL)
{
- const enum digest_algorithm b_digest = md_name_to_digest(tok);
+ const enum digest_algorithm b_pbkdf2_digest = md_name_to_digest(tok);
- if (! (b_digests = sreallocarray(b_digests, b_digests_count + 1,
- sizeof b_digest)))
+ if (! (b_pbkdf2_digests = sreallocarray(b_pbkdf2_digests,
+ b_pbkdf2_digests_count + 1,
+ sizeof b_pbkdf2_digest)))
{
(void) perror("sreallocarray()");
return false;
}
- b_digests[b_digests_count++] = b_digest;
+ b_pbkdf2_digests[b_pbkdf2_digests_count++] = b_pbkdf2_digest;
}
(void) free(opt);
}
}
- if (! (run_optimal_benchmarks || run_argon2_benchmarks || run_pbkdf2_benchmarks))
+ if (! run_options || (run_options & (run_options - 1U)))
{
(void) print_usage();
+ (void) fprintf(stderr, "Error: Conflicting options (or no options) given.\n");
+ (void) fprintf(stderr, "\n");
return false;
}
- if (! b_itercounts)
+#ifdef HAVE_LIBARGON2
+ if (! b_argon2_types)
{
- b_itercounts = b_itercounts_default;
- b_itercounts_count = BENCH_ARRAY_SIZE(b_itercounts_default);
+ b_argon2_types = b_argon2_types_default;
+ b_argon2_types_count = BENCH_ARRAY_SIZE(b_argon2_types_default);
}
- if (! b_digests)
+ if (! b_argon2_memcosts)
{
- b_digests = b_digests_default;
- b_digests_count = BENCH_ARRAY_SIZE(b_digests_default);
+ b_argon2_memcosts = b_argon2_memcosts_default;
+ b_argon2_memcosts_count = BENCH_ARRAY_SIZE(b_argon2_memcosts_default);
}
-#ifdef HAVE_LIBARGON2
- if (! b_types)
+ if (! b_argon2_timecosts)
{
- b_types = b_types_default;
- b_types_count = BENCH_ARRAY_SIZE(b_types_default);
+ b_argon2_timecosts = b_argon2_timecosts_default;
+ b_argon2_timecosts_count = BENCH_ARRAY_SIZE(b_argon2_timecosts_default);
}
- if (! b_memcosts)
+ if (! b_argon2_threads)
{
- b_memcosts = b_memcosts_default;
- b_memcosts_count = BENCH_ARRAY_SIZE(b_memcosts_default);
+ b_argon2_threads = b_argon2_threads_default;
+ b_argon2_threads_count = BENCH_ARRAY_SIZE(b_argon2_threads_default);
}
- if (! b_timecosts)
+#endif /* HAVE_LIBARGON2 */
+
+ if (! b_pbkdf2_itercounts)
{
- b_timecosts = b_timecosts_default;
- b_timecosts_count = BENCH_ARRAY_SIZE(b_timecosts_default);
+ b_pbkdf2_itercounts = b_pbkdf2_itercounts_default;
+ b_pbkdf2_itercounts_count = BENCH_ARRAY_SIZE(b_pbkdf2_itercounts_default);
}
- if (! b_threads)
+ if (! b_pbkdf2_digests)
{
- b_threads = b_threads_default;
- b_threads_count = BENCH_ARRAY_SIZE(b_threads_default);
+ b_pbkdf2_digests = b_pbkdf2_digests_default;
+ b_pbkdf2_digests_count = BENCH_ARRAY_SIZE(b_pbkdf2_digests_default);
}
-#endif /* HAVE_LIBARGON2 */
return true;
}
#ifdef HAVE_LIBARGON2
-static inline bool ATHEME_FATTR_WUR
-do_argon2_benchmark(const argon2_type type, const size_t memcost, const size_t timecost, const size_t threads)
-{
- long double elapsed;
-
- if (! benchmark_argon2(type, memcost, timecost, threads, &elapsed))
- // This function logs error messages on failure
- return false;
-
- (void) fprintf(stderr, "%10s %10zu %8zu %4zu %12LF\n", argon2_type_to_name(type),
- memcost, timecost, threads, elapsed);
- return true;
-}
-
static bool ATHEME_FATTR_WUR
do_argon2_benchmarks(void)
{
(void) argon2_print_colheaders();
- for (size_t b_type = 0; b_type < b_types_count; b_type++)
- for (size_t b_memcost = 0; b_memcost < b_memcosts_count; b_memcost++)
- for (size_t b_timecost = 0; b_timecost < b_timecosts_count; b_timecost++)
- for (size_t b_thread = 0; b_thread < b_threads_count; b_thread++)
- if (! do_argon2_benchmark(b_types[b_type], b_memcosts[b_memcost],
- b_timecosts[b_timecost], b_threads[b_thread]))
+ for (size_t b_argon2_type = 0; b_argon2_type < b_argon2_types_count; b_argon2_type++)
+ for (size_t b_argon2_memcost = 0; b_argon2_memcost < b_argon2_memcosts_count; b_argon2_memcost++)
+ for (size_t b_argon2_timecost = 0; b_argon2_timecost < b_argon2_timecosts_count; b_argon2_timecost++)
+ for (size_t b_argon2_thread = 0; b_argon2_thread < b_argon2_threads_count; b_argon2_thread++)
+ if (! benchmark_argon2(b_argon2_types[b_argon2_type], b_argon2_memcosts[b_argon2_memcost],
+ b_argon2_timecosts[b_argon2_timecost], b_argon2_threads[b_argon2_thread], NULL))
// This function logs error messages on failure
return false;
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "\n");
return true;
}
#endif /* HAVE_LIBARGON2 */
-static inline bool ATHEME_FATTR_WUR
-do_pbkdf2_benchmark(const enum digest_algorithm digest, const size_t iterations)
-{
- long double elapsed;
-
- if (! benchmark_pbkdf2(digest, iterations, &elapsed))
- // This function logs error messages on failure
- return false;
-
- (void) fprintf(stderr, "%8s %8zu %12LF\n", md_digest_to_name(digest), iterations, elapsed);
- return true;
-}
-
static bool ATHEME_FATTR_WUR
do_pbkdf2_benchmarks(void)
{
(void) pbkdf2_print_colheaders();
- for (size_t b_digest = 0; b_digest < b_digests_count; b_digest++)
- for (size_t b_itercount = 0; b_itercount < b_itercounts_count; b_itercount++)
- if (! do_pbkdf2_benchmark(b_digests[b_digest], b_itercounts[b_itercount]))
+ for (size_t b_pbkdf2_digest = 0; b_pbkdf2_digest < b_pbkdf2_digests_count; b_pbkdf2_digest++)
+ for (size_t b_pbkdf2_itercount = 0; b_pbkdf2_itercount < b_pbkdf2_itercounts_count; b_pbkdf2_itercount++)
+ if (! benchmark_pbkdf2(b_pbkdf2_digests[b_pbkdf2_digest], b_pbkdf2_itercounts[b_pbkdf2_itercount], NULL))
// This function logs error messages on failure
return false;
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "\n");
return true;
}
int
main(int argc, char *argv[])
{
+ (void) print_version();
+
if (! benchmark_init())
// This function logs error messages on failure
return EXIT_FAILURE;
// This function logs error messages on failure
return EXIT_FAILURE;
- (void) fprintf(stderr, "\n");
- (void) fprintf(stderr, "%s\n", PACKAGE_STRING);
- (void) fprintf(stderr, "Using digest frontend: %s\n", digest_get_frontend_info());
- (void) fprintf(stderr, "\n");
-
#if (ATHEME_API_DIGEST_FRONTEND == ATHEME_API_DIGEST_FRONTEND_INTERNAL) && !defined(IN_CI_BUILD_ENVIRONMENT)
- (void) fprintf(stderr, "WARNING: This program will perform significantly better if you build it\n");
- (void) fprintf(stderr, " against a supported third-party cryptographic digest library.\n");
(void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "NOTE: This program may perform significantly better if you build it\n");
+ (void) fprintf(stderr, " against a supported third-party cryptographic digest library!\n");
#endif
- if (run_optimal_benchmarks && ! do_optimal_benchmarks(optimal_clocklimit, optimal_memlimit))
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "\n");
+
+ if ((run_options & BENCH_RUN_OPTIONS_OPTIMAL) &&
+ ! do_optimal_benchmarks(optimal_clocklimit, optimal_memlimit, optimal_memlimit_given))
// This function logs error messages on failure
return EXIT_FAILURE;
#ifdef HAVE_LIBARGON2
- if (run_argon2_benchmarks && ! do_argon2_benchmarks())
+ if ((run_options & BENCH_RUN_OPTIONS_ARGON2) && ! do_argon2_benchmarks())
// This function logs error messages on failure
return EXIT_FAILURE;
#endif /* HAVE_LIBARGON2 */
- if (run_pbkdf2_benchmarks && ! do_pbkdf2_benchmarks())
+ if ((run_options & BENCH_RUN_OPTIONS_PBKDF2) && ! do_pbkdf2_benchmarks())
// This function logs error messages on failure
return EXIT_FAILURE;
* copyright notice and this permission notice appear in all copies.
*/
-#include <atheme/attributes.h> // ATHEME_FATTR_WUR
-#include <atheme/argon2.h> // ARGON2_*
-#include <atheme/digest.h> // DIGALG_*, digest_oneshot_pbkdf2()
-#include <atheme/pbkdf2.h> // PBKDF2_*
-#include <atheme/stdheaders.h> // (everything else)
-#include <atheme/sysconf.h> // HAVE_LIBARGON2
+#include <atheme/attributes.h> // ATHEME_FATTR_WUR
+#include <atheme/argon2.h> // ARGON2_*
+#include <atheme/digest.h> // DIGALG_*, digest_oneshot_pbkdf2()
+#include <atheme/pbkdf2.h> // PBKDF2_*
+#include <atheme/stdheaders.h> // (everything else)
+#include <atheme/sysconf.h> // HAVE_LIBARGON2
-#include "benchmark.h" // benchmark_*()
-#include "optimal.h" // self-declarations
-#include "utils.h" // (everything else)
+#ifdef HAVE_LIBARGON2
+# include <argon2.h> // argon2_type, argon2_type2string()
+#endif
+
+#include "benchmark.h" // (everything else)
+#include "optimal.h" // self-declarations
#ifdef HAVE_LIBARGON2
static bool ATHEME_FATTR_WUR
-do_optimal_argon2_benchmark(const long double clocklimit, const size_t memlimit)
+do_optimal_argon2_benchmark(const long double optimal_clocklimit, const size_t optimal_memlimit)
{
(void) fprintf(stderr, "Beginning automatic optimal Argon2 benchmark ...\n");
+ (void) fprintf(stderr, "\n");
(void) fprintf(stderr, "NOTE: This does not test multithreading. Use '-a -p' for thread testing.\n");
(void) fprintf(stderr, "\n");
(void) argon2_print_colheaders();
- const argon2_type type = Argon2_id;
- size_t memcost = memlimit;
- size_t timecost = ARGON2_TIMECOST_MIN;
- const size_t threads = 1U;
-
- bool timecost_raised = false;
long double elapsed_prev = 0L;
long double elapsed = 0L;
+ size_t timecost_prev = 0U;
+
+ const argon2_type type = Argon2_id;
+ size_t memcost = optimal_memlimit;
+ size_t timecost = ARGON2_TIMECOST_MIN;
+ const size_t threads = 1ULL;
// First try at our memory limit and the minimum time cost
if (! benchmark_argon2(type, memcost, timecost, threads, &elapsed))
return false;
// If that's still too slow, halve the memory usage until it isn't
- while (elapsed > clocklimit)
+ while (elapsed > optimal_clocklimit)
{
if (memcost <= ARGON2_MEMCOST_MIN)
{
}
// Now that it's fast enough, raise the time cost until it isn't
- while (elapsed <= clocklimit)
+ while (elapsed < optimal_clocklimit)
{
- timecost++;
- timecost_raised = true;
elapsed_prev = elapsed;
+ timecost_prev = timecost;
+ timecost++;
if (! benchmark_argon2(type, memcost, timecost, threads, &elapsed))
// This function logs error messages on failure
return false;
}
- // If it was raised, go back to the previous loop's outputs
- if (timecost_raised)
+ // If it was raised, go back to the previous loop's outputs (now that it's too slow)
+ if (timecost_prev)
{
- timecost--;
elapsed = elapsed_prev;
+ timecost = timecost_prev;
}
(void) fprintf(stderr, "\n");
(void) fprintf(stderr, "\n");
(void) fflush(stderr);
(void) fprintf(stdout, "crypto {\n");
- (void) fprintf(stdout, "\t/* Target: %LFs; Benchmarked: %LFs */\n", clocklimit, elapsed);
- (void) fprintf(stdout, "\targon2_type = \"%s\";\n", argon2_type_to_name(type));
- (void) fprintf(stdout, "\targon2_memcost = %zu; /* %u KiB */ \n", memcost, (1U << memcost));
+ (void) fprintf(stdout, "\t/* Target: %LFs; Benchmarked: %LFs */\n", optimal_clocklimit, elapsed);
+ (void) fprintf(stdout, "\targon2_type = \"%s\";\n", argon2_type2string(type, 0));
+ (void) fprintf(stdout, "\targon2_memcost = %zu; /* %llu KiB */ \n", memcost, (1ULL << memcost));
(void) fprintf(stdout, "\targon2_timecost = %zu;\n", timecost);
(void) fprintf(stdout, "\targon2_threads = %zu;\n", threads);
(void) fprintf(stdout, "};\n");
(void) fflush(stdout);
+ (void) fsync(fileno(stdout));
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "\n");
(void) fprintf(stderr, "\n");
(void) fflush(stderr);
return true;
#endif /* HAVE_LIBARGON2 */
static bool ATHEME_FATTR_WUR
-do_optimal_pbkdf2_benchmark(const long double clocklimit)
+do_optimal_pbkdf2_benchmark(const long double optimal_clocklimit)
{
(void) fprintf(stderr, "Beginning automatic optimal PBKDF2 benchmark ...\n");
+ (void) fprintf(stderr, "\n");
(void) fprintf(stderr, "NOTE: This does not test SHA1. Use '-k -d' for SHA1 testing.\n");
- (void) fprintf(stderr, "NOTE: If you wish to support SASL SCRAM logins, please see\n");
- (void) fprintf(stderr, " the 'doc/SASL-SCRAM-SHA' file, whose parameter advice\n");
- (void) fprintf(stderr, " takes precedence over the advice given here.\n");
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "NOTE: If you wish to support SASL SCRAM logins, please see the\n");
+ (void) fprintf(stderr, " 'doc/SASL-SCRAM-SHA' file in the source code repository, whose parameter\n");
+ (void) fprintf(stderr, " advice takes precedence over the advice given by this benchmark utility!\n");
(void) fprintf(stderr, "\n");
(void) pbkdf2_print_colheaders();
elapsed = elapsed_sha512;
}
+ /* PBKDF2 is pretty linear: There's only one parameter (iteration count), and it has
+ * almost perfect scaling on the algorithm's runtime. This enables a very simplified
+ * optimal parameter discovery process, compared to the other functions above.
+ */
const char *const mdname = md_digest_to_name(md);
- size_t iterations = (size_t) (initial / (elapsed / clocklimit));
+ size_t iterations = (size_t) (initial * (optimal_clocklimit / elapsed));
iterations -= (iterations % 1000U);
iterations = BENCH_MIN(initial, iterations);
- while (elapsed > clocklimit)
+ while (elapsed > optimal_clocklimit)
{
if (iterations <= PBKDF2_ITERCNT_MIN)
{
(void) fprintf(stderr, "\n");
(void) fflush(stderr);
(void) fprintf(stdout, "crypto {\n");
- (void) fprintf(stdout, "\t/* Target: %LFs; Benchmarked: %LFs */\n", clocklimit, elapsed);
+ (void) fprintf(stdout, "\t/* Target: %LFs; Benchmarked: %LFs */\n", optimal_clocklimit, elapsed);
(void) fprintf(stdout, "\tpbkdf2v2_digest = \"%s\";\n", mdname);
(void) fprintf(stdout, "\tpbkdf2v2_rounds = %zu;\n", iterations);
(void) fprintf(stdout, "};\n");
(void) fflush(stdout);
+ (void) fsync(fileno(stdout));
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "\n");
(void) fprintf(stderr, "\n");
(void) fflush(stderr);
return true;
}
bool ATHEME_FATTR_WUR
-do_optimal_benchmarks(const long double clocklimit, const unsigned int memlimit)
+do_optimal_benchmarks(const long double optimal_clocklimit, const size_t ATHEME_VATTR_MAYBE_UNUSED optimal_memlimit,
+ const bool ATHEME_VATTR_MAYBE_UNUSED optimal_memlimit_given)
{
#ifdef HAVE_LIBARGON2
- if (! do_optimal_argon2_benchmark(clocklimit, memlimit))
+ if (! optimal_memlimit_given)
+ {
+ (void) fprintf(stderr, "Be sure to specify -L/--optimal-memory-limit appropriately for this machine!\n");
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "\n");
+ (void) fprintf(stderr, "\n");
+ }
+
+ if (! do_optimal_argon2_benchmark(optimal_clocklimit, optimal_memlimit))
// This function logs error messages on failure
return false;
#endif
- if (! do_optimal_pbkdf2_benchmark(clocklimit))
+
+ if (! do_optimal_pbkdf2_benchmark(optimal_clocklimit))
// This function logs error messages on failure
return false;