How to Simulate Fractional Cache Sizes (Percentage of Working Set) in libCacheSim
libCacheSim lets you specify cache capacity as a floating-point fraction of the trace's working-set size, automatically converting values like 0.01 into concrete byte or object counts.
libCacheSim's cachesim CLI eliminates manual size calculations by interpreting decimal arguments as percentages of the working-set size (WSS). This feature enables rapid sensitivity analysis across relative cache capacities without pre-processing traces to compute absolute storage requirements. The implementation detects fractional inputs through pattern matching and scales them against pre-calculated WSS metrics stored in wss_obj and wss_byte.
Parsing Fractional Arguments in the CLI
When you invoke cachesim, the argument parser examines each cache-size token to determine whether it represents an absolute value or a relative fraction.
The conv_cache_sizes() Detection Logic
In libCacheSim/bin/cachesim/cli_parser.c, the function conv_cache_sizes() inspects each size argument:
- If the token contains a dot (
.), libCacheSim treats it as a floating-point fraction of the working set. - The parser multiplies this fraction by the trace's working-set size to derive the concrete cache capacity.
- If you pass
0orauto, the simulator automatically applies the default fraction set: 0.001, 0.003, 0.01, 0.03, 0.1, 0.2, 0.4, and 0.8 (0.1% through 80%).
The concrete size calculation depends on the --ignore-obj-size flag. Without the flag, the fraction applies to wss_byte (total unique bytes); with the flag, it applies to wss_obj (distinct object count).
Automatic Cache Size Selection
Passing 0 or auto triggers set_cache_size() to instantiate eight separate cache simulations spanning the default fraction range. This allows comprehensive hit-rate analysis across orders of magnitude in relative capacity with a single command execution.
Working-Set Size Calculation
Before simulation begins, libCacheSim computes the working-set size through cal_working_set_size() in libCacheSim/bin/cli_reader_utils.c.
Trace Scanning and Sampling
The function performs a complete pass through the trace to count distinct objects and accumulate their total byte size. For very large traces, it employs sampling (examining every N-th object) to bound memory consumption during this preprocessing phase. The results populate two critical variables:
wss_obj: The number of unique object IDs in the trace.wss_byte: The sum of unique objects' sizes in bytes.
These values persist for the duration of the simulation session, allowing the CLI to scale fractional inputs into absolute capacities.
Byte Mode vs. Object Mode
- Default mode: A fraction like
0.1allocates cache space equal to 10% ofwss_byte, respecting variable object sizes. --ignore-obj-sizemode: The same fraction allocates space for 10% ofwss_obj, treating every object as size 1 for capacity calculations.
Practical CLI Examples
Simulate 1% of Working-Set Bytes
./bin/cachesim trace.vscsi vscsi lru 0.01
This command configures an LRU cache with capacity equal to 1% of the trace's total unique data volume.
Simulate 5% of Distinct Objects
./bin/cachesim trace.vscsi vscsi lru 0.05 --ignore-obj-size
Here, libCacheSim calculates 5% of wss_obj and configures the cache to hold that many objects, regardless of individual object sizes.
Run Automatic Fraction Sweep
./bin/cachesim trace.vscsi vscsi lru auto
This executes eight simulations at fractions 0.001, 0.003, 0.01, 0.03, 0.1, 0.2, 0.4, and 0.8, generating a complete performance curve across relative capacities.
Python Binding Workaround
The Python API does not directly expose fractional size syntax. Instead, compute the working set manually and scale it:
from libcachesim import TraceReader, LRU
reader = TraceReader("trace.vscsi", trace_type="vscsi")
# Calculate working-set size in bytes
wss_bytes = sum(req.obj_size for req in reader)
# Target 2% of working set
cache_size = int(0.02 * wss_bytes)
cache = LRU(cache_size=cache_size)
obj_mr, byte_mr = cache.process_trace(reader)
print(f"Object miss ratio: {obj_mr:.4f}, Byte miss ratio: {byte_mr:.4f}")
This approach mirrors the CLI's internal logic while using the Python interface.
Core Implementation Files
The fractional cache size feature spans three key locations in the codebase:
libCacheSim/bin/cachesim/cli_parser.c: Implementsconv_cache_sizes()to detect decimal inputs andset_cache_size()to handleautogeneration.libCacheSim/bin/cli_reader_utils.c: Containscal_working_set_size(), which computeswss_objandwss_bytethrough trace analysis.doc/quickstart_cachesim.md: Documents the fraction syntax for end users.
Summary
- libCacheSim interprets cache-size arguments containing decimals (e.g.,
0.01) as fractions of the working-set size. - The CLI automatically calculates working-set size via
cal_working_set_size()before simulation begins. - Use
--ignore-obj-sizeto apply fractions to object counts rather than byte volumes. - Passing
0orautotriggers a predefined sweep across eight fractions from 0.1% to 80%. - Implementation resides primarily in
cli_parser.candcli_reader_utils.c.
Frequently Asked Questions
How does libCacheSim distinguish between fractional and absolute cache sizes?
libCacheSim checks for the presence of a dot (.) in the cache-size argument within conv_cache_sizes(). Tokens containing a dot are parsed as floating-point numbers and treated as fractions of the working-set size, while integer tokens are interpreted as absolute byte or object counts depending on the mode.
What is the difference between byte-based and object-based fractional sizing?
Without flags, fractions apply to the total unique bytes (wss_byte) in the trace. When you specify --ignore-obj-size, libCacheSim applies the fraction to the count of unique objects (wss_obj) instead, effectively simulating a cache that holds a percentage of distinct items regardless of their individual sizes.
Can I use fractional cache sizes with the Python bindings?
No, the Python API requires absolute size values. You must manually calculate the working-set size using TraceReader, multiply by your desired fraction, and pass the resulting integer to the cache constructor. This mirrors the CLI's preprocessing logic but requires explicit implementation in your Python script.
What fractions does libCacheSim use when I specify auto or 0?
The simulator uses a fixed progression optimized for sensitivity analysis: 0.001, 0.003, 0.01, 0.03, 0.1, 0.2, 0.4, and 0.8. This logarithmic spacing efficiently covers the performance curve from tiny caches (0.1% of working set) to large caches (80% of working set) in a single execution.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →