../duty-cycle-throttle

测试perf不同时间内能够采样多少sample.

测试方法: perf + timeout + gups

set -l period 16
for time in 1 2 4 8 16 32 64 128
 set -l label $period-$time
 printf "=== %s ===" $lable
    sudo perf record -z -vv \
        --count $period \
        --phys-data --data --weight \
        -e $event:Pu \
        --output $label.perf.data \
        timeout $time \
        gups --thread=4 --update=800000000 --len=13950255104 --granularity=8 --report=1000 hotset --hot=1065353216 --weight=9 --reverse \
        2> $label.stderr | tee $label.stdout
 echo
end

sudo perf script --force \
    --input $label.perf.data \
    --fields tid,pid,time,phys_addr,addr,event \
    > $label.perf.data.csv 2> $label.perf.data.err
    
#!/usr/bin/env python3
import math
import re
from io import StringIO
from pathlib import Path

import pandas as pd
from fire import Fire

HEX = r"0x[0-9a-fA-F]+"
PAGE_SIZE = 4096


def count_hot(samples, start, length):
    count = samples.query(f"{start + length - (1<<30)} <= va < {start} + {length}").shape[0]
    return count


def main(run):
    run = Path(run)
    event, period = run.stem.split("-")
    start, length = list(
        map(
            lambda x: int(x, 0),
            re.search(
                rf"memory (?P<start>{HEX}) length (?P<length>\d+)",
                run.with_suffix(".stdout").read_text(),
            ).groups()))
    samples = pd.read_csv(
        StringIO(run.with_suffix(".perf.data.csv").read_text().replace("/", " ").replace(":", " ")),
        names=["pid", "tid", "ts", "event", "precision", "va", "pa"],
        sep=r"\s+",
    )
    # print(samples)
    samples["va"] = samples["va"].apply(int, base=16)
    samples["pa"] = samples["pa"].apply(int, base=16)
    samples["vpfn"] = samples["va"] / PAGE_SIZE
    samples["ppfn"] = samples["pa"] / PAGE_SIZE
    # query the number of samples whose va falls between the last gib of the memory range
    start_ts, last_ts = samples.ts.min(), samples.ts.max()
    upages = length / PAGE_SIZE
    # print("event,period,start,length,time,total_sample,hot_sample,hot_sample_ratio,hot_page,hot_page_ratio,hot_page_coverage")
    for time in range(1, math.ceil(last_ts - start_ts)):
        sub = samples.query(f"ts < {start_ts + time}")
        total = sub.shape[0]
        hot = count_hot(sub, start, length)
        # unique hot page
        uhot = count_hot(sub.drop_duplicates(subset=["vpfn"]), start, length)
        print(f"{event},{period},{start:#x},{length:#x},{time},{total},{hot},{hot/total:.6f},{uhot},{uhot/total:.6f},{uhot/upages:.6f}")
    total = samples.shape[0]
    hot = count_hot(samples, start, length)
    uhot = count_hot(samples.drop_duplicates(subset=["vpfn"]), start, length)
    print(f"{event},{period},{start:#x},{length:#x},overall,{total},{hot},{hot/total:.6f},{uhot},{uhot/total:.6f},{uhot/upages:.6f}")


if __name__ == "__main__":
    Fire(main)
echo cloud-hyperviso pcm-memory virtiofsd gdb | xargs -n1 sudo pkill -9
sudo swapoff --all
sudo sysctl -w vm.overcommit_memory=1
echo 3 | sudo tee /proc/sys/vm/drop_caches
ulimit -n 65535
echo 3000000 | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_{min,max}_freq