aboutsummaryrefslogtreecommitdiff
path: root/mapper.lv2/test
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2017-03-16 22:02:44 +0100
committerHanspeter Portner <dev@open-music-kontrollers.ch>2017-03-16 22:02:44 +0100
commit67dcd89870c9c95611b6787caa08131fb85be7e5 (patch)
treed8c98b835e37d81b78e990cc06571c036cee85af /mapper.lv2/test
parentaf9d3420a69ab9ae7013e980a720a3a21f3a876d (diff)
parent53e6403cb691c5ec917b1fbad3121dac004815e1 (diff)
downloadsynthpod-67dcd89870c9c95611b6787caa08131fb85be7e5.tar.xz
Add 'mapper.lv2/' from commit '53e6403cb691c5ec917b1fbad3121dac004815e1'
git-subtree-dir: mapper.lv2 git-subtree-mainline: af9d3420a69ab9ae7013e980a720a3a21f3a876d git-subtree-split: 53e6403cb691c5ec917b1fbad3121dac004815e1
Diffstat (limited to 'mapper.lv2/test')
-rw-r--r--mapper.lv2/test/Makefile27
-rw-r--r--mapper.lv2/test/mapper_test.c209
2 files changed, 236 insertions, 0 deletions
diff --git a/mapper.lv2/test/Makefile b/mapper.lv2/test/Makefile
new file mode 100644
index 00000000..3858e0ac
--- /dev/null
+++ b/mapper.lv2/test/Makefile
@@ -0,0 +1,27 @@
+CC ?= clang
+
+all: mapper_assert mapper_speed
+
+mapper_assert: mapper_test.c ../mapper.lv2/mapper.h
+ $(CC) -std=gnu11 -g -o $@ $< -I../ $(shell pkg-config --cflags lv2) -lpthread
+
+mapper_speed: mapper_test.c ../mapper.lv2/mapper.h
+ $(CC) -std=gnu11 -O3 -o $@ $< -I../ $(shell pkg-config --cflags lv2) -lpthread
+
+test_assert: mapper_assert
+ ./$< 1 0
+ ./$< 2 0
+ ./$< 4 1
+ ./$< 8 1
+ ./$< 16 2
+ ./$< 32 2
+
+test_speed: mapper_speed
+ ./$< 1 0
+ ./$< 2 0
+ ./$< 4 1
+ ./$< 8 1
+ ./$< 16 2
+ ./$< 32 2
+
+test: test_assert test_speed
diff --git a/mapper.lv2/test/mapper_test.c b/mapper.lv2/test/mapper_test.c
new file mode 100644
index 00000000..19210f46
--- /dev/null
+++ b/mapper.lv2/test/mapper_test.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2017 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#define MAPPER_IMPLEMENTATION
+#include <mapper.lv2/mapper.h>
+
+#include <stdio.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <assert.h>
+
+#define MAX_URI_LEN 16
+#define MAX_ITEMS 0x100000 // 1M
+
+typedef struct _rtmem_slot_t rtmem_slot_t;
+typedef struct _rtmem_t rtmem_t;
+typedef struct _pool_t pool_t;
+
+// test URIs are of fixed length
+struct _rtmem_slot_t {
+ char uri [MAX_URI_LEN];
+};
+
+// dummy rt memory structure
+struct _rtmem_t {
+ atomic_uint nalloc; // counts number allocations
+ atomic_uint nfree; // counts number of frees
+ rtmem_slot_t slots [0]; // contains slots as multiple of MAX_ITEMS
+};
+
+// per-thread properties
+struct _pool_t {
+ pthread_t thread;
+ mapper_pool_t mapper_pool;
+};
+
+static rtmem_t *
+rtmem_new(uint32_t rpools)
+{
+ // create as many slots as worst case scenario dictates it
+ rtmem_t *rtmem = calloc(1, sizeof(rtmem_t) + (rpools*MAX_ITEMS)*sizeof(rtmem_slot_t));
+ if(!rtmem)
+ return NULL;
+
+ atomic_init(&rtmem->nalloc, 0);
+ atomic_init(&rtmem->nfree, 0);
+
+ return rtmem;
+}
+
+static void
+rtmem_free(rtmem_t *rtmem)
+{
+ free(rtmem);
+}
+
+static char *
+_rtmem_alloc(void *data, size_t size)
+{
+ rtmem_t *rtmem = data;
+
+ // dummily just take the next slot according to allocation counter
+ const uint32_t nalloc = atomic_fetch_add_explicit(&rtmem->nalloc, 1, memory_order_relaxed);
+ return rtmem->slots[nalloc].uri;
+}
+
+static void
+_rtmem_free(void *data, char *uri)
+{
+ rtmem_t *rtmem = data;
+
+ // increase free counter (to decipher collisions later)
+ atomic_fetch_add_explicit(&rtmem->nfree, 1, memory_order_relaxed);
+ // clear uri buffer
+ memset(uri, 0x0, MAX_URI_LEN);
+}
+
+// threads should start (un)mapping at the same time
+static atomic_bool rolling = ATOMIC_VAR_INIT(false);
+
+static void *
+_thread(void *data)
+{
+ mapper_pool_t *mapper_pool = data;
+ LV2_URID_Map *map = mapper_pool_get_map(mapper_pool);
+ LV2_URID_Unmap *unmap = mapper_pool_get_unmap(mapper_pool);
+
+ while(!atomic_load_explicit(&rolling, memory_order_relaxed))
+ {} // wait for go signal
+
+ char uri [MAX_URI_LEN];
+ for(uint32_t i = 0; i < MAX_ITEMS/2; i++)
+ {
+ snprintf(uri, MAX_URI_LEN, "urn:hx:%08"PRIx32, i);
+
+ const uint32_t urid1 = map->map(map->handle, uri);
+ assert(urid1);
+ const char *dst = unmap->unmap(unmap->handle, urid1);
+ assert(dst);
+ assert(strcmp(dst, uri) == 0);
+ const uint32_t urid2 = map->map(map->handle, uri);
+ assert(urid2);
+ assert(urid1 == urid2);
+ }
+
+ return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+ static char zeros [MAX_URI_LEN];
+
+ assert(mapper_is_lock_free());
+
+ assert(argc > 2);
+ const uint32_t n = atoi(argv[1]); // number of concurrent threads
+ const uint32_t r = atoi(argv[2]); // number of threads using rt memory
+ assert(r < n);
+
+ // create rt memory
+ rtmem_t *rtmem = rtmem_new(r);
+ assert(rtmem);
+
+ // create mapper
+ mapper_t *mapper = mapper_new(MAX_ITEMS);
+ assert(mapper);
+
+ // create array of threads
+ pool_t *pools = calloc(n, sizeof(pool_t));
+ assert(pools);
+
+ // init/start threads
+ for(uint32_t p = 0; p < n; p++)
+ {
+ pool_t *pool = &pools[p];
+ mapper_pool_t *mapper_pool = &pool->mapper_pool;
+
+ if(p < r) // let thread use real-time memory
+ mapper_pool_init(mapper_pool, mapper, _rtmem_alloc, _rtmem_free, rtmem);
+ else
+ mapper_pool_init(mapper_pool, mapper, NULL, NULL, NULL); // fall-back
+
+ pthread_create(&pool->thread, NULL, _thread, mapper_pool);
+ }
+
+ // signal rolling
+ atomic_store_explicit(&rolling, true, memory_order_relaxed);
+
+ // stop threads
+ for(uint32_t p = 0; p < n; p++)
+ {
+ pool_t *pool = &pools[p];
+
+ pthread_join(pool->thread, NULL);
+ }
+
+ // query rt memory allocations and frees
+ const uint32_t nalloc = atomic_load_explicit(&rtmem->nalloc, memory_order_relaxed);
+ const uint32_t nfree = atomic_load_explicit(&rtmem->nfree, memory_order_relaxed);
+
+ // deinit threads
+ for(uint32_t p = 0; p < n; p++)
+ {
+ pool_t *pool = &pools[p];
+ mapper_pool_t *mapper_pool = &pool->mapper_pool;
+
+ mapper_pool_deinit(mapper_pool);
+ }
+
+ // free threads
+ free(pools);
+
+ // free mapper
+ mapper_free(mapper);
+
+ // check if all rt memory has been cleared
+ for(uint32_t i = 0; i < nalloc; i++)
+ {
+ rtmem_slot_t *slot = &rtmem->slots[i];
+
+ assert(memcmp(slot->uri, zeros, MAX_URI_LEN) == 0);
+ }
+
+ // free rt memory
+ rtmem_free(rtmem);
+
+ // report rt memory allocations and collisions
+ printf("\trt-allocs: %.1f%%, rt-collisions: %.1f%%\n",
+ 200.f * (nalloc - nfree) / MAX_ITEMS,
+ 200.f * nfree / MAX_ITEMS);
+
+ return 0;
+}