Skip to content

feat: Add S4-FIFO algo - #341

Merged
LauYeeYu merged 1 commit into
developfrom
dev/s4fifo
Sep 24, 2026
Merged

LauYeeYu merged 1 commit into
developfrom
dev/s4fifo

Conversation

@LauYeeYu

Copy link
Copy Markdown
Collaborator

S4-FIFO generalizes S3-FIFO with two extra tunable parameters. Build with -DENABLE_S4FIFO=ON. #332

This PR brings the implementation #335 to the main branch.

Usage:

# learned (default)
cachesim TRACE oracleGeneral s4fifo cache-size-ratio --ignore-obj-size 1

# static S3-FIFO-equivalent behaviour
cachesim TRACE oracleGeneral s4fifo cache-size-ratio  --ignore-obj-size 1 -e "auto-tune=0"

# a different observation window, as a fraction of the trace or an absolute count
cachesim TRACE oracleGeneral s4fifo cache-size-ratio  -e "feature-collect-reqs=0.3"
cachesim TRACE oracleGeneral s4fifo cache-size-ratio  -e "feature-collect-reqs=2000000"

Results

Example 1

10M-request twitter trace, whole trace scored, miss-ratio reduction vs FIFO:

size ratio S3-FIFO S4-FIFO
0.001 14.4% 16.2%
0.01 22.8% 25.0%
0.03 21.9% 24.7%
0.1 18.8% 21.0%
0.8 3.7% 3.8%

Example 2

Haocheng@node0:~/libCacheSim$ ./_build/bin/cachesim /mntData2/data/oracleReuse/cphy/w71.oracleGeneral.bin.zst oracleGeneral s4fifo 0.1 --ignore-obj-size 1
[INFO]  09-16-2026 04:05:51 cli_reader_utils.c:268  (tid=140355046479104): calculating working set size...
[INFO]  09-16-2026 04:05:51 cli_reader_utils.c:297  (tid=140355046479104): working set size: 673334 object 673334 byte
[INFO]  09-16-2026 04:05:52 cli_parser.c:598  (tid=140355046479104): trace path: /mntData2/data/oracleReuse/cphy/w71.oracleGeneral.bin.zst, trace_type ORACLE_GENERAL_TRACE, ofilepath result/w71.oracleGeneral.bin.zst.cachesim, 64 threads, warmup -1 sec, total 1 algo x 1 size = 1 caches, s4fifo, ignore object size
[DEBUG] 09-16-2026 04:05:52 request.h:130  (tid=140355046479104): req clock_time 27145606, id 14779568, size 1, cost 1, op nop, valid 1
[DEBUG] 09-16-2026 04:05:52 request.h:130  (tid=140355046479104): req clock_time 27145606, id 14779568, size 1, cost 1, op nop, valid 1
[INFO]  09-16-2026 04:05:52    sim.c:65   (tid=140355046479104): w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 24.00 hour: 1172163 requests, miss ratio 0.2126, interval miss ratio 0.2126
[INFO]  09-16-2026 04:05:52 S4FIFO.c:772  (tid=140355046479104): S4FIFO-0.1000-2-0-0.00: applying learned configuration small-size-ratio=0.0500,ghost-size-ratio=0.9000,move-to-main-threshold=1,ghost-to-main-threshold=0,small-skip-ratio=0.2500
[INFO]  09-16-2026 04:05:52    sim.c:65   (tid=140355046479104): w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 48.00 hour: 2412842 requests, miss ratio 0.1860, interval miss ratio 0.1609
[INFO]  09-16-2026 04:05:52    sim.c:65   (tid=140355046479104): w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 72.00 hour: 3623208 requests, miss ratio 0.1820, interval miss ratio 0.1741
[INFO]  09-16-2026 04:05:53    sim.c:65   (tid=140355046479104): w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 96.00 hour: 5825046 requests, miss ratio 0.2274, interval miss ratio 0.3021
/mntData2/data/oracleReuse/cphy/w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 cache size    67333,          6840776 req, miss ratio 0.2164, throughput 5.89 MQPS
Haocheng@node0:~/libCacheSim$ ./_build/bin/cachesim /mntData2/data/oracleReuse/cphy/w71.oracleGeneral.bin.zst oracleGeneral s4fifo 0.1 --ignore-obj-size 1 -e "auto-tune=0"
[INFO]  09-16-2026 04:06:04 cli_reader_utils.c:268  (tid=140679681869056): calculating working set size...
[INFO]  09-16-2026 04:06:05 cli_reader_utils.c:297  (tid=140679681869056): working set size: 673334 object 673334 byte
[INFO]  09-16-2026 04:06:05 cli_parser.c:598  (tid=140679681869056): trace path: /mntData2/data/oracleReuse/cphy/w71.oracleGeneral.bin.zst, trace_type ORACLE_GENERAL_TRACE, ofilepath result/w71.oracleGeneral.bin.zst.cachesim, 64 threads, warmup -1 sec, total 1 algo x 1 size = 1 caches, s4fifo, eviction-params: auto-tune=0, ignore object size
[DEBUG] 09-16-2026 04:06:05 request.h:130  (tid=140679681869056): req clock_time 27145606, id 14779568, size 1, cost 1, op nop, valid 1
[DEBUG] 09-16-2026 04:06:05 request.h:130  (tid=140679681869056): req clock_time 27145606, id 14779568, size 1, cost 1, op nop, valid 1
[INFO]  09-16-2026 04:06:05    sim.c:65   (tid=140679681869056): w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 24.00 hour: 1172163 requests, miss ratio 0.2126, interval miss ratio 0.2126
[INFO]  09-16-2026 04:06:05    sim.c:65   (tid=140679681869056): w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 48.00 hour: 2412842 requests, miss ratio 0.1864, interval miss ratio 0.1617
[INFO]  09-16-2026 04:06:05    sim.c:65   (tid=140679681869056): w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 72.00 hour: 3623208 requests, miss ratio 0.1871, interval miss ratio 0.1886
[INFO]  09-16-2026 04:06:06    sim.c:65   (tid=140679681869056): w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 96.00 hour: 5825046 requests, miss ratio 0.2327, interval miss ratio 0.3077
/mntData2/data/oracleReuse/cphy/w71.oracleGeneral.bin.zst S4FIFO-0.1000-2-0-0.00 cache size    67333,          6840776 req, miss ratio 0.2218, throughput 5.81 MQPS

* feat: Add S4-FIFO algo

* fix(s4fifo): address review findings on child sizing, warmup and feature tracking

Five fixes from the review of the S4-FIFO PR:

- Size each sub-FIFO's hash table from its own byte size, capped by any
  requested --hashpower, rather than inheriting the parent's. Previously a
  single S4FIFO allocated three full-size tables; at a 1GiB cache size peak
  RSS drops from 527MiB to 338MiB, matching S3FIFO's 340MiB, with an
  identical miss ratio.

- Leave WARMUP on the first capacity eviction instead of when occupancy
  reaches cache_size. Eviction runs before occupancy can exceed the limit,
  so the old test needed the trace to fill the cache exactly and in practice
  never fired: on cloudPhysicsIO the learned mode spent the whole trace in
  warmup and never predicted a configuration.

- Only pre-scan the trace for its request count when an algorithm actually
  reads it. Every cachesim and MRC run paid for a full extra pass, which on
  a txt or zstd trace costs as much as the simulation (LRU on a 1M-request
  csv: 0.48s -> 0.33s).

- Stop double-counting one-hit-wonders: S4FIFO_track_ghost_insert already
  records them, so the extra call doubled one_hit_count whenever a ghost
  FIFO was configured.

- Stamp clock reinsertions in the main FIFO with S4FIFO_track_main_insert.
  A reinserted object takes a fresh tail position but kept a stale
  insert_seq, skewing the main queue's hit-position histogram.

The eviction path itself is unchanged: the static heuristic still matches
S3-FIFO exactly, and the full test suite passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(s4fifo): propagate n_total_req through cloning, and fix ghost-queue tracking

Second round of review fixes.

- Adding n_total_req grew common_cache_params_t from 24 to 32 bytes, but
  clone_cache and create_cache_with_new_size still asserted the old size, so
  any assertion-enabled build aborted in simulate_at_multi_sizes (testSimulator
  exited 134 under -DCMAKE_BUILD_TYPE=Debug). That assert was a tripwire for
  exactly the bug that had happened - both functions rebuild the struct field
  by field and were silently dropping the new field - so copy n_total_req in
  both, retain it on cache_t to copy it from, and make the tripwire a
  _Static_assert. As a runtime assert it was compiled out of release builds and
  so never fired in CI; now it breaks the build for everyone, which is the
  point. Verified it still trips by adding a scratch field.

- MINISIM hardcoded n_total_req = 0 even though it had just counted the trace,
  so the default fractional feature-collect-reqs fell back to a fixed 10000 and
  MRC disagreed with cachesim. Pass sampled_cnt - not n_req_, since spatial
  sampling drops requests before the cache sees them, so sampled_cnt is what
  cache->n_req climbs to. On twitter_cluster52 at wss 0.055 the miss ratio goes
  0.216370 -> 0.205729, and the curve now matches cachesim exactly (0.299438
  and 0.185243 against 0.2994 and 0.1852).

- S4FIFO_track_ghost_insert returned early outside a collection window, so
  objects inserted during warmup or between windows kept a zero insert_seq and
  ghost_insert_seq froze. A later hit inside a window was then scored against a
  stamp from a different sequence. Always stamp and advance, as the small and
  main helpers do, and gate only the per-window one-hit counter. Costs ~1%
  throughput (4.82 -> 4.78 MQPS) for the extra lookup.

- record_ghost_removal ran on every ghost hit, but with a positive
  ghost-to-main-threshold the entry deliberately stays in the queue. The
  tracker subtracts recorded removals as holes from later hit positions, so
  this invented holes that were never there; record it only in the branch that
  actually removes.

Release and Debug both build clean and pass all 10 tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@LauYeeYu
LauYeeYu merged commit 0b91ef6 into develop Sep 24, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants