diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 115 |
1 files changed, 115 insertions, 0 deletions
@@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/sort.h> +#include <linux/random.h> +#include <asm/cpufeature.h> +#include <asm/processor.h> +#include <asm/fpu/api.h> +#include <asm/simd.h> + +static unsigned long stamp = 0; +module_param(stamp, ulong, 0); + +#define declare_it(name) bool mix_ ##name(void *input, size_t len); + +#define do_it(name, input, len) do { \ + u32 eax = 0, ebx = 0, ecx = 0, edx = 0; \ + for (i = 0; i < WARMUP; ++i) \ + ret |= mix_ ##name(input, len); \ + asm volatile("cpuid" : "+a" (eax), "=b" (ebx), "=d" (edx), "+c" (ecx)); \ + for (i = 0; i <= TRIALS; ++i) { \ + trial_times[i] = get_cycles(); \ + ret |= mix_ ##name(input, len); \ + } \ + for (i = 0; i < TRIALS; ++i) \ + trial_times[i] = trial_times[i + 1] - trial_times[i]; \ + sort(trial_times, TRIALS + 1, sizeof(cycles_t), compare_cycles, NULL); \ + median_ ## name = trial_times[TRIALS / 2]; \ +} while (0) + +#define report_it(name) do { \ + pr_err("%lu: %12s: %6llu cycles per call\n", stamp, #name, median_ ## name); \ +} while (0) + + +declare_it(original) +declare_it(crc32loop) +declare_it(tinylfsr) +declare_it(widelfsr) +declare_it(blake2s) +declare_it(dblblake2s) +declare_it(k12f800) +declare_it(k12f1600) + +static int compare_cycles(const void *a, const void *b) +{ + return *((cycles_t *)a) - *((cycles_t *)b); +} + +static int __init mod_init(void) +{ + enum { WARMUP = 6000, TRIALS = 10000, IDLE = 1 * 1000, LEN = 4096 }; + static u8 buffer[LEN]; + int ret = 0, i; + cycles_t *trial_times; + cycles_t median_original = 0; + cycles_t median_crc32loop = 0; + cycles_t median_tinylfsr = 0; + cycles_t median_widelfsr = 0; + cycles_t median_blake2s = 0; + cycles_t median_dblblake2s = 0; + cycles_t median_k12f800 = 0; + cycles_t median_k12f1600 = 0; + unsigned long flags; + DEFINE_SPINLOCK(lock); + + get_random_bytes(buffer, sizeof(buffer)); + + trial_times = kcalloc(TRIALS + 1, sizeof(cycles_t), GFP_KERNEL); + if (!trial_times) + return -ENOMEM; + + msleep(IDLE); + + spin_lock_irqsave(&lock, flags); + + do_it(original, buffer, sizeof(buffer)); + do_it(crc32loop, buffer, sizeof(buffer)); + do_it(tinylfsr, buffer, sizeof(buffer)); + do_it(widelfsr, buffer, sizeof(buffer)); + do_it(blake2s, buffer, sizeof(buffer)); + do_it(dblblake2s, buffer, sizeof(buffer)); + do_it(k12f800, buffer, sizeof(buffer)); + do_it(k12f1600, buffer, sizeof(buffer)); + + spin_unlock_irqrestore(&lock, flags); + + report_it(original); + report_it(crc32loop); + report_it(tinylfsr); + report_it(widelfsr); + report_it(blake2s); + report_it(dblblake2s); + report_it(k12f800); + report_it(k12f1600); + + kfree(trial_times); + + /* We should never actually agree to insert the module. Choosing + * -0x1000 here is an amazing hack. It causes the kernel to not + * actually load the module, while the standard userspace tools + * don't return an error, because it's too big. */ + return -0x1000; +} + +module_init(mod_init); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("kBench9000 Cycle Counter"); +MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>"); |