diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/guest-diag/guest_pin_stream.py | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py index bed4728..ac4f72b 100644 --- a/tools/guest-diag/guest_pin_stream.py +++ b/tools/guest-diag/guest_pin_stream.py @@ -30,6 +30,12 @@ REGION = 0x200000 # ..0x45000) and the per-channel push allocations follow; 512 KB per 2 MB # region covers both without scanning holes that hold nothing. SPAN = int(os.environ.get("STREAM_SPAN", "0x80000"), 16) +# CE push-buffer window: one 1 MB allocation per CE channel at +# 0x120000000 + 0x100000*rank; SPAN2 covers the 1 MB boundary inside a +# 2 MB region. +LO2 = int(os.environ.get("STREAM_LO2", "0x120000000"), 16) +HI2 = int(os.environ.get("STREAM_HI2", "0x120600000"), 16) +SPAN2 = int(os.environ.get("STREAM_SPAN2", "0x180000"), 16) TRACE = ("/sys/kernel/tracing/trace" if os.path.exists("/sys/kernel/tracing/trace") else "/sys/kernel/debug/tracing/trace") @@ -108,6 +114,31 @@ def cdt_pid(): return None +def scan_window(fd, lo, hi, span, out): + base = lo & ~(REGION - 1) + while base < hi: + va = max(base, lo) & ~0xFFF + end = min(base + span, hi) + while va < end: + n = min(BATCH, (end - va) // 0x1000) + if n <= 0: + break + os.lseek(fd, (va // 4096) * 8, 0) + data = os.read(fd, n * 8) + got = len(data) // 8 + for i in range(got): + e = int.from_bytes(data[i * 8:i * 8 + 8], 'little') + if not ((e >> 63) & 1): + continue + pfn = e & ((1 << 55) - 1) + pa = pfn << 12 + if not pa or (PAMAX and pa >= PAMAX): + continue + out[va + i * 0x1000] = pa + va += got * 0x1000 + base += REGION + + def scan(pid): """Present pages in the first SPAN bytes of every REGION, as {va: pa}. @@ -115,32 +146,18 @@ def scan(pid): aligned); scanning only the allocation heads keeps the per-loop page table work small, which is what makes the stream fast while the client is mapping and the guest is loaded. + + Two windows: the GR window (rings/pushbuffers/counter page) and the CE + push-buffer window (0x120000000+, one 1 MB allocation per CE channel). + The CE window uses a wider span because the per-channel allocations are + 1 MB apart inside a 2 MB region. """ fd = os.open('/proc/%d/pagemap' % pid, os.O_RDONLY) out = {} try: - base = LO & ~(REGION - 1) - while base < HI: - va = max(base, LO) & ~0xFFF - end = min(base + SPAN, HI) - while va < end: - n = min(BATCH, (end - va) // 0x1000) - if n <= 0: - break - os.lseek(fd, (va // 4096) * 8, 0) - data = os.read(fd, n * 8) - got = len(data) // 8 - for i in range(got): - e = int.from_bytes(data[i * 8:i * 8 + 8], 'little') - if not ((e >> 63) & 1): - continue - pfn = e & ((1 << 55) - 1) - pa = pfn << 12 - if not pa or (PAMAX and pa >= PAMAX): - continue - out[va + i * 0x1000] = pa - va += got * 0x1000 - base += REGION + scan_window(fd, LO, HI, SPAN, out) + if HI2 > LO2: + scan_window(fd, LO2, HI2, SPAN2, out) finally: os.close(fd) return out |
