#!/usr/bin/env python3
from collections import namedtuple
from pathlib import Path
import re
import statistics
import sys

Vad = namedtuple("Vad", "pointer start end reserve commit")
def parse_vad_stream(fd):
    """
    VAD     level      start      end    commit
    b719dfc8 ( 9)         10       10         1 Private      READWRITE         
    b71a0820 ( 8)         20       20         1 Private      READWRITE         
    b7195008 ( 9)         30      22f        19 Private      READWRITE         
    """
    total_reserve = 0
    total_commit = 0
    special_page_allocs = 0
    special_page_commits = 0
    vads = []
    for line in fd:
        matches = re.match("([0-9a-f]{8}) *\( *\d*\) *([0-9a-f]+) *([0-9a-f]+) *([0-9a-f]+)", line)
        if not matches:
            continue
        pointer = matches.group(1)
        try:
            start = int(matches.group(2), 16)
            end = int(matches.group(3), 16)
            commit = int(matches.group(4), 10)
        except ValueError:
            print(f"Error parsing: {line.rstrip()}")
        reserve = end - start + 1
        if reserve < commit:
            print(f"Invalid commit: {line.rstrip()}")
        total_reserve += reserve
        total_commit += commit
        vads.append(Vad(
            pointer=pointer,
            start=start,
            end=end,
            reserve=reserve,
            commit=commit,
        ))
        if reserve == 469:
            special_page_allocs += 1
            special_page_commits += commit
    #vads.sort(key=lambda v: -v.commit)
    print("Top 3 commits:")
    for i in range(3):
        print(f"  {vads[i]}")
    print(f"Total reserve: {total_reserve} pages = {total_reserve * 4} KB")
    print(f"Total commit: {total_commit} pages = {total_commit * 4} KB")
    reserves = [v.reserve for v in vads]
    commits = [v.commit for v in vads]
    print(f"Reserve avg: {statistics.mean(reserves)}, median: {statistics.median(reserves)}, deviation: {statistics.stdev(reserves)}")
    print(f"Commit avg: {statistics.mean(commits)}, median: {statistics.median(commits)}, deviation: {statistics.stdev(commits)}")
    print(f"Size 469 allocations: {special_page_allocs}; committed: {special_page_commits}")

def parse_vad(filename):
    if filename == "-":
        return parse_vad_stream(sys.stdin)

    filename = Path(filename)
    with filename.open() as fd:
        return parse_vad_stream(fd)

def main(argv):
    if len(argv) < 2:
        sys.exit("Usage: vad.py <filename>")

    parse_vad(argv[1])

if __name__ == "__main__":
    main(sys.argv)
