Ctrl K
ComunidadGuías…

benchmark/timer.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3

"""
benchmark all single-byte input examples:

rotor:

./benchmark/timer.py benchmark/m64-full-Z3 benchmark/m64-full-Z3-const benchmark/m64-riscu-Z3 benchmark/m64-riscu-Z3-const benchmark/m32-full-Z3 benchmark/m32-full-Z3-const benchmark/m32-riscu-Z3 benchmark/m32-riscu-Z3-const benchmark/m64-full-bitwuzla benchmark/m64-full-bitwuzla-const benchmark/m64-riscu-bitwuzla benchmark/m64-riscu-bitwuzla-const benchmark/m32-full-bitwuzla benchmark/m32-full-bitwuzla-const benchmark/m32-riscu-bitwuzla benchmark/m32-riscu-bitwuzla-const benchmark/m64-full-BVDD benchmark/m64-riscu-BVDD benchmark/m32-full-BVDD benchmark/m32-riscu-BVDD -o rotor.csv --start 0 --end 150 --step 30

bitme:

./benchmark/timer.py benchmark/m32-riscu-Z3 benchmark/m32-riscu-Z3-const benchmark/m32-riscu-bitwuzla benchmark/m32-riscu-bitwuzla-const benchmark/m32-riscu-BVDD benchmark/m32-riscu-BVDD-bitr benchmark/m32-riscu-CFLOBVDD benchmark/m32-riscu-CFLOBVDD-bitr -o bitme.csv --start 0 --end 150 --step 30
"""

import subprocess
import sys
import argparse
import csv
import os

def get_script_lines(script_path):
    """
    Reads a script and returns a list of command objects.
    Each object tracks the command string and its completion status.
    """
    try:
        with open(script_path, 'r') as f:
            raw_lines = f.readlines()
    except FileNotFoundError:
        print(f"Error: The file '{script_path}' was not found.")
        sys.exit(1)

    # We store a dict for each line to track state mutable
    commands = [
        {'cmd': line.strip(), 'done': False}
        for line in raw_lines
        if line.strip() and not line.strip().startswith('#')
    ]
    return commands

def process_script_at_timeout(script_lines, timeout):
    """
    Iterates through the script lines.
    - If a line is already 'done', we skip execution and count it.
    - If not, we run it. If it finishes, we mark it 'done' and count it.

    Returns the total count of finished lines (previous + new).
    """
    total_finished = 0

    for line_obj in script_lines:
        # Optimization: If already done in a previous (smaller) timeout,
        # skip execution but increment count.
        if line_obj['done']:
            total_finished += 1
            continue

        # If not done, attempt to run it
        try:
            subprocess.run(
                line_obj['cmd'],
                shell=True,
                executable='/bin/bash',
                timeout=timeout,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL
            )
            # If we reach here, it finished successfully
            line_obj['done'] = True
            total_finished += 1

        except subprocess.TimeoutExpired:
            # It failed to finish; do not increment count, do not mark done
            pass

    return total_finished

def main():
    parser = argparse.ArgumentParser(description="Benchmark multiple bash scripts with optimized incremental timeouts.")
    parser.add_argument("scripts", nargs='+', help="List of bash script files to test")
    parser.add_argument("--output", "-o", required=True, help="Path to the output CSV file")
    parser.add_argument("--start", type=float, required=True, help="Starting timeout in seconds")
    parser.add_argument("--end", type=float, required=True, help="Ending timeout in seconds")
    parser.add_argument("--step", type=float, required=True, help="Timeout increment in seconds")

    args = parser.parse_args()

    if args.start > args.end:
        print("Error: Start timeout cannot be greater than end timeout.")
        sys.exit(1)
    if args.step <= 0:
        print("Error: Step must be positive.")
        sys.exit(1)

    # 1. Initialize State
    # Dictionary mapping: filename -> list of {'cmd': str, 'done': bool}
    scripts_state = {}
    print("Loading scripts and initializing state...")
    for script_file in args.scripts:
        lines = get_script_lines(script_file)
        scripts_state[script_file] = lines
        print(f" -> Loaded '{script_file}' ({len(lines)} executable lines)")

    results = []

    print(f"\nStarting optimized benchmark: {args.start}s to {args.end}s (step {args.step}s)...")

    current_timeout = args.start

    # 2. Main Execution Loop
    while current_timeout <= args.end + (args.step / 10000.0):
        print(f"Testing timeout: {current_timeout:.2f}s...", end='', flush=True)

        row = [current_timeout]

        for script_file in args.scripts:
            # Pass the mutable list of line objects
            # The function will update 'done' statuses in-place
            count = process_script_at_timeout(scripts_state[script_file], current_timeout)
            row.append(count)

        results.append(row)
        print(" Done.")

        current_timeout += args.step

    # 3. Write Data
    headers = ['timeout (s)'] + [os.path.basename(s) for s in args.scripts]

    try:
        with open(args.output, 'w', newline='') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow(headers)
            writer.writerows(results)
        print(f"\nSuccess! Data written to '{args.output}'.")
    except IOError as e:
        print(f"\nError writing to file: {e}")

if __name__ == "__main__":
    main()