diff --git a/share/analysis-scripts/benchmark.sh b/share/analysis-scripts/benchmark.sh deleted file mode 100755 index 3b94892cd32f197cd0c5597e277ebafcd0395b58..0000000000000000000000000000000000000000 --- a/share/analysis-scripts/benchmark.sh +++ /dev/null @@ -1,199 +0,0 @@ -#!/bin/bash -eu - -# -------------------------------------------------------------------------- -# --- Command Line Parsing --- -# -------------------------------------------------------------------------- - -targets="" -git_hash="master" -clone_dir="frama-c-clones" -comment="" -show_usage="" -repository_path="" -makefile_path="." -output_file="benchmark-results.csv" - -while [[ $# > 0 ]] -do - case $1 in - -b|--hash|--branch) - git_hash="$2" - shift - ;; - - -d|--clone-dir) - clone_dir="$2" - shift - ;; - - -c|--comment) - comment="$2" - shift - ;; - - -p|--repository-path) - repository_path="$2" - shift - ;; - - -m|--makefile-path) - makefile_path="$2" - shift - ;; - - -o|--output) - output_file="$2" - shift - ;; - - -h|--help) - show_usage="yes" - ;; - - *) - targets="$targets $1" - ;; - esac - shift -done - -if [ -z "$targets" -o -n "$show_usage" ] -then - echo "Usage: $0 TARGET ..." - echo "Run benchmark for the specified targets." - echo "" - echo "The following arguments can be given:" - echo " -b, --hash HASH, selects HASH or BRANCH in the frama-c repository" - echo " --branch BRANCH" - echo " -d, --clone-dir path to the directory where frama-c versions are" - echo " cloned" - echo " -c, --comment COMMENT a comment associated to results for better" - echo " readability of the results; if omitted," - echo " defaults to the Frama-C branch name" - echo " -p, --repository-path PATH do not clone frama-c, use this repository instead" - echo " -m, --makefile-path FILE path to the makefile which can build the target" - echo " -o, --output FILE path to the output CSV file to be filled" - echo " -h, --help prints this help and quits" - exit 1 -fi - -if [ -z "$comment" ] -then - # Note: if the user gave us a commit hash instead of a branch name, - # we do not retrieve the branch name (which may not exist anyway) - comment="$git_hash" -fi - - -# -------------------------------------------------------------------------- -# --- Frama-C repository --- -# -------------------------------------------------------------------------- - -if [ -z "$repository_path" ] -then - # git_hash and comment cannot be parsed yet: - # we need the git clone to dereference it, in case it's a tag/branch name - - ##### Preparation of git clones/checkouts ##### - - bare="$clone_dir/frama-c.git" - - # Check if bench clone exists - if [ ! -d "$bare" ] - then - echo "Cloning Frama-C..." - git clone --bare --quiet git@git.frama-c.com:frama-c/frama-c "$bare" - sed --in-place '/bare = true/d' $bare/config - fi - - # Fetch all refs - ( - cd $bare - git fetch origin '+refs/heads/*:refs/heads/*' --prune - ) - - # Now we can parse the other arguments - - # Resolve branch name if given - git_hash=`git --git-dir="$bare" rev-parse "$git_hash"` - - # repository_path must be an absolute path - repository_path="$(readlink -f "$clone_dir/$git_hash")" - - # Checkout and build the branch if necessary - if [ ! -e "$clone_dir/$git_hash" ] - then - echo "Building Frama-C for git commit: $git_hash" - # The workdir cmd can extract a working tree of the desired hash - # without cloning once more - workdir_cmd=`locate git-new-workdir --limit 1` - if [ -z "$workdir_cmd" ] - then - git --git-dir="$bare" worktree add "$repository_path" "$git_hash" - else - bash "$workdir_cmd" "$bare" "$repository_path" "$git_hash" - fi - # Build Frama-C - ( - cd "$repository_path"; - autoconf; - ./configure --disable-wp; - make -j; - ) - fi -fi - -# In case building has failed for some reason, we check if the actual binary -# exists and report an error otherwise, indicating which directory should be -# deleted. -FRAMAC="$repository_path/bin/frama-c" - -if [ ! -e "$FRAMAC" ] -then - echo "Error: could not find Frama-C binary: $FRAMAC" - echo "You may try erasing the directory to force a recompilation." - exit 2 -fi - - -# -------------------------------------------------------------------------- -# --- Benchmark execution and output --- -# -------------------------------------------------------------------------- - -header="target\ttimestamp\tFrama-C hash\tcomment\tcpu_time\tmaxmem\talarms\t\ -warnings\tsem reach fun\tsyn reach fun\ttotal fun\tsem reach stmt\t\ -syn reach stmt\tcommand args\tcase study git hash" - -if [ ! -e "$output_file" ] -then - echo "output file does not exist, creating: $output_file" - printf "$header\n" > "$output_file" -fi - -for target in $targets -do - pushd $makefile_path > /dev/null - make --no-print-directory $target BENCHMARK=y FRAMAC="$FRAMAC" - - case_git_hash=`git rev-parse HEAD` - . $target/stats.txt - popd > /dev/null - - printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \ - "$target" "$timestamp" $git_hash "$comment" \ - $user_time $memory $alarms $warnings \ - $sem_reach_fun $syn_reach_fun $total_fun $sem_reach_stmt $syn_reach_stmt \ - "$cmd_args" $case_git_hash \ - >> "$output_file" - - if command -v sqlite3 2>&1 >/dev/null - then - export comment - export git_hash - export case_git_hash - export target - "${BASH_SOURCE%/*}/bench-sqlite.sh" "$makefile_path/$target/stats.txt" - else - echo "command 'sqlite3' not found, cannot update the database" - fi -done diff --git a/share/analysis-scripts/clone.sh b/share/analysis-scripts/clone.sh index 19fe1a82afc70a5f1b8880713e67d0648e57af6d..0ed6b8553c2144fb94fb9cd8f3260f39b65212d9 100755 --- a/share/analysis-scripts/clone.sh +++ b/share/analysis-scripts/clone.sh @@ -64,15 +64,8 @@ target_path="$(readlink -f "$clone_dir/$git_hash")" # Checkout if [ ! -e "$target_path" ] then - # The workdir cmd can extract a working tree of the desired hash - # without cloning once more - workdir_cmd=`locate git-new-workdir --limit 1` - if [ -z "$workdir_cmd" ] - then - git --git-dir="$bare" worktree add "$target_path" "$git_hash" - else - bash "$workdir_cmd" "$bare" "$target_path" "$git_hash" - fi + git clone "$bare" "$target_path" --quiet + (cd "$target_path" && git checkout "$git_hash" --quiet) fi # Build Frama-C diff --git a/share/analysis-scripts/results_display.py b/share/analysis-scripts/results_display.py index 732784ea6ddfd9ca73f3436aedb753418fd8de30..afec20997215b4f077ac97000b3848155009421c 100644 --- a/share/analysis-scripts/results_display.py +++ b/share/analysis-scripts/results_display.py @@ -133,6 +133,14 @@ class PlainDisplay: elif s == "@-": attributes = self.NEGATIVE else: + available = size - n + if len(s) > available: + if available > 16: + s = s[0:9] + '...' + s[13-available:] + elif available > 6: + s = s[0:available - 3] + '...' + else: + s = '' n += len(s) self.write(s, attributes if override is None else override) if n < size: @@ -184,7 +192,7 @@ class CursesDisplay(PlainDisplay): stdscr.nodelay(True) stdscr.refresh() # Needs to be done once or nothing will be output - self.window = curses.newpad(400, 160) + self.window = curses.newpad(2000, 160) curses.init_color(curses.COLOR_YELLOW, 300, 300, 300) curses.init_pair(1, curses.COLOR_RED, 0) curses.init_pair(2, curses.COLOR_GREEN, 0) @@ -198,15 +206,22 @@ class CursesDisplay(PlainDisplay): self.scroll_y = 0 def write(self, text, attributes=0): - self.window.addstr(text, attributes) + try: + self.window.addstr(text, attributes) + except curses.error: # don't exactly know why it happens, but it happens + pass def print_table(self, results): self.window.clear() PlainDisplay.print_table(self, results) height, width = self.stdscr.getmaxyx() + self.scroll_y = max(0, min(self.scroll_y, len(results)-height+2)) # relocate scroll if too far try: - self.window.refresh(0, 0, 0, 0, 1, width - 1) - self.window.refresh(self.scroll_y + 2, 0, 2, 0, height - 1, width - 1) + if len(results) + 2 > height: + self.window.refresh(0, 0, 0, 0, 1, width - 1) + self.window.refresh(self.scroll_y + 2, 0, 2, 0, height - 1, width - 1) + else: + self.window.refresh(0, 0, 0, 0, height - 1, width - 1) except Exception: # getmaxyx may be out of date, especially when resizing down the # window ; just ignore errors diff --git a/share/analysis-scripts/summary.py b/share/analysis-scripts/summary.py index 8c9949fa10ab2cc036ab80477dc0e848506c0ce7..b2ee5d102f1b4319ecc279c67e73e45d60fe4c38 100755 --- a/share/analysis-scripts/summary.py +++ b/share/analysis-scripts/summary.py @@ -30,6 +30,8 @@ import os import signal import argparse import uuid +import csv +from pathlib import Path import frama_c_results import results_display @@ -76,15 +78,18 @@ def list_targets(dir): def clone_frama_c(clonedir, hash): print("Cloning Frama-C", hash, "...") - res = subprocess.run( - ["./scripts/clone.sh", "--clone-dir", clonedir, hash], - stdout=subprocess.PIPE, - encoding="ascii", - ) - if res.returncode != 0: - raise OperationException("Cannot clone repository. Try to manually" - "remove the broken clone in " + clonedir) - return res.stdout.strip() + "/build" + try: + clone_cmd = Path(__file__).parent / "clone.sh" + res = subprocess.run( + [clone_cmd, "--clone-dir", clonedir, hash], + stdout=subprocess.PIPE, + encoding="ascii", + check=True) + return res.stdout.strip() + "/build" + except subprocess.CalledProcessError as e: + raise OperationException( + f"Cannot clone repository. Try to manually remove the broken clone" + f"in {clonedir}\n{e.output}") from e def run_make(framac, benchmark_tag=None): args = ["make", "--keep-going", "all"] @@ -141,6 +146,22 @@ def poll_results(targets, benchmark_tag): return results +def dump_results_csv(results, path): + with open(path, 'w', newline='') as file: + fieldnames = [ + "target_name", "timestamp", + "sem_reach_fun", "syn_reach_fun", "total_fun", + "sem_reach_stmt", "syn_reach_stmt", + "alarms", "warnings", "coverage", + "user_time", "memory"] + writer = csv.DictWriter( + file, + fieldnames=fieldnames, + extrasaction='ignore') + writer.writeheader() + writer.writerows(results) + + def run_analyses(display, database, framac, benchmark_tag): results = [] targets = list_targets(".") @@ -197,7 +218,9 @@ parser.add_argument("-c", "--comment", parser.add_argument("-p", "--repository-path", action="store", metavar="PATH", help="don't clone Frama-C, use this git repository instead") - +parser.add_argument("-o", "--output-csv", + action="store", metavar="PATH", type=Path, + help="output the results to the given CSV file") errors = b"" @@ -237,6 +260,9 @@ try: print("Results:\n") results_display.PlainDisplay().print_table(results) + if args.output_csv is not None: + dump_results_csv(results, args.output_csv) + except OperationException as e: errors += bytearray(str(e), "ascii")