Download sdq-ling/watch_io.py from HelloSun/ling30tiny_EPQ: direct link, hf CLI and curl.
- Browser
- Download file 4.22 kB
-
https://huggingface.co/HelloSun/ling30tiny_EPQ/resolve/main/sdq-ling/watch_io.py
- Command line
-
hf download hf://HelloSun/ling30tiny_EPQ/sdq-ling/watch_io.py
-
curl -L -o watch_io.py https://huggingface.co/HelloSun/ling30tiny_EPQ/resolve/main/sdq-ling/watch_io.py
4.22 kB
| #!/usr/bin/env python3 | |
| """Run a command while sampling how the model file is actually read. | |
| Reports, per sample and at the end: | |
| read_bytes /proc/<pid>/io bytes actually fetched from the block device | |
| file_resident mincore(model file) pages of the GGUF sitting in the page cache | |
| RssAnon/RssFile process RSS split (arena+weights vs mapped file) | |
| Cached /proc/meminfo system-wide page cache | |
| The point: a buffered read would show up as file_resident growing; O_DIRECT reads | |
| never touch the cache, so read_bytes grows while file_resident stays flat. | |
| usage: watch_io.py <model.gguf>[,<model2.gguf>,...] <cmd> [args...] | |
| """ | |
| import os | |
| import re | |
| import subprocess | |
| import sys | |
| import time | |
| PAGE = os.sysconf('SC_PAGE_SIZE') | |
| CHR = 1024 ** 3 | |
| def meminfo(key): | |
| for line in open('/proc/meminfo'): | |
| if line.startswith(key): | |
| return int(line.split()[1]) * 1024 | |
| return 0 | |
| def proc_io(pid): | |
| out = {} | |
| try: | |
| for line in open(f'/proc/{pid}/io'): | |
| k, _, v = line.partition(':') | |
| out[k] = int(v) | |
| except OSError: | |
| return None | |
| return out | |
| def proc_status(pid): | |
| out = {} | |
| try: | |
| for line in open(f'/proc/{pid}/status'): | |
| for k in ('RssAnon', 'RssFile', 'VmHWM'): | |
| if line.startswith(k): | |
| out[k] = int(line.split()[1]) * 1024 | |
| except OSError: | |
| pass | |
| return out | |
| def file_resident(paths): | |
| """resident bytes of the given files via mincore (helper binary)""" | |
| r = subprocess.run(['/tmp/pagecache_resident'] + paths, capture_output=True, text=True) | |
| m = re.search(r'TOTAL\s+resident\s+([\d.]+) GiB', r.stdout) | |
| if m: | |
| return float(m.group(1)) * CHR | |
| m = re.search(r'resident\s+([\d.]+) GiB', r.stdout) | |
| return float(m.group(1)) * CHR if m else -1 | |
| def main(): | |
| models = sys.argv[1].split(',') | |
| cmd = sys.argv[2:] | |
| subprocess.run(['sync']) | |
| print(f'[watch] evicting {len(models)} shard(s) from the page cache', flush=True) | |
| subprocess.run(['/tmp/pagecache_resident', '--evict'] + models) | |
| base_cached = meminfo('Cached:') | |
| base_read = None | |
| t0 = time.time() | |
| # NOTE: never use pipes here - sdq-chat prints several hundred KB of | |
| # tokenizer warnings and would block on a full 64 KB pipe. | |
| out_f = open('/tmp/watch_stdout.log', 'w') | |
| err_f = open('/tmp/watch_stderr.log', 'w') | |
| proc = subprocess.Popen(cmd, stdout=out_f, stderr=err_f) | |
| pid = proc.pid | |
| peak_res = 0.0 | |
| peak_rssanon = peak_rssfile = 0 | |
| peak_cached = base_cached | |
| samples = 0 | |
| while proc.poll() is None: | |
| io_ = proc_io(pid) | |
| st = proc_status(pid) | |
| if io_ is None: | |
| break | |
| if base_read is None: | |
| base_read = io_['read_bytes'] | |
| res = file_resident(models) | |
| cached = meminfo('Cached:') | |
| peak_res = max(peak_res, res) | |
| peak_cached = max(peak_cached, cached) | |
| peak_rssanon = max(peak_rssanon, st.get('RssAnon', 0)) | |
| peak_rssfile = max(peak_rssfile, st.get('RssFile', 0)) | |
| samples += 1 | |
| print(f'[watch] t={time.time()-t0:6.1f}s read_bytes={(io_["read_bytes"]-base_read)/CHR:7.3f} GiB ' | |
| f' rchar={(io_["rchar"])/CHR:8.3f} GiB model_file_resident={res/CHR:6.3f} GiB ' | |
| f'RssAnon={st.get("RssAnon",0)/CHR:6.3f} RssFile={st.get("RssFile",0)/CHR:6.3f} ' | |
| f'Cached_delta={(cached-base_cached)/CHR:+7.3f} GiB', flush=True) | |
| time.sleep(float(os.environ.get("WATCH_INTERVAL", "2.0"))) | |
| proc.wait() | |
| out_f.close() | |
| err_f.close() | |
| print(f'\n[watch] === summary over {samples} samples, {time.time()-t0:.1f}s ===') | |
| print(f'[watch] peak model_file_resident in page cache : {peak_res/CHR:.3f} GiB') | |
| print(f'[watch] peak process RssAnon : {peak_rssanon/CHR:.3f} GiB') | |
| print(f'[watch] peak process RssFile : {peak_rssfile/CHR:.3f} GiB') | |
| print(f'[watch] system Cached delta (peak) : {(peak_cached-base_cached)/CHR:+.3f} GiB') | |
| print(f'[watch] final model_file_resident : {file_resident(models)/CHR:.3f} GiB') | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(main()) | |