How to Configure Hashpower and Memory Footprint for libCacheSim Simulations

Set the hashpower field in common_cache_params_t to control the internal hash table size, where memory usage scales as sizeof(cache_obj_t) × 2^hashpower.

libCacheSim uses an internal hash table to map object IDs to cache entries, and the hashpower parameter directly determines how much DRAM is allocated for this structure. Understanding how to tune this value lets you balance lookup performance against memory constraints, whether you are running simulations on a laptop or a high-capacity server.

Understanding Hashpower in libCacheSim

Hashpower is the exponent that defines the number of buckets in the cache’s internal hash table. The table contains 2^hashpower buckets, with each bucket storing a pointer (or metadata structure) to a cache object.

The macro that performs this calculation is defined in libCacheSim/dataStructure/hashtable/hashtableStruct.h:

#define hashsize(n) ((uint64_t)1 << (uint16_t)(n))

Consequently, the base memory consumed by a cache grows roughly as:


memory ≈ sizeof(cache_obj_t) × 2^hashpower

Additional overhead comes from linked-list entries, algorithm-specific metadata (e.g., Bloom filters, priority queues), and the actual object storage.

Default Hashpower Values and Where They Are Set

libCacheSim sets different defaults depending on the entry point you use.

Source Default Value Location
Library API hashpower = 20 libCacheSim/include/libCacheSim/cache.h (lines 63-68)
CLI (cachesim) hashpower = 24 libCacheSim/bin/cachesim/cache_init.h (lines 22-26)
Small traces Reduced by 8 (minimum 16) libCacheSim/bin/cachesim/cache_init.h (lines 31-33)

The CLI automatically reduces hashpower by 8 if the trace path contains "data/trace.", capping the lower bound at 16 for algorithms like Hyperbolic or BeladySize:

cc_params.hashpower = MAX(cc_params.hashpower - 8, 16);

How Hashpower Affects Memory Footprint

For a 64-bit system where sizeof(void*) == 8, a hashpower of 24 creates:


2^24 = 16,777,216 buckets
≈ 128 MiB just for the bucket array

Increasing hashpower by 1 doubles the bucket array size; decreasing it by 1 halves the allocation.

Empirical profiling in doc/memory_usage_profiling.md (lines 71-74) confirms that create_chained_hashtable_v2() dominates the memory footprint for FIFO, LRU, and Clock algorithms.

Estimation formula:


total_memory ≈ cache_size               // object storage
               + sizeof(cache_obj_t) × 2^hashpower   // hash table
               + algorithm_overhead

For default LRU with hashpower = 24 and cache_obj_t ≈ 32 bytes:


hash table ≈ 32 B × 2^24 ≈ 512 MiB
object storage = 1 GiB  → total ≈ 1.5 GiB

Lowering hashpower to 20 reduces the hash table to ≈ 32 MiB, saving ~480 MiB.

Configuring Hashpower for Your Simulation

Programmatic Configuration (C API)

When calling create_cache() or algorithm-specific initializers, populate common_cache_params_t with your desired value:

#include "libCacheSim/cache.h"

common_cache_params_t params = {
    .cache_size = 1ULL << 30,            // 1 GiB
    .default_ttl = 86400 * 30,           // 30 days
    .hashpower = 18,                     // 2^18 = 262,144 buckets (~2 MiB)
    .consider_obj_metadata = false,
};

cache_t *c = create_cache("data/trace.vscsi", "lru", params.cache_size,
                         NULL, false);

The hashpower field is read by cache_struct_init() (invoked by each eviction algorithm's *_init function), propagating your setting to the hashtable allocation.

CLI Configuration (cachesim Binary)

The cachesim command-line tool does not expose a runtime flag for hashpower. To change the default, edit libCacheSim/bin/cachesim/cache_init.h and modify the constant:

static inline cache_t *create_cache(...){
    common_cache_params_t cc_params = {
        .cache_size = cache_size,
        .default_ttl = 86400 * 300,
        .hashpower = 22,      // ← new default
        .consider_obj_metadata = consider_obj_metadata,
    };
    // ...
}

Recompile the binary:

mkdir -p build && cd build
cmake .. && make -j

Custom Plugin Configuration

When implementing a custom cache plugin (see example/plugin_v1/test_plugin.c), you receive a common_cache_params_t argument. Adjust hashpower before passing parameters to internal constructors:

common_cache_params_t params = default_common_cache_params();
params.hashpower = 20;   // optimize for containerized environment

cache_t *my_cache = my_plugin_init(params, custom_args);

Choosing the Right Hashpower Value

Situation Recommended Hashpower Rationale
Large caches (≥ 1 GiB) 24 – 26 Ample DRAM available; larger tables reduce collisions and improve lookup speed.
Small caches (≤ 100 MiB) 16 – 20 Saves memory; acceptable collision rates due to lower absolute object counts.
Very large workloads (tens of GiB) 26 – 28 (if RAM permits) Maintains low load factor, preventing performance degradation on high-traffic traces.
Memory-constrained environments (containers, notebooks) 16 (minimum) Guarantees hashtable stays under ≈ 8 MiB (pointer array only).

Summary

  • Hashpower controls the size of the internal hash table as 2^hashpower buckets, directly impacting DRAM usage.
  • Default values vary by entry point: 20 for the C API (cache.h), 24 for the CLI (cache_init.h), with automatic reduction for small traces.
  • Memory scales linearly with 2^hashpower; each increment doubles the hash table allocation.
  • Configure via common_cache_params_t.hashpower in code, or by editing cache_init.h and recompiling for the CLI.
  • Select values between 16 (minimum) and 28 based on available RAM and cache size to balance memory footprint against lookup performance.

Frequently Asked Questions

What is the minimum hashpower value allowed in libCacheSim?

The minimum enforced value is 16. This lower bound is hardcoded in libCacheSim/bin/cachesim/cache_init.h (lines 101-104) using MAX(cc_params.hashpower - 8, 16) to prevent excessive collision rates that would degrade performance on small traces.

How do I calculate the exact memory usage of the hash table?

Multiply the number of buckets by the size of a pointer on your architecture. Use the formula: memory_bytes = (1ULL << hashpower) * sizeof(void*). For example, with hashpower = 24 on a 64-bit system: 2^24 * 8 bytes = 134,217,728 bytes (128 MiB). Add sizeof(cache_obj_t) per stored object for total cache memory.

Why does the CLI use a higher default hashpower than the library API?

The cachesim CLI targets production-scale traces and assumes server-class DRAM availability, defaulting to 24 in cache_init.h. The library API (cache.h) defaults to 20 to provide a safer baseline for embedded or experimental use where memory constraints are unknown. The CLI also implements automatic reduction logic for small traces that the raw API does not apply.

Can I change hashpower without recompiling when using the cachesim binary?

No. The cachesim command-line tool does not expose a runtime flag (such as --hashpower) to adjust this parameter. To modify the default, you must edit libCacheSim/bin/cachesim/cache_init.h, change the .hashpower value in the cc_params struct, and recompile the project with cmake and make.

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 →