# How to Integrate libCacheSim as a C Library into Existing Applications

> Easily integrate libCacheSim as a C library into your existing applications. Learn how to initialize, read requests, and compute miss ratios to enhance performance.

- Repository: [Juncheng Yang/libcachesim](https://github.com/1a1a11a/libcachesim)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Integrate libCacheSim into C applications by including the umbrella header [`libCacheSim.h`](https://github.com/1a1a11a/libcachesim/blob/main/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`](https://github.com/1a1a11a/libcachesim/blob/main/reader.h)): Manages memory-mapped trace files and yields `request_t` objects. Supports CSV, binary, and vscsi formats.
- **`request_t`** (defined in [`request.h`](https://github.com/1a1a11a/libcachesim/blob/main/request.h)): Encapsulates a single access with fields for timestamp, object ID, size, operation type, and TTL.
- **`cache_t`** (defined in [`cache.h`](https://github.com/1a1a11a/libcachesim/blob/main/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`](https://github.com/1a1a11a/libcachesim/blob/main/simulator.h)): High-level functions like `simulate_at_multi_sizes()` for batch evaluations.

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

```c
#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`](https://github.com/1a1a11a/libcachesim/blob/main/libCacheSim/include/libCacheSim/reader.h), this function accepts a `reader_init_param_t` structure:

```c
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`](https://github.com/1a1a11a/libcachesim/blob/main/request.h):

```c
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:

```c
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`](https://github.com/1a1a11a/libcachesim/blob/main/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:

```c
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`](https://github.com/1a1a11a/libcachesim/blob/main/libCacheSim/cache/eviction/LRU.c)).

### Resource Cleanup

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

```c
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:

```bash
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:

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

```

Alternatively, specify flags manually:

```bash
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`](https://github.com/1a1a11a/libcachesim/blob/main/simulator.h) automates this:

```c
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`](https://github.com/1a1a11a/libcachesim/blob/main/libCacheSim/cache/plugin.c). Reference the example implementation at [`example/plugin_v1/plugin_lru.c`](https://github.com/1a1a11a/libcachesim/blob/main/example/plugin_v1/plugin_lru.c).

## Complete Minimal Example

The following program ([`simple_lru.c`](https://github.com/1a1a11a/libcachesim/blob/main/simple_lru.c)) demonstrates a fully functional integration:

```c
#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:

```bash
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`](https://github.com/1a1a11a/libcachesim/blob/main/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`](https://github.com/1a1a11a/libcachesim/blob/main/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`](https://github.com/1a1a11a/libcachesim/blob/main/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.