#include #include #include #include #include #include #include #include "cprng.h" #include "crypto_test.h" #define CYCLECOUNTER_RDTSC #ifdef CYCLECOUNTER_RDTSC /* * rdtsc is not actually a cycle counter, it turns out -- it always * ticks at the same duration independent of CPU frequency scaling. */ typedef uint64_t cyclecounter_t; static uint64_t rdtsc(void) { uint32_t low, high; __asm__ __volatile__ ("rdtsc" : "=a"(low), "=d"(high)); return ((uint64_t)high << 32) | low; } static void cyclecounter_start(cyclecounter_t *cyclecounter) { *cyclecounter = rdtsc(); } static double cyclecounter_end(cyclecounter_t *cyclecounter) { return (double)(rdtsc() - *cyclecounter); } #else /* * Measuring real times works if (a) there is no dynamic CPU frequency * scaling, and (b) you know your CPU's frequency. Because I am lazy, * CYCLES_PER_NS is hard-coded. */ #include #define CYCLES_PER_NS 1.2 /* 1.2 GHz */ typedef struct timespec cyclecounter_t; static void cyclecounter_start(cyclecounter_t *cyclecounter) { if (clock_gettime(CLOCK_MONOTONIC, cyclecounter) == -1) err(1, "clock_gettime"); } static double cyclecounter_end(cyclecounter_t *cyclecounter) { struct timespec now, diff; double nanoseconds; if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) err(1, "clock_gettime"); timespecsub(&now, cyclecounter, &diff); nanoseconds = timespec2ns(&diff); return (nanoseconds * CYCLES_PER_NS); } #endif static struct cprng cprng; static void seed(void) { uint8_t s[32]; static int fd = -1; if (fd == -1) { fd = open("/dev/urandom", O_RDONLY); if (fd == -1) err(1, "open"); } const ssize_t nread = read(fd, s, sizeof s); if (nread == -1) err(1, "read"); if (nread != 32) errx(1, "short read: %zd != 32", nread); cprng_seed(&cprng, s); } static volatile sig_atomic_t alarmed; static void alarm_handler(int signo __unused) { alarmed = 1; } #define MISALIGN_PTR 0 #define MISALIGN_LEN 0 unsigned char buf[0x10000 + MISALIGN_PTR + MISALIGN_LEN]; int main(int argc, char **argv) { cyclecounter_t cyclecounter; double cycles; unsigned int i, n, c; if (signal(SIGALRM, &alarm_handler) == SIG_ERR) err(1, "signal(SIGALRM)"); crypto_test(); printf("%6s %10s %12s %12s %14s\n", "bytes", "iters", "cycles", "cpb", "cpi"); (void)i; #if 1 printf("* cprng_buf\n"); for (i = 0; i <= 16; i++) { n = (1 << i) + MISALIGN_LEN; c = 0; seed(); alarmed = 0; alarm(3); cyclecounter_start(&cyclecounter); while (!alarmed) { cprng_buf(&cprng, buf + MISALIGN_PTR, n); c++; } cycles = cyclecounter_end(&cyclecounter); (void)printf("%6u %10u %12f %12f %14f\n", n, c, cycles, (cycles / ((double)n * c)), (cycles / c)); } #endif printf("* cprng32\n"); n = 4; c = 0; seed(); alarmed = 0; alarm(3); cyclecounter_start(&cyclecounter); while (!alarmed) { volatile uint32_t v __unused = cprng32(&cprng); c++; } cycles = cyclecounter_end(&cyclecounter); (void)printf("%6u %10u %12f %12f %14f\n", n, c, cycles, (cycles / ((double)n * c)), (cycles / c)); printf("* cprng64\n"); n = 8; c = 0; seed(); alarmed = 0; alarm(3); cyclecounter_start(&cyclecounter); while (!alarmed) { volatile uint64_t v __unused = cprng64(&cprng); c++; } cycles = cyclecounter_end(&cyclecounter); (void)printf("%6u %10u %12f %12f %14f\n", n, c, cycles, (cycles / ((double)n * c)), (cycles / c)); return 0; }