// Sequential file-cache pressure test. // Reads a large read-only asset through SysReadFile and checks that the // read-only page cache stays bounded by dropping clean pages. #include #include #include #include #define READ_CHUNK 4096u #define MIN_PRESSURE_BYTES (3u * 1024u * 1024u) #define RESIDENT_LIMIT_PAGES 640u static uint8_t gBuf[READ_CHUNK]; static void print(const char* s) { SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) }; SysWriteConsole(&req); } static void print_u64(uint64_t v) { char buf[32]; int i = 0; if (v == 0) { print("0"); return; } while (v && i < (int)sizeof(buf)) { buf[i++] = (char)('0' + (v % 10)); v /= 10; } while (i--) { char c[2] = { buf[i], 0 }; print(c); } } static void exit_now(int code) { for (;;) SysExitProcess(code); } static void fail(const char* msg) { print("pcache_pressure: "); print(msg); print("\n"); exit_now(1); } static void fail_status(const char* what, uint32_t status) { print("pcache_pressure: "); print(what); print(" failed status="); print_u64(status); print("\n"); exit_now(1); } static uint32_t query_cache(SYS_FILE_CACHE_STATS* out) { return SysQueryKernelStats(SYS_KERNEL_STATS_FILE_CACHE, out, sizeof(*out), 0); } static uint32_t open_first_large(uint32_t* fileOut, const char** pathOut, uint64_t* sizeOut) { static const char* candidates[] = { "1:/apps/video.bk2", "0:/apps/video.bk2", "/apps/video.bk2", "video.bk2", "1:/apps/doom1.wad", "0:/apps/doom1.wad", "/apps/doom1.wad", "doom1.wad", }; for (size_t i = 0; i < sizeof(candidates) / sizeof(candidates[0]); ++i) { uint32_t h = 0; SYS_OPEN_FILE_REQUEST req = SysMakeOpenFileRequest(SysSvFromCstr(candidates[i]), SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY, SYS_FILE_OPEN_EXISTING, SYS_FILE_FLAG_NONE, &h); uint32_t s = SysOpenFile(&req); if (s != NTLSTATUS_SUCCESS) continue; uint64_t size = 0; s = SysGetFileSize(h, &size); if (s != NTLSTATUS_SUCCESS) { SysCloseHandle(h); continue; } if (size >= MIN_PRESSURE_BYTES) { *fileOut = h; *pathOut = candidates[i]; *sizeOut = size; return NTLSTATUS_SUCCESS; } SysCloseHandle(h); } return NTLSTATUS_NOT_FOUND; } int main(void) { print("pcache_pressure: start\n"); SYS_FILE_CACHE_STATS before; SYS_FILE_CACHE_STATS after; if (query_cache(&before) != NTLSTATUS_SUCCESS) fail("initial cache stats query failed"); uint32_t file = 0; const char* path = 0; uint64_t size = 0; uint32_t s = open_first_large(&file, &path, &size); if (s != NTLSTATUS_SUCCESS) fail_status("open large asset", s); print("pcache_pressure: using "); print(path ? path : ""); print(" size="); print_u64(size); print("\n"); uint64_t total = 0; uint64_t target = size < (8u * 1024u * 1024u) ? size : (8u * 1024u * 1024u); while (total < target) { size_t got = 0; SYS_FILE_IO_REQUEST readReq = SysMakeFileIoRequest(file, gBuf, sizeof(gBuf), &got); s = SysReadFile(&readReq); if (s != NTLSTATUS_SUCCESS) fail_status("read", s); if (got == 0) break; total += got; } SysCloseHandle(file); if (total < MIN_PRESSURE_BYTES) fail("asset read was too short to pressure the cache"); if (query_cache(&after) != NTLSTATUS_SUCCESS) fail("final cache stats query failed"); uint64_t loads = after.Loads - before.Loads; uint64_t hits = after.Hits - before.Hits; uint64_t drops = after.Drops - before.Drops; uint64_t raReq = after.ReadAheadRequests - before.ReadAheadRequests; uint64_t raLoad = after.ReadAheadPagesLoaded - before.ReadAheadPagesLoaded; uint64_t raThrottle = after.ReadAheadPagesThrottled - before.ReadAheadPagesThrottled; uint64_t batchReads = after.BatchReads - before.BatchReads; uint64_t batchPages = after.BatchPagesLoaded - before.BatchPagesLoaded; print("pcache_pressure: read bytes="); print_u64(total); print(" loads+="); print_u64(loads); print(" hits+="); print_u64(hits); print(" drops+="); print_u64(drops); print(" resident="); print_u64(after.ResidentPages); print(" active="); print_u64(after.ActivePages); print(" standby="); print_u64(after.StandbyPages); print(" max="); print_u64(after.MaxResidentPages); print(" readahead-req+="); print_u64(raReq); print(" readahead-load+="); print_u64(raLoad); print(" readahead-throttle+="); print_u64(raThrottle); print(" batch-reads+="); print_u64(batchReads); print(" batch-pages+="); print_u64(batchPages); print("\n"); if (loads < 512) fail("expected at least 512 cache page loads"); if (after.ResidentPages > RESIDENT_LIMIT_PAGES) fail("resident page cache exceeded pressure bound"); if (loads > RESIDENT_LIMIT_PAGES && drops == 0) fail("cache did not drop clean pages under pressure"); print("pcache_pressure: PASS\n"); exit_now(0); return 0; }