d47b095875
* win: direct I/O via FILE_FLAG_NO_BUFFERING + compat_fsize + VirtualLock primitives compat_open_direct() gives Windows the O_DIRECT twin fd st.h already uses on Linux/macOS: FILE_FLAG_NO_BUFFERING, same 4K-alignment contract as O_DIRECT (the engine's DIRECT=1 path already aligns offset/len and slabs are posix_memalign'd). Measured on GLM-5.2 744B int4, Ryzen 9 9950X3D / 126 GB / PCIe4 NVMe (5.8 GB/s at the engine's 19MBx8T pattern), Windows 11, MinGW GCC 16.1, 32-token greedy runs at --topp 0.7, 40 GB pin, current dev HEAD: buffered: 0.38 tok/s (expert-disk dominates) DIRECT=1: 0.56 tok/s (1.47x) — byte-identical greedy output vs buffered compat_fsize() (GetFileSizeEx): CRT lseek(SEEK_END) returns -1 on NO_BUFFERING fds (measured on UCRT); iobench uses it and gains a NO_BUFFERING branch so disk numbers are comparable across platforms. compat_mlock/compat_munlock: VirtualLock with working-set growth (bare VirtualLock caps at the default working-set minimum, a few hundred KB). Wired into the engine in the next commit. tests/test_compat_direct.c covers the alignment contract, data integrity, fsize on both fd kinds; skips cleanly off Windows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * win: wire VirtualLock into mem_wire, munlock pairing in expert_host_release MLOCK=1 was a silent no-op on Windows: pinned experts could be paged out by working-set trimming under memory pressure. mem_wire now uses compat_mlock (VirtualLock + working-set growth); expert_host_release unlocks before freeing, mirroring the POSIX branch. Validated: 39.6 GB pin wired in 17s on a 126 GB machine, zero failures; TF oracle 32/32 with MLOCK=1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * cuda: thread-local current-device cache in select_ctx cudaSetDevice on every call is expensive when the serial expert loop alternates devices. Measured on RTX 5090 + RTX 4090 (Windows, DLL backend, pre-#68 dispatch): expert-matmul 14.3s -> 25.4s per 32 tokens going from 1 to 2 devices, entirely per-call context switching. The current device is per-thread in the CUDA runtime, so a thread_local cache skips redundant switches; multi-GPU expert serving becomes positive-scaling instead of negative. Kernel suite passes on sm_120 + sm_89; TF oracle 32/32 dual-GPU. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: olorin <io@zyphyr.co> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
60 lines
2.4 KiB
C
60 lines
2.4 KiB
C
/* test_compat_direct.c — O_DIRECT equivalente su Windows: FILE_FLAG_NO_BUFFERING.
|
|
* compat_open_direct(path) deve dare un fd che bypassa la cache del file system,
|
|
* leggibile con pread() a offset/len/buffer allineati a 4K (stesso contratto di
|
|
* O_DIRECT su Linux: richieste non allineate falliscono, mai dati corrotti). */
|
|
#include <stdio.h>
|
|
|
|
#ifndef _WIN32
|
|
int main(void){ puts("compat direct tests: skipped (POSIX has native O_DIRECT)"); return 0; }
|
|
#else
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
#include "../compat.h"
|
|
|
|
static int fail(const char *m){ fprintf(stderr,"compat direct test failed: %s\n",m); return 1; }
|
|
|
|
#define FSZ (1u<<20)
|
|
#define TMPF "test_direct.tmp"
|
|
|
|
int main(void){
|
|
FILE *w=fopen(TMPF,"wb"); if(!w) return fail("create temp");
|
|
uint8_t *pat=malloc(FSZ);
|
|
for(uint32_t i=0;i<FSZ;i++) pat[i]=(uint8_t)(i*2246822519u>>24);
|
|
if(fwrite(pat,1,FSZ,w)!=FSZ){ fclose(w); return fail("short write"); }
|
|
fclose(w);
|
|
|
|
int dfd = compat_open_direct(TMPF);
|
|
if(dfd<0) return fail("compat_open_direct returned -1");
|
|
|
|
/* lettura allineata 4K (offset, len, buffer): deve restituire i byte esatti */
|
|
void *buf=NULL;
|
|
if(posix_memalign(&buf,4096,64*1024)!=0) return fail("alloc aligned");
|
|
if(pread(dfd, buf, 64*1024, 4096)!=64*1024) return fail("aligned pread size");
|
|
if(memcmp(buf, pat+4096, 64*1024)!=0) return fail("aligned pread data mismatch");
|
|
|
|
/* richiesta non allineata: deve fallire (-1), MAI restituire dati sbagliati */
|
|
ssize_t r = pread(dfd, buf, 64*1024, 1000);
|
|
if(r>0 && memcmp(buf, pat+1000, (size_t)r)!=0) return fail("misaligned read returned wrong data");
|
|
|
|
/* dimensione file: lseek(SEEK_END) FALLISCE sui fd NO_BUFFERING (misurato:
|
|
* ritorna -1); compat_fsize deve funzionare su entrambi i tipi di fd */
|
|
if(compat_fsize(dfd)!=(off_t)FSZ) return fail("compat_fsize on direct fd");
|
|
int bfd = open(TMPF, COMPAT_O_RDONLY);
|
|
if(compat_fsize(bfd)!=(off_t)FSZ) return fail("compat_fsize on buffered fd");
|
|
close(bfd);
|
|
|
|
/* fd inesistente */
|
|
if(compat_open_direct("no_such_file.tmp")>=0) return fail("open missing file must fail");
|
|
if(compat_fsize(-1)>=0) return fail("compat_fsize on bad fd must be negative");
|
|
|
|
close(dfd);
|
|
compat_aligned_free(buf); free(pat); remove(TMPF);
|
|
puts("compat direct tests: ok");
|
|
return 0;
|
|
}
|
|
#endif /* _WIN32 */
|