/* SPDX-License-Identifier: GPL-2.0 * * Copyright (C) 2018 Jason A. Donenfeld . All Rights Reserved. */ #include #include #include #include #include #include #include #include #include #include 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 ");