Skip to content
Snippets Groups Projects
bench_ast_diff.py 3.94 KiB
Newer Older
#!/usr/bin/env python3

"""Benchmarks OSCS targets to compare performance with and without use of -ast-diff"""

import argparse
import csv
from pathlib import Path

frama_c_config = which("frama-c-config")

if frama_c_config is None:
    sys.exit("error: cannot find frama-c-config in the path")

    with sp.Popen(args, stdout=sp.PIPE, stderr=sp.STDOUT) as proc:
        out, _ = proc.communicate()
        if proc.returncode != 0:
            sys.exit(f"Error: {args} returned {proc.returncode}: {out}")
        return out.decode()
frama_c_lib = Path(run_and_check([frama_c_config, "-print-lib-path"]))

sys.path.append(str(frama_c_lib / "analysis-scripts"))

import frama_c_results as fcres

Virgile Prevosto's avatar
Virgile Prevosto committed
def create_csv(f, rows):
    with open(f, "w", newline="", encoding="utf-8", errors="ignore") as file:
        fieldnames = ["name", "user_time_standard", "user_time_ast_diff", "gain"]
        writer = csv.DictWriter(file, fieldnames=fieldnames, extrasaction="ignore")
        writer.writeheader()
        writer.writerows(rows)

def process_target(target):
    print(f"now processing {target}")
    if os.access(target, os.F_OK):
        rmtree(Path(target), ignore_errors=True)
    print("standard pass")
    res = sp.run([make, target], stdout=sp.DEVNULL)
    row = {"name": target}
    if res.returncode == 0:
        standard = fcres.load(target + "/stats.txt")
        timeout = 60
        if "user_time" in standard:
            row["user_time_standard"] = standard["user_time"]
            baseline = float(standard["user_time"])
            timeout = baseline * 5
            env = os.environ.copy()
            env["AST_DIFF"] = "1"
            print("AST diff pass")
            try:
                sp.run(
                    [make, target],
                    env=env,
                    timeout=timeout,
                    stdout=sp.DEVNULL,
                    stderr=sp.DEVNULL,
                )
                ast_diff = fcres.load(target + "/stats.txt")
                if "user_time" in ast_diff:
                    row["user_time_ast_diff"] = ast_diff["user_time"]
                    with_ast_diff = float(row["user_time_ast_diff"])
                    row["gain"] = (baseline - with_ast_diff) / baseline
                    row["user_time_ast_diff"] = "FAILURE"
            except sp.TimeoutExpired:
                row["user_time_ast_diff"] = "TIMEOUT"
    else:
        sys.exit(f"error when processing target: {target}")

def run_bench(targets):
    total_standard = 0
    total_ast_diff = 0
    rows = []
        row = process_target(t)
        if "gain" in row:
            total_standard += float(row["user_time_standard"])
            total_ast_diff += float(row["user_time_ast_diff"])
        rows.append(row)
    rows.append(
        {
            "name": "total when both succeed",
            "user_time_standard": total_standard,
            "user_time_ast_diff": total_ast_diff,
            "gain": (total_standard - total_ast_diff) / total_standard,
        }
    )
parser = argparse.ArgumentParser(
    description="Run analyses first in normal mode "
    "and then in incremental mode "
    "(without syntactic diff)"
)
parser.add_argument(
    "-o",
    "--output",
    action="store",
    metavar="PATH",
    type=Path,
    help="store results in the given file",
)

args, targets = parser.parse_known_args()
if not targets:
    print("No targets specified in command line, running for all targets")
    targets = run_and_check([make, "display-targets"]).split()
rows = run_bench(targets)
if args.output is not None:
else:
    print("Results:")
    print("name,user_time_standard,user_time_ast_diff,gain")
    for row in rows:
        print(
            f"{row['name']},{row['user_time_standard']},{row['user_time_ast_diff']},{row['gain']}"
        )