Splinter's Core & Benchmarks

Splinter strongly separates storage and calculation concerns by design. Thus, "core" in splinter is a relative term that always refers to splinter.c and splinter.h; relative to how much of the included code is left.

A system that's "20% Core" has roughly 20% of the original code left in it after removal of unused functions.

Core Excludes All Tooling & Tests.

In core, we care about the size of the code that establishes and maintains the store, not the code that consumes it. This means referring to core automatically excludes the CLI, etc.

Embedding Splinter's Core

You have the option to link against libsplinter.a or libsplinter_p.a if you have them in your linker path. You also have the option of just adding splinter.c as a dependency and including its header file, splinter.h, like any other tiny C library.

It's recommended that you first make a copy of them and then take out any of the public API functions and forward declarations that you don't use for maximum efficiency; the smaller it gets, the more likely it will be optimally cached by the CPU.

Leave the originals as-is, so you can still build and use the CLI to manage the stores. Additionally, double check alignment at 64 bytes (there's a test for that) if you do anything to the slot structures.

Real-World Commodity Hardware Benchmarks

All tests were conducted on a Tiger Lake (i3-1115G4) with 6GB total usable RAM while performing other experiments (worst case workday):

Test Memory Model Hygiene Duration (ms) W/Backoff (us) Threads Ops/Sec EAGAIN% NumKeys Corrupt
MRSW in-memory none 60000 0 63 + 1 3,259,500 23.72 20K 0
MRSW im-memory hybrid 60000 0 63 + 1 3,620,886 30.50 20K 0
MRSW in-memory none 60000 0 31 + 1 3,245,405 20.76 20K 0
MRSW im-memory hybrid 60000 0 31 + 1 3,273,807 20.60 20K 0
MRSW in-memory none 30000 0 15 + 1 4,094,896 31.94 10K 0
MRSW file-backed none 30000 0 15 + 1 4,768,989 29.63 10K 0
MRSW file-backed none 30000 150 15 + 1 2,992,652 13.94 10K 0
MRSW file-backed hybrid 30000 150 15 + 1 3,189,306 25.91 10K 0

Keys were limited in file tests due to space and wear constraints, but an in-memory reference is provided.

A Note On Keyspaces

The key part of key -> value really is the key to success in your schema (no puns intended, honestly).

The most basic use of a key is something like foo. And if you used tandem slots, you'd be able to access foo, its velocity, its acceleration and its jitter through foo, foo.1, foo.2 and foo.3 respectively.

That's easy enough, but what if foo collided with something else named foo that you also wanted to track? That's why it's handy to prepend some kind of namespace prior to the key. The author uses something like this:

type_name::experiment_name::run::variable::

Just .. be kind to your future self when naming keys and remember you can change the order access operator if needed. You can change it to something that won't appear in your normal data, like 💩; the separator is stored as SPL_ORDER_SEPARATOR in splinter.h.

A little levity can make drab analysis marathons more tolerable. Send in the poop, the clowns, the beds, or whatever it takes in the name of discovery.