Files
nt-lite/code/user/tests/pcache_pressure/pcache_pressure.c
T

176 lines
5.1 KiB
C

// Sequential file-cache pressure test.
// Reads this test executable through SysReadFile and checks cache behavior when
// the image is large enough to apply pressure.
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <ntlite/syscall.h>
#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) {
while (true) 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 char gSelfPath[SYS_PATH_MAX];
// Copies a string view into a fixed NUL-terminated buffer.
static int copy_view(char* out, size_t outSize, SYS_STRING_VIEW view) {
if (!out || outSize == 0 || !view.Data || view.Length + 1 > outSize)
return 0;
memcpy(out, view.Data, view.Length);
out[view.Length] = '\0';
return 1;
}
// Opens this process image as the cache-pressure input file.
static uint32_t open_self_image(uint32_t* fileOut, const char** pathOut, uint64_t* sizeOut) {
SYS_PEB* peb = SysGetPeb();
if (!peb || peb->Magic != SYS_PEB_MAGIC || peb->Version != SYS_ENV_VERSION)
return NTLSTATUS_INVALID_PARAMETER;
if (!copy_view(gSelfPath, sizeof(gSelfPath), peb->ImagePath))
return NTLSTATUS_INVALID_PARAMETER;
uint32_t h = 0;
SYS_OPEN_FILE_REQUEST req = SysMakeOpenFileRequest(SysSvFromCstr(gSelfPath),
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)
return s;
uint64_t size = 0;
s = SysGetFileSize(h, &size);
if (s != NTLSTATUS_SUCCESS) {
SysCloseHandle(h);
return s;
}
if (size == 0) {
SysCloseHandle(h);
return NTLSTATUS_NOT_FOUND;
}
*fileOut = h;
*pathOut = gSelfPath;
*sizeOut = size;
return NTLSTATUS_SUCCESS;
}
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_self_image(&file, &path, &size);
if (s != NTLSTATUS_SUCCESS)
fail_status("open self image", s);
print("pcache_pressure: using ");
print(path ? path : "<unknown>");
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 == 0)
fail("self image read returned no bytes");
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;
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("\n");
if (size >= MIN_PRESSURE_BYTES) {
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");
} else {
print("pcache_pressure: self image below pressure size; pressure bounds skipped\n");
}
print("pcache_pressure: PASS\n");
exit_now(0);
return 0;
}