From 887579f109f1e72fb83bd0f8bf6f447861736f9d Mon Sep 17 00:00:00 2001 From: Thomas Gschwantner Date: Sun, 10 Jun 2018 21:45:16 +0200 Subject: mpmc_ptr_ring: add selftest --- src/main.c | 2 +- src/queueing.c | 2 + src/queueing.h | 1 + src/selftest/mpmc_ring.h | 121 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 src/selftest/mpmc_ring.h (limited to 'src') diff --git a/src/main.c b/src/main.c index f1db64b..6711f44 100644 --- a/src/main.c +++ b/src/main.c @@ -30,7 +30,7 @@ static int __init mod_init(void) blake2s_fpu_init(); curve25519_fpu_init(); #ifdef DEBUG - if (!allowedips_selftest() || !packet_counter_selftest() || !curve25519_selftest() || !chacha20poly1305_selftest() || !poly1305_selftest() || !blake2s_selftest() || !ratelimiter_selftest()) + if (!allowedips_selftest() || !packet_counter_selftest() || !curve25519_selftest() || !chacha20poly1305_selftest() || !poly1305_selftest() || !blake2s_selftest() || !ratelimiter_selftest() || !mpmc_ring_selftest()) return -ENOTRECOVERABLE; #endif noise_init(); diff --git a/src/queueing.c b/src/queueing.c index 80048c9..2b22c18 100644 --- a/src/queueing.c +++ b/src/queueing.c @@ -44,3 +44,5 @@ void packet_queue_free(struct crypt_queue *queue, bool multicore) WARN_ON(!mpmc_ptr_ring_empty(&queue->ring)); mpmc_ptr_ring_cleanup(&queue->ring, NULL); } + +#include "selftest/mpmc_ring.h" diff --git a/src/queueing.h b/src/queueing.h index 14d69df..cb21944 100644 --- a/src/queueing.h +++ b/src/queueing.h @@ -140,6 +140,7 @@ static inline void queue_enqueue_per_peer(struct crypt_queue *queue, struct sk_b #ifdef DEBUG bool packet_counter_selftest(void); +bool mpmc_ring_selftest(void); #endif #endif /* _WG_QUEUEING_H */ diff --git a/src/selftest/mpmc_ring.h b/src/selftest/mpmc_ring.h new file mode 100644 index 0000000..9503b36 --- /dev/null +++ b/src/selftest/mpmc_ring.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018 Thomas Gschwantner . All Rights Reserved. + */ + +#ifdef DEBUG + +#include "../mpmc_ptr_ring.h" +#include +#include +#include + +#define THREADS_PRODUCER 16 +#define THREADS_CONSUMER 16 +#define ELEMENT_COUNT 1000000L /* divisible by threads_{consumer,producer} */ +#define QUEUE_SIZE 1024 + +#define EXPECTED_TOTAL ((ELEMENT_COUNT * (ELEMENT_COUNT + 1)) / 2) +#define PER_PRODUCER (ELEMENT_COUNT/THREADS_PRODUCER) +#define PER_CONSUMER (ELEMENT_COUNT/THREADS_CONSUMER) +#define THREADS_TOTAL (THREADS_PRODUCER + THREADS_CONSUMER) + +struct mpmc_ptr_ring *ring; + +struct worker_producer { + struct work_struct work; + int thread_num; +}; + +struct worker_consumer { + struct work_struct work; + int thread_num; + long total; + long count; +}; + +static void producer_function(struct work_struct *work) +{ + struct worker_producer *td = container_of(work, struct worker_producer, work); + uintptr_t count = (td->thread_num * PER_PRODUCER) + 1; + + for (; count <= (td->thread_num + 1) * PER_PRODUCER; ++count) { + while (mpmc_ptr_ring_produce(ring, (const void *) count)) + schedule(); + } +} + +static void consumer_function(struct work_struct *work) +{ + struct worker_consumer *td = container_of(work, struct worker_consumer, work); + int i; + + for (i = 0; i < PER_CONSUMER; ++i) { + uintptr_t value; + while (!(value = (uintptr_t) mpmc_ptr_ring_consume(ring))) + schedule(); + + td->total += value; + ++(td->count); + } +} + +bool __init mpmc_ring_selftest(void) +{ + struct workqueue_struct *wq; + struct worker_producer *producers; + struct worker_consumer *consumers; + long total = 0, count = 0; + int i; + + producers = kmalloc_array(THREADS_PRODUCER, sizeof(*producers), GFP_KERNEL); + consumers = kmalloc_array(THREADS_CONSUMER, sizeof(*consumers), GFP_KERNEL); + ring = kmalloc(sizeof(*ring), GFP_KERNEL); + + BUG_ON(!ring || !producers || !consumers); + BUG_ON(mpmc_ptr_ring_init(ring, QUEUE_SIZE, GFP_KERNEL)); + + wq = alloc_workqueue("mpmc_ring_selftest", WQ_UNBOUND, 0); + + for (i = 0; i < THREADS_PRODUCER; ++i) { + producers[i].thread_num = i; + INIT_WORK(&producers[i].work, producer_function); + queue_work(wq, &producers[i].work); + } + + for (i = 0; i < THREADS_CONSUMER; ++i) { + consumers[i] = (struct worker_consumer) { + .thread_num = i, + .total = 0, + .count = 0, + }; + INIT_WORK(&consumers[i].work, consumer_function); + queue_work(wq, &consumers[i].work); + } + + destroy_workqueue(wq); + BUG_ON(!mpmc_ptr_ring_empty(ring)); + mpmc_ptr_ring_cleanup(ring, NULL); + kfree(ring); + + for (i = 0; i < THREADS_CONSUMER; ++i) { + total += consumers[i].total; + count += consumers[i].count; + } + + kfree(producers); + kfree(consumers); + + if (count == ELEMENT_COUNT && total == EXPECTED_TOTAL) { + pr_info("mpmc_ring self-tests: pass"); + return true; + } + + pr_info("mpmc_ring self-test failed:"); + pr_info("Count: %lu, expected: %lu", count, ELEMENT_COUNT); + pr_info("Total: %lu, expected: %lu", total, EXPECTED_TOTAL); + + return false; +} + +#endif -- cgit v1.2.3-59-g8ed1b