tools: Clean up the progress script

And make the output clearer.
This commit is contained in:
Léo Lam 2020-09-07 18:31:51 +02:00
parent 02e6bb42db
commit 3c06896cfe
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
1 changed files with 63 additions and 54 deletions

View File

@ -1,89 +1,98 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
from collections import defaultdict
from colorama import Back, Fore, Style from colorama import Back, Fore, Style
import enum
import utils import utils
from utils import FunctionStatus
import typing as tp
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("--print-nm", "-n", action="store_true", parser.add_argument("--print-nm", "-n", action="store_true",
help="Print non-matching functions") help="Print non-matching functions with major issues")
parser.add_argument("--print-eq", "-e", action="store_true", parser.add_argument("--print-eq", "-e", action="store_true",
help="Print non-matching, semantically equivalent functions") help="Print non-matching functions with minor issues")
parser.add_argument("--print-ok", "-m", action="store_true", parser.add_argument("--print-ok", "-m", action="store_true",
help="Print matching functions") help="Print matching functions")
args = parser.parse_args() args = parser.parse_args()
class AIClassType(enum.Enum):
Action = 0
AI = 1
Behavior = 2
Query = 3
code_size_total = 0 code_size_total = 0
code_size_matching = 0
code_size_equivalent = 0
code_size_nonmatching = 0
num_total = 0 num_total = 0
num_matching = 0 code_size: tp.DefaultDict[FunctionStatus, int] = defaultdict(int)
num_equivalent = 0 counts: tp.DefaultDict[FunctionStatus, int] = defaultdict(int)
num_nonmatching = 0 ai_counts: tp.DefaultDict[AIClassType, int] = defaultdict(int)
num_wip = 0 ai_counts_done: tp.DefaultDict[AIClassType, int] = defaultdict(int)
num_ai_action_done = 0
num_ai_ai_done = 0
num_ai_behavior_done = 0
num_ai_query_done = 0
num_ai_action = 0
num_ai_ai = 0
num_ai_behavior = 0
num_ai_query = 0
for info in utils.get_functions(): for info in utils.get_functions():
code_size_total += info.size code_size_total += info.size
num_total += 1 num_total += 1
ai_class_type: tp.Optional[AIClassType] = None
if info.name.startswith("AI_F_Action_"): if info.name.startswith("AI_F_Action_"):
num_ai_action += 1 ai_class_type = AIClassType.Action
num_ai_action_done += bool(info.decomp_name) elif info.name.startswith("AI_F_AI_"):
if info.name.startswith("AI_F_AI_"): ai_class_type = AIClassType.AI
num_ai_ai += 1 elif info.name.startswith("AI_F_Behavior_"):
num_ai_ai_done += bool(info.decomp_name) ai_class_type = AIClassType.Behavior
if info.name.startswith("AI_F_Behavior_"): elif info.name.startswith("AI_F_Query_"):
num_ai_behavior += 1 ai_class_type = AIClassType.Query
num_ai_behavior_done += bool(info.decomp_name)
if info.name.startswith("AI_F_Query_"): if ai_class_type is not None:
num_ai_query += 1 ai_counts[ai_class_type] += 1
num_ai_query_done += bool(info.decomp_name) if info.decomp_name:
ai_counts_done[ai_class_type] += 1
if not info.decomp_name: if not info.decomp_name:
continue continue
if info.status == utils.FunctionStatus.NonMatching: counts[info.status] += 1
num_nonmatching += 1 code_size[info.status] += info.size
code_size_nonmatching += info.size
if info.status == FunctionStatus.NonMatching:
if args.print_nm: if args.print_nm:
print(f"{Fore.RED}NM{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}") print(f"{Fore.RED}NM{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}")
elif info.status == utils.FunctionStatus.Equivalent: elif info.status == FunctionStatus.Equivalent:
num_equivalent += 1
code_size_equivalent += info.size
if args.print_eq: if args.print_eq:
print(f"{Fore.YELLOW}EQ{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}") print(f"{Fore.YELLOW}EQ{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}")
elif info.status == utils.FunctionStatus.Matching: elif info.status == FunctionStatus.Matching:
num_matching += 1
code_size_matching += info.size
if args.print_ok: if args.print_ok:
print(f"{Fore.GREEN}OK{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}") print(f"{Fore.GREEN}OK{Fore.RESET} {utils.format_symbol_name(info.decomp_name)}")
elif info.status == utils.FunctionStatus.Wip: elif info.status == FunctionStatus.Wip:
num_wip += 1
print(f"{Back.RED}{Style.BRIGHT}{Fore.WHITE} WIP {Style.RESET_ALL} {utils.format_symbol_name(info.decomp_name)}{Style.RESET_ALL}") print(f"{Back.RED}{Style.BRIGHT}{Fore.WHITE} WIP {Style.RESET_ALL} {utils.format_symbol_name(info.decomp_name)}{Style.RESET_ALL}")
print()
print(f"{num_total} functions (size: ~{code_size_total} bytes)") def format_progress(label: str, num: int, size: int):
print(f"{num_matching + num_equivalent} {Fore.CYAN}matching or equivalent{Fore.RESET} \ percentage = round(100 * num / num_total, 3)
({round(100 * (num_matching + num_equivalent) / num_total, 3)}%) \ size_percentage = round(100 * size / code_size_total, 3)
(size: {round(100 * (code_size_matching + code_size_equivalent) / code_size_total, 3)}%)") return f"{num:>7d} {label}{Fore.RESET} ({percentage}% | size: {size_percentage}%)"
print(f"{num_matching} {Fore.GREEN}matching{Fore.RESET} ({round(100 * num_matching / num_total, 3)}%)")
print(f"{num_equivalent} {Fore.YELLOW}equivalent{Fore.RESET} ({round(100 * num_equivalent / num_total, 3)}%)") def format_progress_for_status(label: str, status: FunctionStatus):
print(f"{num_nonmatching} {Fore.RED}non-matching{Fore.RESET} ({round(100 * num_nonmatching / num_total, 3)}%)") return format_progress(label, counts[status], code_size[status])
def format_ai_progress(label: str, class_type: AIClassType):
percentage = round(100 * ai_counts_done[class_type] / ai_counts[class_type], 3)
return f"{ai_counts_done[class_type]:>7d} {label}{Fore.RESET} ({percentage}%)"
print() print()
print(f"{num_ai_action_done}/{num_ai_action} actions ({round(100 * num_ai_action_done / num_ai_action, 3)}%)")
print(f"{num_ai_ai_done}/{num_ai_ai} AIs ({round(100 * num_ai_ai_done / num_ai_ai, 3)}%)") print(f"{num_total:>7d} functions (size: ~{code_size_total} bytes)")
print(f"{num_ai_behavior_done}/{num_ai_behavior} behaviors ({round(100 * num_ai_behavior_done / num_ai_behavior, 3)}%)")
print(f"{num_ai_query_done}/{num_ai_query} queries ({round(100 * num_ai_query_done / num_ai_query, 3)}%)") 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()
print(format_ai_progress("actions", AIClassType.Action))
print(format_ai_progress("AIs", AIClassType.AI))
print(format_ai_progress("behaviors", AIClassType.Behavior))
print(format_ai_progress("queries", AIClassType.Query))