How to Integrate libCacheSim as a C Library into Existing Applications

Integrate libCacheSim into C applications by including the umbrella header libCacheSim.h, initializing a reader_t via open_trace() and a cache_t via algorithm-specific init functions like LRU_init(), then iterating with read_one_req() and cache->get() to compute miss ratios, linking against libCacheSim, glib-2.0, and zstd.

libCacheSim is a high-performance C library maintained at 1a1a11a/libcachesim that provides trace readers, request objects, and over 30 eviction algorithms for cache simulation. By linking against the shared library, you embed sophisticated cache modeling directly into existing applications without managing the underlying complexity of trace parsing or eviction state machines.

Core Architecture and Data Structures

The library centers on five opaque types declared in libCacheSim/include/libCacheSim/:

  • reader_t (defined in reader.h): Manages memory-mapped trace files and yields request_t objects. Supports CSV, binary, and vscsi formats.
  • request_t (defined in request.h): Encapsulates a single access with fields for timestamp, object ID, size, operation type, and TTL.
  • cache_t (defined in cache.h): Abstract cache object exposing function pointers for get(), put(), evict(), and cache_free().
  • Common parameters (common_cache_params_t): Configures hash power, cache size, and metadata accounting.
  • Simulator API (declared in simulator.h): High-level functions like simulate_at_multi_sizes() for batch evaluations.

Include the single umbrella header to pull in all public definitions:

#include <libCacheSim.h>

Step-by-Step Integration Guide

Initialize the Trace Reader

Configure column mappings and open the trace file using open_trace(). In libCacheSim/include/libCacheSim/reader.h, this function accepts a reader_init_param_t structure:

reader_init_param_t params = default_reader_init_params();
params.obj_id_field   = 5;   // CSV column containing object ID
params.obj_size_field = 4;   // CSV column containing object size
params.time_field     = 2;   // CSV column containing timestamp
params.has_header_set = true;
params.delimiter      = ',';

reader_t *r = open_trace("path/to/trace.csv", CSV_TRACE, &params);

The reader_t maintains an internal memory map of the file and metadata such as total request count.

Allocate a Request Object

Create a reusable request_t to avoid per-iteration heap allocations. The function new_request() is declared in request.h:

request_t *req = new_request();

This object is mutated by read_one_req() rather than reallocated on each call.

Instantiate a Cache Algorithm

Each eviction policy exposes an initialization function (e.g., LRU_init, ARC_init, S3FIFO_init) defined under libCacheSim/cache/eviction/. Pass common_cache_params_t to configure capacity:

common_cache_params_t cp = {
    .cache_size = 1 * GiB,
    .hashpower = 24,
    .consider_obj_metadata = false
};

cache_t *c = LRU_init(cp, NULL);  // Returns a concrete cache_t instance

The returned pointer implements the vtable defined in cache.h, providing uniform access to get(), put(), and eviction routines regardless of the specific algorithm.

Run the Simulation Loop

Iterate through the trace, invoking cache->get() to test for hits. A return value of NULL (or Boolean false) indicates a miss:

uint64_t n_req = 0, n_miss = 0;

while (read_one_req(r, req) == 0) {
    if (!c->get(c, req)) {
        n_miss++;  // Object not resident; miss recorded
    }
    n_req++;
}

printf("miss ratio = %.4f\n", (double)n_miss / n_req);

The get() method internally updates metadata, inserts missing objects, and triggers evictions according to the policy implemented in the specific algorithm file (e.g., libCacheSim/cache/eviction/LRU.c).

Resource Cleanup

Release resources in reverse order of allocation to prevent memory leaks:

free_request(req);
c->cache_free(c);   // Algorithm-specific destructor
close_reader(r);

Compiling and Linking Your Application

Build and Install libCacheSim

Clone and install the library system-wide to generate the pkg-config file:

git clone https://github.com/1a1a11a/libcachesim
cd libcachesim
mkdir _build && cd _build
cmake -G Ninja .. && ninja
sudo ninja install

This installs libCacheSim.so and libCacheSim.pc to standard system paths.

Compile Against the Library

Use pkg-config to inject correct include paths and linker flags. The library requires glib-2.0 and zstd as mandatory dependencies:

gcc my_app.c $(pkg-config --cflags --libs libCacheSim glib-2.0) -o my_app -lm -lzstd

Alternatively, specify flags manually:

gcc my_app.c -I/usr/local/include -lCacheSim -lglib-2.0 -lzstd -lm -o my_app

Advanced Integration Patterns

Multi-Size Cache Simulations

Evaluate the same trace against multiple cache sizes without manual file rewinding. The simulate_at_multi_sizes() function in simulator.h automates this:

guint64 sizes[] = { 1<<20, 10<<20, 100<<20 };  // 1 MiB, 10 MiB, 100 MiB

sim_res_t *res = simulate_at_multi_sizes(
    r,
    (cache_t*)LRU_init,  // Initialization function pointer
    3,                   // Number of sizes
    sizes,
    NULL,                // Optional reader args
    0.0,                 // Percentage to sample
    1                    // Number of threads
);

/* Access results: res[i].hit_cnt and res[i].miss_cnt per size */

Implementing Custom Eviction Policies

Extend libCacheSim with proprietary algorithms by implementing the cache_t interface. Create a source file defining your_policy_init() that returns a struct with populated function pointers for get, put, evict, and cache_free. Register the plugin via the infrastructure in libCacheSim/cache/plugin.c. Reference the example implementation at example/plugin_v1/plugin_lru.c.

Complete Minimal Example

The following program (simple_lru.c) demonstrates a fully functional integration:

#include <libCacheSim.h>

int main(void) {
    /* 1. Configure CSV reader */
    reader_init_param_t p = default_reader_init_params();
    p.obj_id_field   = 5;
    p.obj_size_field = 4;
    p.time_field     = 2;
    p.has_header_set = true;
    p.delimiter      = ',';
    
    reader_t *r = open_trace("data/trace.csv", CSV_TRACE, &p);
    
    /* 2. Allocate reusable request */
    request_t *req = new_request();
    
    /* 3. Initialize 1 GiB LRU cache */
    common_cache_params_t cp = {
        .cache_size = 1 * GiB,
        .hashpower = 24,
        .consider_obj_metadata = false
    };
    cache_t *c = LRU_init(cp, NULL);
    
    /* 4. Run simulation */
    uint64_t n_req = 0, n_miss = 0;
    while (read_one_req(r, req) == 0) {
        if (!c->get(c, req)) n_miss++;
        n_req++;
    }
    printf("miss ratio: %.4f\n", (double)n_miss / n_req);
    
    /* 5. Cleanup */
    free_request(req);
    c->cache_free(c);
    close_reader(r);
    
    return 0;
}

Compile and execute:

gcc simple_lru.c $(pkg-config --cflags --libs libCacheSim glib-2.0) -o simple_lru -lm -lzstd
./simple_lru

Summary

  • Include the umbrella header libCacheSim/include/libCacheSim.h to access all public APIs.
  • Initialize trace readers with open_trace() and reader_init_param_t to map CSV columns or binary formats.
  • Create cache instances via algorithm-specific functions like LRU_init(), passing common_cache_params_t for sizing.
  • Iterate using read_one_req() and test residency with cache->get(), counting misses for ratio calculations.
  • Link with pkg-config --cflags --libs libCacheSim glib-2.0 and add -lzstd -lm to resolve dependencies.
  • Extend functionality through the plugin API in plugin.c for custom eviction policies or use simulate_at_multi_sizes() for batch analysis.

Frequently Asked Questions

What dependencies are required to build applications with libCacheSim?

libCacheSim requires GLib 2.0 and Zstandard (zstd). When compiling, pass flags for both libraries: pkg-config --cflags --libs libCacheSim glib-2.0 plus -lzstd -lm. These are mandatory runtime dependencies specified in the upstream CMakeLists.txt.

Can I use libCacheSim without reading from trace files?

Yes. While reader_t abstracts trace I/O, you can populate request_t objects manually and feed them directly to cache->get() or cache->put(). This is useful for hardware simulation or live caching scenarios where requests originate from runtime instrumentation rather than static files.

How do I select between different eviction algorithms at runtime?

Store function pointers to the initialization routines (e.g., LRU_init, ARC_init, S3FIFO_init) and invoke the desired constructor based on configuration. All algorithms return a cache_t* that exposes a uniform interface, allowing polymorphic cache behavior without changing the simulation loop logic.

Is libCacheSim thread-safe for parallel simulations?

The core cache_t implementations are not generally thread-safe for concurrent access to a single instance, but you can run independent simulations in parallel by creating separate reader_t and cache_t instances per thread. The simulate_at_multi_sizes() function accepts a thread-count parameter to parallelize evaluations across sizes safely.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →