From fac645f7780c7673775f09fe625651f600f7ee7b Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Wed, 18 May 2016 10:29:03 +0100 Subject: [PATCH] Add a pile of debug output around the CPU dispatching machinery. Report on finding things in the environment, progress on runtime probes, and the decisions about which implementations we pick. Decision-making isn't time-critical, so this is left in permanently. --- base/dispatch.c | 74 +++++++++++++++++++++++++++++++++++++++++----------- base/dispatch.h | 26 ++++++++++++++++++ symm/chacha.c | 5 ++-- symm/rijndael-base.c | 5 ++-- symm/rijndael.c | 10 ++++--- symm/salsa20.c | 5 ++-- 6 files changed, 100 insertions(+), 25 deletions(-) diff --git a/base/dispatch.c b/base/dispatch.c index 4b5e17a9..eedf0172 100644 --- a/base/dispatch.c +++ b/base/dispatch.c @@ -30,6 +30,8 @@ #include "config.h" #include +#include +#include #include #include @@ -85,8 +87,11 @@ static void cpuid(struct cpuid *cc, unsigned a, unsigned c) #ifdef __GNUC__ /* Stupid dance to detect whether the CPUID instruction is available. */ f = getflags(); - if (!(setflags(f | EFLAGS_ID) & EFLAGS_ID)) return; - if ( setflags(f & ~EFLAGS_ID) & EFLAGS_ID ) return; + if (!(setflags(f | EFLAGS_ID) & EFLAGS_ID) || + setflags(f & ~EFLAGS_ID) & EFLAGS_ID) { + dispatch_debug("CPUID instruction not available"); + return; + } setflags(f); /* Alas, EBX is magical in PIC code, so abuse ESI instead. This isn't @@ -95,6 +100,8 @@ static void cpuid(struct cpuid *cc, unsigned a, unsigned c) __asm__ ("pushl %%ebx; cpuid; movl %%ebx, %%esi; popl %%ebx" : "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d) : "a" (a) , "c" (c)); +#else + dispatch_debug("GNU inline assembler not available; can't CPUID"); #endif } @@ -146,6 +153,7 @@ static int xmm_registers_available_p(void) : "%ecx", "%edx"); return (f); #else + dispatch_debug("GNU inline assembler not available; can't check for XMM"); return (0); #endif } @@ -154,6 +162,31 @@ static int xmm_registers_available_p(void) /*----- External interface ------------------------------------------------*/ +/* --- @dispatch_debug@ --- * + * + * Arguments: @const char *fmt@ = a format string + * @...@ = additional arguments + * + * Returns: --- + * + * Use: Writes a formatted message to standard output if dispatch + * debugging is enabled. + */ + +void dispatch_debug(const char *fmt, ...) +{ + va_list ap; + const char *e = getenv("CATACOMB_CPUDISPATCH_DEBUG"); + + if (e && *e != 'n' && *e != '0') { + va_start(ap, fmt); + fputs("Catacomb CPUDISPATCH: ", stderr); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); + } +} + /* --- @check_env@ --- * * * Arguments: @const char *ftok@ = feature token @@ -202,30 +235,41 @@ static int IGNORABLE check_env(const char *ftok) #include +static int IGNORABLE + feat_debug(const char *ftok, const char *check, int verdict) +{ + if (verdict >= 0) { + dispatch_debug("feature `%s': %s -> %s", ftok, check, + verdict ? "available" : "absent"); + } + return (verdict); +} + int cpu_feature_p(int feat) { int IGNORABLE f; IGNORE(f); -#define CHECK_ENV(ftok) \ - do { if ((f = check_env(ftok)) >= 0) return (f); } while (0) +#define CASE_CPUFEAT(feat, ftok, cond) case CPUFEAT_##feat: \ + if ((f = feat_debug(ftok, "environment override", \ + check_env(ftok))) >= 0) \ + return (f); \ + else \ + return (feat_debug(ftok, "runtime probe", cond)); switch (feat) { #ifdef CPUFAM_X86 - case CPUFEAT_X86_SSE2: { - CHECK_ENV("x86:sse2"); - return (xmm_registers_available_p() && - cpuid_features_p(CPUID1D_SSE2, 0)); - } - case CPUFEAT_X86_AESNI: { - check_env("x86:aesni"); - return (xmm_registers_available_p() && - cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI)); - } + CASE_CPUFEAT(X86_SSE2, "x86:sse2", + xmm_registers_available_p() && + cpuid_features_p(CPUID1D_SSE2, 0)); + CASE_CPUFEAT(X86_AESNI, "x86:aesni", + xmm_registers_available_p() && + cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI)); #endif default: + dispatch_debug("denying unknown feature %d", feat); return (0); } -#undef CHECK_ENV +#undef CASE_CPUFEAT } /*----- That's all, folks -------------------------------------------------*/ diff --git a/base/dispatch.h b/base/dispatch.h index 612cfcd3..bbb81f30 100644 --- a/base/dispatch.h +++ b/base/dispatch.h @@ -138,8 +138,34 @@ stcls ret ext argdecls { rtn dflt args; } #endif +/* --- Some macros for producing useful debugging --- */ + +#define DISPATCH_PICK_COND(what, func, cond) do { \ + if (cond) { \ + dispatch_debug("picked `%s' for `%s'", #func, #what); \ + return (func); \ + } \ +} while (0) +#define DISPATCH_PICK_FALLBACK(what, func) do { \ + dispatch_debug("using default `%s'", #what); \ + return (func); \ +} while (0) + /*----- Functions provided ------------------------------------------------*/ +/* --- @dispatch_debug@ --- * + * + * Arguments: @const char *fmt@ = a format string + * @...@ = additional arguments + * + * Returns: --- + * + * Use: Writes a formatted message to standard output if dispatch + * debugging is enabled. + */ + +extern void dispatch_debug(const char */*fmt*/, ...); + /* --- @cpu_feature_p@ --- * * * Arguments: @unsigned feat@ = a @CPUFEAT_...@ code diff --git a/symm/chacha.c b/symm/chacha.c index 8fe50e19..5683c8e9 100644 --- a/symm/chacha.c +++ b/symm/chacha.c @@ -79,9 +79,10 @@ extern core__functype chacha_core_x86_sse2; static core__functype *pick_core(void) { #ifdef CPUFAM_X86 - if (cpu_feature_p(CPUFEAT_X86_SSE2)) return chacha_core_x86_sse2; + DISPATCH_PICK_COND(chacha_core, chacha_core_x86_sse2, + cpu_feature_p(CPUFEAT_X86_SSE2)); #endif - return simple_core; + DISPATCH_PICK_FALLBACK(chacha_core, simple_core); } /* --- @populate@ --- * diff --git a/symm/rijndael-base.c b/symm/rijndael-base.c index 6e59130c..3d2bb8ef 100644 --- a/symm/rijndael-base.c +++ b/symm/rijndael-base.c @@ -123,9 +123,10 @@ extern setup__functype rijndael_setup_x86_aesni; static setup__functype *pick_setup(void) { #ifdef CPUFAM_X86 - if (cpu_feature_p(CPUFEAT_X86_AESNI)) return rijndael_setup_x86_aesni; + DISPATCH_PICK_COND(rijndael_setup, rijndael_setup_x86_aesni, + cpu_feature_p(CPUFEAT_X86_AESNI)); #endif - return simple_setup; + DISPATCH_PICK_FALLBACK(rijndael_setup, simple_setup); } void rijndael_setup(rijndael_ctx *k, unsigned nb, const void *buf, size_t sz) diff --git a/symm/rijndael.c b/symm/rijndael.c index 9ee8aa28..dcb35e61 100644 --- a/symm/rijndael.c +++ b/symm/rijndael.c @@ -90,17 +90,19 @@ extern rijndael_dblk__functype rijndael_dblk_x86_aesni; static rijndael_eblk__functype *pick_eblk(void) { #ifdef CPUFAM_X86 - if (cpu_feature_p(CPUFEAT_X86_AESNI)) return rijndael_eblk_x86_aesni; + DISPATCH_PICK_COND(rijndael_eblk, rijndael_eblk_x86_aesni, + cpu_feature_p(CPUFEAT_X86_AESNI)); #endif - return simple_eblk; + DISPATCH_PICK_FALLBACK(rijndael_eblk, simple_eblk); } static rijndael_dblk__functype *pick_dblk(void) { #ifdef CPUFAM_X86 - if (cpu_feature_p(CPUFEAT_X86_AESNI)) return rijndael_dblk_x86_aesni; + DISPATCH_PICK_COND(rijndael_dblk, rijndael_dblk_x86_aesni, + cpu_feature_p(CPUFEAT_X86_AESNI)); #endif - return simple_dblk; + DISPATCH_PICK_FALLBACK(rijndael_dblk, simple_dblk); } #define DO(what, t, aa, bb, cc, dd, a, b, c, d, w) do { \ diff --git a/symm/salsa20.c b/symm/salsa20.c index d3fb69a7..15e4d50e 100644 --- a/symm/salsa20.c +++ b/symm/salsa20.c @@ -59,9 +59,10 @@ extern core__functype salsa20_core_x86_sse2; static core__functype *pick_core(void) { #ifdef CPUFAM_X86 - if (cpu_feature_p(CPUFEAT_X86_SSE2)) return salsa20_core_x86_sse2; + DISPATCH_PICK_COND(salsa20_core, salsa20_core_x86_sse2, + cpu_feature_p(CPUFEAT_X86_SSE2)); #endif - return simple_core; + DISPATCH_PICK_FALLBACK(salsa20_core, simple_core); } /* --- @populate@ --- * -- 2.11.0