Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a table cache #42

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ TEST_MURMUR_SRCS := test/test_murmur.c
TEST_MURMUR_OBJS := $(TEST_MURMUR_SRCS:%=$(BUILD_DIR)/%.o)
TEST_MURMUR_DEPS := $(TEST_MURMUR_OBJS:.o=.d)

CPPFLAGS ?= $(INC_FLAGS) -MMD -MP -O3 # -g -O0
CPPFLAGS ?= $(INC_FLAGS) -std=c11 -Wall -pedantic -MMD -MP -O0 -g -DWITH_TABLE_CACHE -DWITH_TABLE_CACHE_STATS

lib: $(BUILD_DIR)/src/libhamt.dylib

Expand Down
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,27 @@ In order to use `libhamt` in your own projects, copy `include/hamt.h` and

### Benchmarks

For basic performance comparison with AVL and red-black trees (from `libavl`)
![Benchmark results](./doc/img/benchmark.png)

The current HAMT implementation consistently outperforms the `libavl` AVL-tree
and red-black tree implementations by 5x for querying, 1.5x-4x for node insert,
and 1.5x-5x for node removal. Persistent insert and remove implementations
scale roughly similar to the classic trees, with more favorable scaling
behavior for HAMT. Where table caching is an option, the persistent HAMT
implementation reaches better insert performance than red-black trees and
better removal performance than red-black and AVL trees at appoximately 10e5
elements.

Compared to hash tables, HAMT query times start at 2x vs. GLib's `HashTable`
and 20x vs. `hsearch(3)` (the latter still being investigated) and then get
progressively worse. This makes sense, given the O(1) vs. O(log N) expectations
between the different approaches.

Note that benchmarking and optimization is an ongoing effort and please take
all numbers with a pinch of salt. All measurements have so far been collected
on a single system (Apple MBP M2 Max under Ventura 13.4.1).

For detailed performance comparison with AVL and red-black trees (from `libavl`)
and the HashTree from GLib, see [the benchmarking repo][hamt_bench_github].


Expand Down
Binary file added doc/img/benchmark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 26 additions & 3 deletions include/hamt.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,37 @@ typedef uint32_t (*hamt_key_hash_fn)(const void *key, const size_t gen);

struct hamt;

/*
* A custom allocator interface. This is similar to the function
* pointer callback allocator interface exposed in e.g. libavl but
* additionally enables (1) a user-defined context pointer to allow
* for user state management; and (2) passing current and/or new size
* information to free() and realloc() functions for (optional) sized
* deallocation.
*/
struct hamt_allocator {
void *(*malloc)(const size_t size);
void *(*realloc)(void *chunk, const size_t size);
void (*free)(void *chunk);
void *(*malloc)(const ptrdiff_t size, void *ctx);
void *(*realloc)(void *ptr, const ptrdiff_t old_size,
const ptrdiff_t new_size, void *ctx);
void (*free)(void *ptr, const ptrdiff_t size, void *ctx);
void *ctx;
};

extern struct hamt_allocator hamt_allocator_default;

#if defined(WITH_TABLE_CACHE)
/*
* Configuration options for the table cache; this allows the user to
* control cache behavior beyond default settings.
*/
struct hamt_cache_config {
ptrdiff_t initial_cache_sizes[32]; /* in # of tables */
};

extern struct hamt_cache_config hamt_cache_config_default;

#endif

struct hamt *hamt_create(hamt_key_hash_fn key_hash, hamt_cmp_fn key_cmp,
struct hamt_allocator *ator);
void hamt_delete(struct hamt *trie);
Expand Down
Loading
Loading