brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.7 KiB · 9e01fda Raw
129 lines · plain
1"""Reads JSON files produced by the benchmarking framework and renders them.2 3Installation:4> apt-get install python3-pip5> pip3 install matplotlib pandas seaborn6 7Run:8> python3 libc/benchmarks/libc-benchmark-analysis.py3 <files>9"""10 11import argparse12import json13import pandas as pd14import seaborn as sns15import matplotlib.pyplot as plt16from matplotlib.ticker import EngFormatter17 18def formatUnit(value, unit):19    return EngFormatter(unit, sep="").format_data(value)20 21def formatCache(cache):22  letter = cache["Type"][0].lower()23  level = cache["Level"]24  size = formatUnit(cache["Size"], "B")25  ways = cache["NumSharing"]26  return F'{letter}L{level}:{size}/{ways}'27 28def getCpuFrequency(study):29    return study["Runtime"]["Host"]["CpuFrequency"]30 31def getId(study):32    CpuName = study["Runtime"]["Host"]["CpuName"]33    CpuFrequency = formatUnit(getCpuFrequency(study), "Hz")34    Mode = " (Sweep)" if study["Configuration"]["IsSweepMode"] else ""35    CpuCaches = ", ".join(formatCache(c) for c in study["Runtime"]["Host"]["Caches"])36    return F'{CpuName} {CpuFrequency}{Mode}\n{CpuCaches}'37 38def getFunction(study):39    return study["Configuration"]["Function"]40 41def getLabel(study):42    return F'{getFunction(study)} {study["StudyName"]}'43 44def displaySweepData(id, studies, mode):45    df = None46    for study in studies:47        Measurements = study["Measurements"]48        SweepModeMaxSize = study["Configuration"]["SweepModeMaxSize"]49        NumSizes = SweepModeMaxSize + 150        NumTrials = study["Configuration"]["NumTrials"]51        assert NumTrials * NumSizes  == len(Measurements), 'not a multiple of NumSizes'52        Index = pd.MultiIndex.from_product([range(NumSizes), range(NumTrials)], names=['size', 'trial'])53        if df is None:54            df = pd.DataFrame(Measurements, index=Index, columns=[getLabel(study)])55        else:56            df[getLabel(study)] = pd.Series(Measurements, index=Index)57    df = df.reset_index(level='trial', drop=True)58    if mode == "cycles":59        df *= getCpuFrequency(study)60    if mode == "bytespercycle":61        df *= getCpuFrequency(study)62        for col in df.columns:63            df[col] = pd.Series(data=df.index, index=df.index).divide(df[col])64    FormatterUnit = {"time":"s","cycles":"","bytespercycle":"B/cycle"}[mode]65    Label = {"time":"Time","cycles":"Cycles","bytespercycle":"Byte/cycle"}[mode]66    graph = sns.lineplot(data=df, palette="muted", ci=95)67    graph.set_title(id)68    graph.yaxis.set_major_formatter(EngFormatter(unit=FormatterUnit))69    graph.yaxis.set_label_text(Label)70    graph.xaxis.set_major_formatter(EngFormatter(unit="B"))71    graph.xaxis.set_label_text("Copy Size")72    _ = plt.xticks(rotation=90)73    plt.show()74 75def displayDistributionData(id, studies, mode):76    distributions = set()77    df = None78    for study in studies:79        distribution = study["Configuration"]["SizeDistributionName"]80        distributions.add(distribution)81        local = pd.DataFrame(study["Measurements"], columns=["time"])82        local["distribution"] = distribution83        local["label"] = getLabel(study)84        local["cycles"] = local["time"] * getCpuFrequency(study)85        if df is None:86            df = local87        else:88            df = df.append(local)89    if mode == "bytespercycle":90        mode = "time"91        print("`--mode=bytespercycle` is ignored for distribution mode reports")92    FormatterUnit = {"time":"s","cycles":""}[mode]93    Label = {"time":"Time","cycles":"Cycles"}[mode]94    graph = sns.violinplot(data=df, x="distribution", y=mode, palette="muted", hue="label", order=sorted(distributions))95    graph.set_title(id)96    graph.yaxis.set_major_formatter(EngFormatter(unit=FormatterUnit))97    graph.yaxis.set_label_text(Label)98    _ = plt.xticks(rotation=90)99    plt.show()100 101 102def main():103    parser = argparse.ArgumentParser(description="Process benchmark json files.")104    parser.add_argument("--mode", choices=["time", "cycles", "bytespercycle"], default="time", help="Use to display either 'time', 'cycles' or 'bytes/cycle'.")105    parser.add_argument("files", nargs="+", help="The json files to read from.")106 107    args = parser.parse_args()108    study_groups = dict()109    for file in args.files:110        with open(file) as json_file:111            json_obj = json.load(json_file)112            Id = getId(json_obj)113            if Id in study_groups:114                study_groups[Id].append(json_obj)115            else:116                study_groups[Id] = [json_obj]117 118    plt.tight_layout()119    sns.set_theme(style="ticks")120    for id, study_collection in study_groups.items():121        if "(Sweep)" in id:122            displaySweepData(id, study_collection, args.mode)123        else:124            displayDistributionData(id, study_collection, args.mode)125 126 127if __name__ == "__main__":128    main()129