Integrate psp function finder (#1293)

Current output looks like this
```
| Ovl    | Function                 |   Length |   Branches | Jtbl   | WIP                             | %     |
|--------|--------------------------|----------|------------|--------|---------------------------------|-------|
| wrp    | DestroyCurrentEntity     |       16 |          2 |        | https://decomp.me/scratch/aKfDL | 0.99  |
| wrp    | CreateEntitiesToTheRight |       90 |         11 |        | https://decomp.me/scratch/nKKQN | 0.989 |
| wrp    | CreateEntitiesAbove      |       92 |         11 |        | https://decomp.me/scratch/ezNeo | 0.99  |
| wrp    | CreateEntitiesToTheLeft  |       97 |         12 |        |                                 |       |
| wrp    | CreateEntitiesBelow      |       99 |         12 |        |                                 |       |
| wrp    | InitRoomEntities         |      151 |         10 |        | https://decomp.me/scratch/thtl9 | 0.981 |
| wrp    | EntityEquipItemDrop      |      584 |         67 | Yes    | https://decomp.me/scratch/R4CBY | 0.993 |
| wrp    | EntityNumericDamage      |      683 |         51 |        | https://decomp.me/scratch/IyaVH | 0.989 |
| tt_000 | func_80172C30            |      731 |         65 |        |                                 |       |
| wrp    | EntityPrizeDrop          |      973 |        120 | Yes    |                                 |       |
| wrp    | EntityStageNamePopup     |      990 |         83 |        | https://decomp.me/scratch/hTUwZ | 0.972 |
| wrp    | EntityWarpRoom           |     1034 |         83 | Yes    | https://decomp.me/scratch/4MUb6 | 0.953 |
| wrp    | EntityRelicOrb           |     1186 |         87 | Yes    |                                 |       |
| tt_000 | func_80172120            |     1199 |        126 | Yes    |                                 |       |
| wrp    | EntityRedDoor            |     1248 |        112 | Yes    |                                 |       |
| wrp    | HitDetection             |     1628 |        196 |        |                                 |       |
```

I haven't tested the CI script, will just do some commits on master if
it's broken
This commit is contained in:
sozud 2024-06-17 15:52:17 -07:00 committed by GitHub
parent 7c6d759f12
commit b2595df83d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 252 additions and 0 deletions

View File

@ -220,3 +220,73 @@ jobs:
git commit -m 'Update reports' || true
git push
working-directory: gh-duplicates
generate-duplicates-report-psp:
strategy:
matrix:
version: ["pspeu"]
include:
- dependency: pspeu
version: pspeu
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
needs: build-and-test
runs-on: ubuntu-latest
env:
VERSION: ${{ matrix.version }}
steps:
- name: Clone main repository
uses: actions/checkout@v4
with:
submodules: false
- name: Install requirements
run: make update-dependencies
- name: Get dependencies
uses: actions/cache@v4
with:
path: 'disks/dependencies'
key: sotn-${{ matrix.dependency }}-deps
- name: Setting up dependencies
working-directory: disks
run: cat dependencies/* | tar -zxf -
- name: Extract dependencies
run: make extract_disk
- name: Obtain built binaries
uses: actions/download-artifact@v4
with:
name: build_${{ matrix.version }}
path: build/${{ matrix.version }}
- name: Clone asset repository
uses: actions/checkout@v4
with:
ref: 'gh-duplicates-${{ matrix.version }}'
path: 'gh-duplicates'
- name: Set-up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install secondary pre-requirements
run: |
pip3 install -r tools/requirements-python.txt & \
(sudo apt-get update && sudo apt-get install graphviz) & \
wait
- name: Generate function report
run: |
make force_symbols
make force_extract
git clean -fdx asm/
git checkout config/
rm -rf build/us/main.ld
rm -rf build/us/weapon.ld
make -j extract
python3 tools/function_finder/function_finder_psp.py > gh-duplicates/functions.md
rm -rf gh-duplicates/function_calls/ || true
mv function_calls gh-duplicates/
mv function_graphs.md gh-duplicates
- name: Commit all reports
run: |
git config --global user.name 'GitHub Action'
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add -A
git commit -m 'Update reports' || true
git push
working-directory: gh-duplicates

View File

@ -0,0 +1,182 @@
#!/usr/bin/python3
# tool to list functions by difficulty and decomp.me WIP links
import argparse
from pathlib import Path
import sys
from tabulate import tabulate
import os
import re
import concurrent.futures
from helpers import find_scratches
parser = argparse.ArgumentParser(
description="Create list of undecompiled functions and sort them by difficulty"
)
parser.add_argument(
"--use-call-trees",
required=False,
action="store_true",
help="Use to add links to the 'function_calls' folder generated by analyze_calls.py",
)
parser.add_argument(
"--no-fetch",
required=False,
action="store_true",
help="Disable fetching scratch links from decomp.me",
)
parser.add_argument(
"--keywords",
metavar="keyword",
type=str,
nargs="+",
help="Only match paths with these keywords",
)
# look in asm files, read in the text and check for branches and jump tables
def get_asm_files(asm_path):
files = []
for path in Path(asm_path).rglob("*.s"):
# ignore data
if ".data" in str(path) or ".bss" in str(path):
continue
f = open(f"{path}", "r")
text = f.read()
# check for different mips branch types and count
branches = 0
branch_types = [
"b ",
"bczt ",
"bczf ",
"beq ",
"beqz ",
"bge ",
"bgeu ",
"bgez ",
"bgezal ",
"bgt ",
"bgtu ",
"bgtz ",
"ble ",
"bleu ",
"blez ",
"bgezal ",
"bltzal ",
"blt ",
"bltu ",
"bltz ",
"bne ",
"bnez ",
"j ",
"jal ",
"jalr ",
"jr ",
]
for branch in branch_types:
branches = branches + text.count(branch)
jump_table = " "
if "jpt_" in text or "jtbl_" in text:
jump_table = "Yes"
f = {"name": path, "text": text, "branches": branches, "jump_table": jump_table}
files.append(f)
return files
def find_wip(o):
result = find_scratches(o[1], "psp")
if result:
return {"link": result[0], "percent": result[1]}
return None
if __name__ == "__main__":
args = parser.parse_args()
asm_files = get_asm_files("asm/pspeu")
# sort by name, then number of branches, then length
asm_files = sorted(asm_files, key=lambda x: (x["name"]))
asm_files = sorted(asm_files, key=lambda x: (x["branches"]))
asm_files = sorted(asm_files, key=lambda x: len(x["text"].split("\n")))
if args.keywords and len(args.keywords):
# filter based on keywords
asm_files = [
file
for file in asm_files
if any(keyword in str(file["name"]) for keyword in args.keywords)
]
output = []
for f in asm_files:
name = str(f["name"])
length = len(f["text"].split("\n"))
branches = f["branches"]
jump_table = f["jump_table"]
matches = re.search(r"\/(\w+)\/nonmatchings\/\w+\/(\w+)\.s", name)
if matches:
ovl_name = matches.group(1)
func_name = matches.group(2)
else:
ovl_name = ""
ovl_pattern = r'/([^/]+)_psp/'
ovl_match = re.search(ovl_pattern, name)
if ovl_match:
ovl_name = ovl_match.group(1)
name_pattern = r'/([^/]+)\.s'
name_match = re.search(name_pattern, name)
if name_match:
func_name = name_match.group(1)
wip = ""
wip_percentage = ""
output.append(
[
ovl_name,
func_name,
length,
branches,
jump_table,
wip,
wip_percentage,
]
)
if not args.no_fetch:
# we are mostly waiting on IO so run in parallel
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = [executor.submit(find_wip, o) for o in output]
results = [f.result() for f in futures]
# Update output with the results
for i, o in enumerate(output):
# keep the in-source results as definitive
if results[i] != None:
o[5] = results[i]["link"]
o[6] = results[i]["percent"]
if args.use_call_trees:
base_url = (
"https://raw.githubusercontent.com/Xeeynamo/sotn-decomp/gh-duplicates"
)
for i, o in enumerate(output):
unique_name = ".".join([o[0], o[1]])
svg_path = os.path.join("function_calls", f"{unique_name}.svg")
if os.path.exists(svg_path):
o[1] = f"[{o[1]}]({base_url}/{svg_path})"
headers = ["Ovl", "Function", "Length", "Branches", "Jtbl", "WIP", "%"]
print(tabulate(output, headers=headers, tablefmt="github"))