Files
botw/tools/progress.py
T
Léo Lam 2204f46b0b Remove expected/
The intention was to catch functional regressions in non-matching
functions but this doesn't actually work well because referenced
code and data may have moved after a function was dumped, in which
case the reference checker is unable to verify that function calls
and data references are still correct.

Considering this increases the amount of complexity in the checker
and makes the workflow more complicated for contributors, let's just
drop this mechanism. It isn't worth it.

Putting binary files in the repo is also pretty meh.
2021-07-30 20:06:14 +02:00

102 lines
3.7 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
from collections import defaultdict
from colorama import Back, Fore, Style
from util import utils
from util.utils import FunctionStatus
import typing as tp
parser = argparse.ArgumentParser()
parser.add_argument("--csv", "-c", action="store_true",
help="Print a CSV line rather than a human-readable progress report")
parser.add_argument("--print-nm", "-n", action="store_true",
help="Print non-matching functions with major issues")
parser.add_argument("--print-eq", "-e", action="store_true",
help="Print non-matching functions with minor issues")
parser.add_argument("--print-ok", "-m", action="store_true",
help="Print matching functions")
args = parser.parse_args()
code_size_total = 0
num_total = 0
code_size: tp.DefaultDict[FunctionStatus, int] = defaultdict(int)
counts: tp.DefaultDict[FunctionStatus, int] = defaultdict(int)
for info in utils.get_functions():
code_size_total += info.size
num_total += 1
if not info.decomp_name:
continue
counts[info.status] += 1
code_size[info.status] += info.size
if not args.csv:
if info.status == FunctionStatus.NonMatching:
if args.print_nm:
print(f"{Fore.RED}NM{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}")
elif info.status == FunctionStatus.Equivalent:
if args.print_eq:
print(f"{Fore.YELLOW}EQ{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}")
elif info.status == FunctionStatus.Matching:
if args.print_ok:
print(f"{Fore.GREEN}OK{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}")
elif info.status == FunctionStatus.Wip:
print(
f"{Back.RED}{Style.BRIGHT}{Fore.WHITE} WIP {Style.RESET_ALL} {utils.format_symbol_name(info.decomp_name)}{Style.RESET_ALL}")
def format_progress(label: str, num: int, size: int):
percentage = round(100 * num / num_total, 3)
size_percentage = round(100 * size / code_size_total, 3)
return f"{num:>7d} {label}{Fore.RESET} ({percentage}% | size: {size_percentage}%)"
def format_progress_for_status(label: str, status: FunctionStatus):
return format_progress(label, counts[status], code_size[status])
if args.csv:
import git
version = 1
git_object = git.Repo().head.object
timestamp = str(git_object.committed_date)
git_hash = git_object.hexsha
fields = [
str(version),
timestamp,
git_hash,
str(num_total),
str(code_size_total),
str(counts[FunctionStatus.Matching]),
str(code_size[FunctionStatus.Matching]),
str(counts[FunctionStatus.Equivalent]),
str(code_size[FunctionStatus.Equivalent]),
str(counts[FunctionStatus.NonMatching]),
str(code_size[FunctionStatus.NonMatching]),
]
print(",".join(fields))
else:
print()
print(f"{num_total:>7d} functions (size: ~{code_size_total} bytes)")
count_decompiled = counts[FunctionStatus.Matching] + counts[FunctionStatus.Equivalent] + counts[
FunctionStatus.NonMatching]
code_size_decompiled = code_size[FunctionStatus.Matching] + code_size[FunctionStatus.Equivalent] + code_size[
FunctionStatus.NonMatching]
print(format_progress(f"{Fore.CYAN}decompiled", count_decompiled, code_size_decompiled))
print(format_progress_for_status(f"{Fore.GREEN}matching", FunctionStatus.Matching))
print(format_progress_for_status(f"{Fore.YELLOW}non-matching (minor issues)", FunctionStatus.Equivalent))
print(format_progress_for_status(f"{Fore.RED}non-matching (major issues)", FunctionStatus.NonMatching))
print()