This is xnu-11215.1.10. See this file in:
"""
Macros relating to VM Pageout Scan.
"""
from core.cvalue import sizeof, value
import json
from memory import PrettyPrintDictionary
from process import GetTaskSummary
import re
from scheduler import GetRecentTimestamp
from typing import Iterable, Optional
from xnu import header, lldb_command, kern, xnudebug_test


class VmPageoutStats(Iterable):
    def __init__(self, num_samples: Optional[int] = None):
        self.num_samples = num_samples
        self.stats = kern.globals.vm_pageout_stats
        self.num_stats = sizeof(self.stats) // sizeof(self.stats[0])
        self.now = kern.globals.vm_pageout_stat_now

    def __iter__(self):
        self.samples_iterated = 0
        self.index = self.now - 1 if self.now > 0 else self.num_stats - 1
        return self

    ## Iterate stats in reverse chronological order
    def __next__(self):
        if self.index == self.now:
            raise StopIteration

        if (self.num_samples is not None and
            self.samples_iterated == self.num_samples):
            raise StopIteration

        self.samples_iterated += 1

        if self.index == 0:
            self.index = self.num_stats - 1
        else:
            self.index -= 1

        return self

    def page_counts(self) -> str:
       stat = self.stats[self.index]
       return (f'{stat.vm_page_active_count:12d} '
              f'{stat.vm_page_inactive_count:12d} '
              f'{stat.vm_page_speculative_count:12d} '
              f'{stat.vm_page_anonymous_count:12d} '
              f'{stat.vm_page_free_count:12d} '
              f'{stat.vm_page_wire_count:12d} '
              f'{stat.vm_page_compressor_count:12d} '
              f'{stat.vm_page_pages_compressed:12d} '
              f'{stat.vm_page_pageable_internal_count:12d} '
              f'{stat.vm_page_pageable_external_count:12d} '
              f'{stat.vm_page_realtime_count:12d} '
              f'{stat.vm_page_xpmapped_external_count:12d}')

    def page_stats(self) -> str:
        stat = self.stats[self.index]
        return (f'{stat.considered:12d} '
              f'{stat.pages_grabbed:12d} '
              f'{stat.pages_freed:12d} '
              f'{stat.pages_compressed:12d} '
              f'{stat.pages_evicted:12d} '
              f'{stat.pages_purged:12d} '
              f'{stat.skipped_external:12d} '
              f'{stat.skipped_internal:12d} '
              f'{stat.freed_speculative:12d} '
              f'{stat.freed_internal:12d} '
              f'{stat.freed_external:12d} '
              f'{stat.freed_cleaned:12d} '
              f'{stat.freed_internal:12d} '
              f'{stat.freed_external:12d} '
              f'{stat.inactive_referenced:12d} '
              f'{stat.inactive_nolock:12d} '
              f'{stat.reactivation_limit_exceeded:12d} '
              f'{stat.throttled_internal_q:12d} '
              f'{stat.throttled_external_q:12d} '
              f'{stat.forcereclaimed_sharedcache:12d} '
              f'{stat.forcereclaimed_realtime:12d} '
              f'{stat.protected_sharedcache:12d} '
              f'{stat.protected_realtime:12d}')

# Macro: showvmpagehistory

@header(f"{'active':>12s} "
        f"{'inactive':>12s} "
        f"{'speculative':>12s} "
        f"{'anonymous':>12s} "
        f"{'free':>12s} "
        f"{'wired':>12s} "
        f"{'compressor':>12s} "
        f"{'compressed':>12s} "
        f"{'pageable_int':>12s} "
        f"{'pageable_ext':>12s} "
        f"{'realtime':>12s} "
        f"{'xpmapped_ext':>12s}")
@lldb_command('showvmpageouthistory', 'S:')
def ShowVMPageoutHistory(cmd_args=None, cmd_options={}):
    '''
    Dump a recent history of VM page dispostions in reverse chronological order.

    usage: showvmpagehistory [-S samples]

        -S n    Show only `n` most recent samples (samples are collect at 1 Hz)
    '''
    num_samples = int(cmd_options['-S']) if '-S' in cmd_options else None

    print(ShowVMPageoutHistory.header)
    for stat in VmPageoutStats(num_samples):
        print(stat.page_counts())

@xnudebug_test('test_vmpageouthistory')
def TestMemstats(kernel_target, config, lldb_obj, isConnected ):
    """ Test the functionality of showvmpageouthistory command
        returns
         - False on failure
         - True on success
    """
    if not isConnected:
        print("Target is not connected. Cannot test memstats")
        return False
    res = lldb.SBCommandReturnObject()
    lldb_obj.debugger.GetCommandInterpreter().HandleCommand("showvmpageouthistory", res)
    result = res.GetOutput()
    if len(result.splitlines()) < 2:
        print("Result has fewer than two lines")
        return False
    for line in result.splitlines():
        matches = re.findall(r'(\d+|[\w_]+)', line)
        if len(matches) < 12:
            print("Line has fewer than 12 elements!")
            print(line)
            return False
    return True

# EndMacro: showvmpageouthistory

# Macro: showvmpageoutstats

@header(f"{'considered':>12s} "
        f"{'grabbed':>12s} "
        f"{'freed':>12s} "
        f"{'compressed':>12s} "
        f"{'evicted':>12s} "
        f"{'purged':>12s} "
        f"{'skipped_ext':>12s} "
        f"{'skipped_int':>12s} "
        f"{'freed_spec':>12s} "
        f"{'freed_int':>12s} "
        f"{'freed_ext':>12s} "
        f"{'cleaned':>12s} "
        f"{'cleaned_ext':>12s} "
        f"{'cleaned_int':>12s} "
        f"{'inact_ref':>12s} "
        f"{'inact_lck':>12s} "
        f"{'react_lim':>12s} "
        f"{'thrtl_int':>12s} "
        f"{'thrtl_ext':>12s} "
        f"{'forced_sc':>12s} "
        f"{'forced_rt':>12s} "
        f"{'prot_sc':>12s} "
        f"{'prot_rt':>12s}")
@lldb_command('showvmpageoutstats', 'S:')
def ShowVMPageoutStats(cmd_args=None, cmd_options={}):
    '''
    Dump a recent history of VM pageout statistics in reverse chronological order.

    usage: showvmpageoutstats [-S samples]

        -S n    Show only `n` most recent samples (samples are collect at 1 Hz)
    '''
    num_samples = int(cmd_options['-S']) if '-S' in cmd_options else None
    print(ShowVMPageoutStats.header)
    for stat in VmPageoutStats(num_samples):
        print(stat.page_stats())

@xnudebug_test('test_vmpageoutstats')
def TestMemstats(kernel_target, config, lldb_obj, isConnected ):
    """ Test the functionality of showvmpageoutstats command
        returns
         - False on failure
         - True on success
    """
    if not isConnected:
        print("Target is not connected. Cannot test showmvmpageoutstats")
        return False
    res = lldb.SBCommandReturnObject()
    lldb_obj.debugger.GetCommandInterpreter().HandleCommand("showvmpageoutstats", res)
    result = res.GetOutput()
    if len(result.splitlines()) < 2:
        print("Result has fewer than two lines")
        return False
    for line in result.splitlines():
        matches = re.findall(r'(\d|[\w_]+)', line)
        if len(matches) < 23:
            print("Line has fewer than 23 elements!")
            print(line)
            return False
    return True

# EndMacro: showvmpageoutstats