about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorPeter H. Froehlich <peter.hans.froehlich@gmail.com>2019-05-08 01:08:00 +0200
committerPeter H. Froehlich <peter.hans.froehlich@gmail.com>2019-05-08 01:08:00 +0200
commita2f0dba1245270b346e65391ee5e5e94807f2510 (patch)
tree32dac7ddedcd8b91f66d1105e62984cff29a1acb
downloadsimple-allocators-a2f0dba1245270b346e65391ee5e5e94807f2510.tar.gz
Initial commit.
-rw-r--r--.clang-format11
-rw-r--r--Makefile19
-rw-r--r--bench.c153
-rw-r--r--cached.c73
-rw-r--r--cached.h18
5 files changed, 274 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..1585e79
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Linux
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+
+AlwaysBreakAfterReturnType: All
+AlignAfterOpenBracket: DontAlign
+ContinuationIndentWidth: 16
+SortIncludes: false
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0ff5c08
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+CFLAGS=-std=gnu11 -Wall -Wextra -Wpedantic -Og -g -D_DEFAULT_SOURCE \
+       -fsanitize=undefined -fsanitize=address
+LDFLAGS=-fsanitize=undefined -fsanitize=address
+
+ALL=bench
+
+all: $(ALL)
+
+bench: bench.o cached.o
+
+clean:
+	$(RM) $(ALL) *.o
+
+.PHONY:	all check clean format
+
+check:
+	cppcheck --enable=all --std=c11 *.[ch]
+format:
+	clang-format -i *.[ch]
diff --git a/bench.c b/bench.c
new file mode 100644
index 0000000..fb95c2e
--- /dev/null
+++ b/bench.c
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "cached.h"
+
+#define UNUSED __attribute__((unused))
+
+static sig_atomic_t running;
+
+static void
+panic(const char *msg)
+{
+	fprintf(stderr, "panic: %s\n", msg);
+	exit(EXIT_FAILURE);
+}
+
+static void
+alarm_handler(int sig UNUSED, siginfo_t *info UNUSED, void *arg UNUSED)
+{
+	running = 0;
+}
+
+static void
+trap_signals(void)
+{
+	struct sigaction sa;
+
+	sa.sa_sigaction = alarm_handler;
+	sa.sa_flags = SA_SIGINFO;
+
+	if (sigaction(SIGALRM, &sa, NULL) < 0) {
+		panic("failed to setup signal handler");
+	}
+}
+
+static void
+set_alarm(void)
+{
+	running = 1;
+	alarm(1);
+}
+
+static size_t
+bench_malloc(size_t allocs, size_t objsize)
+{
+	void *objs[allocs];
+	size_t count = 0;
+
+	while (running) {
+		for (size_t i = 0; i < allocs; i++) {
+			objs[i] = calloc(1, objsize);
+			count++;
+		}
+		for (size_t i = 0; i < allocs; i++) {
+			free(objs[i]);
+		}
+	}
+
+	return count;
+}
+
+static size_t
+bench_ca_alloc(size_t allocs)
+{
+	void *objs[allocs];
+	size_t count = 0;
+
+	while (running) {
+		for (size_t i = 0; i < allocs; i++) {
+			objs[i] = ca_alloc();
+			count++;
+		}
+		for (size_t i = 0; i < allocs; i++) {
+			ca_free(objs[i]);
+		}
+	}
+
+	return count;
+}
+
+static void
+bench_four(void)
+{
+	if (ca_setup(256, 4096) < 0) {
+		panic("failed to setup cached allocator");
+	}
+
+	set_alarm();
+
+	size_t allocs = bench_ca_alloc(1024);
+
+	printf("%-12s\t%9zu allocs/second\n", "huge_cache", allocs);
+
+	ca_cleanup();
+}
+
+static void
+bench_one(void)
+{
+	if (ca_setup(256, 1024) < 0) {
+		panic("failed to setup cached allocator");
+	}
+
+	set_alarm();
+
+	size_t allocs = bench_ca_alloc(1024);
+
+	printf("%-12s\t%9zu allocs/second\n", "large_cache", allocs);
+
+	ca_cleanup();
+}
+
+static void
+bench_two(void)
+{
+	if (ca_setup(256, 16) < 0) {
+		panic("failed to setup cached allocator");
+	}
+
+	set_alarm();
+
+	size_t allocs = bench_ca_alloc(1024);
+
+	printf("%-12s\t%9zu allocs/second\n", "small_cache", allocs);
+
+	ca_cleanup();
+}
+
+static void
+bench_three(void)
+{
+	set_alarm();
+
+	size_t allocs = bench_malloc(1024, 256);
+
+	printf("%-12s\t%9zu allocs/second\n", "just_malloc", allocs);
+}
+
+int
+main(void)
+{
+	trap_signals();
+
+	bench_three();
+	puts("");
+	bench_two();
+	bench_one();
+	bench_four();
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/cached.c b/cached.c
new file mode 100644
index 0000000..8174cda
--- /dev/null
+++ b/cached.c
@@ -0,0 +1,73 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cached.h"
+
+static size_t object_size;
+static size_t max_cached;
+static size_t num_cached;
+static void **cache;
+
+int
+ca_setup(size_t osize, size_t csize)
+{
+	/* TODO allow osize == 0 following malloc? */
+	if (osize == 0 || csize == 0) {
+		return -1;
+	}
+
+	cache = calloc(csize, sizeof(*cache));
+	if (cache == NULL) {
+		return -2;
+	}
+
+	object_size = osize;
+	max_cached = csize;
+	num_cached = 0;
+
+	return 0;
+}
+
+void *
+ca_alloc(void)
+{
+	assert(cache != NULL);
+
+	if (num_cached > 0) {
+		void *object = cache[--num_cached];
+		return object;
+	}
+
+	return calloc(1, object_size);
+}
+
+void
+ca_free(void *object)
+{
+	assert(cache != NULL);
+
+	if (object == NULL) {
+		/* free(3) also does nothing for NULL */
+		return;
+	}
+
+	if (num_cached < max_cached) {
+		cache[num_cached++] = object;
+		/* memset here to catch dangling references */
+		memset(object, 0, object_size);
+		return;
+	}
+
+	free(object);
+}
+
+void
+ca_cleanup(void)
+{
+	for (size_t i = 0; i < num_cached; i++) {
+		free(cache[i]);
+	}
+	free(cache);
+	cache = NULL;
+}
diff --git a/cached.h b/cached.h
new file mode 100644
index 0000000..32ca61c
--- /dev/null
+++ b/cached.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#ifndef CACHED_H_
+#define CACHED_H_
+
+int
+ca_setup(size_t object_size, size_t cache_size);
+
+void *
+ca_alloc(void);
+
+void
+ca_free(void *object);
+
+void
+ca_cleanup(void);
+
+#endif