mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
misc/github: Post firmware stats after PRs.
This commit is contained in:
parent
a110f5c478
commit
c77ef7f96a
61
.github/workflows/firmware.yml
vendored
61
.github/workflows/firmware.yml
vendored
@ -65,13 +65,72 @@ jobs:
|
|||||||
run: source tools/ci.sh && ci_build_target ${{ matrix.target }}
|
run: source tools/ci.sh && ci_build_target ${{ matrix.target }}
|
||||||
|
|
||||||
- name: '⬆ Upload artifacts'
|
- name: '⬆ Upload artifacts'
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.target }}
|
name: ${{ matrix.target }}
|
||||||
path: ${{ matrix.target }}
|
path: ${{ matrix.target }}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
|
post-stats:
|
||||||
|
needs: build-firmware
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
steps:
|
||||||
|
- name: '⏳ Checkout repository'
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: false
|
||||||
|
|
||||||
|
- name: '♻ Caching dependencies'
|
||||||
|
uses: actions/cache@v4.0.2
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: ~/cache/gcc
|
||||||
|
key: 'arm-gnu-toolchain-13.2.rel1'
|
||||||
|
|
||||||
|
- name: '🐍 Install Python'
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
cache: 'pip'
|
||||||
|
python-version: "3.12.4"
|
||||||
|
|
||||||
|
- name: '🛠 Install dependencies'
|
||||||
|
run: |
|
||||||
|
pip install tabulate==0.9.0
|
||||||
|
|
||||||
|
- name: '🤌 Download artifacts'
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: new_firmware
|
||||||
|
merge-multiple: false
|
||||||
|
|
||||||
|
- name: '🤌 Download release'
|
||||||
|
uses: robinraju/release-downloader@v1
|
||||||
|
with:
|
||||||
|
repository: 'openmv/openmv'
|
||||||
|
tag: 'development'
|
||||||
|
fileName: '*.zip'
|
||||||
|
extract: false
|
||||||
|
out-file-path: 'old_firmware'
|
||||||
|
|
||||||
|
- name: '📝 Generate report'
|
||||||
|
run: |
|
||||||
|
TOOLCHAIN_PATH=${HOME}/cache/gcc
|
||||||
|
export PATH=${TOOLCHAIN_PATH}/bin:${PATH}
|
||||||
|
python tools/gen_stats.py > ${GITHUB_WORKSPACE}/stats.txt
|
||||||
|
cat ${GITHUB_WORKSPACE}/stats.txt
|
||||||
|
if [ -s ./stats.txt ]; then
|
||||||
|
echo "report=true" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "report=false" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: '📝 Post report'
|
||||||
|
if: env.report == 'true'
|
||||||
|
uses: thollander/actions-comment-pull-request@v2
|
||||||
|
with:
|
||||||
|
filePath: ./stats.txt
|
||||||
|
|
||||||
stable-release:
|
stable-release:
|
||||||
needs: build-firmware
|
needs: build-firmware
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|||||||
1
.github/workflows/requirements.txt
vendored
1
.github/workflows/requirements.txt
vendored
@ -1,3 +1,4 @@
|
|||||||
flake8==6.0.0
|
flake8==6.0.0
|
||||||
pytest==7.4.0
|
pytest==7.4.0
|
||||||
ethos-u-vela==3.12.0
|
ethos-u-vela==3.12.0
|
||||||
|
tabulate==0.9.0
|
||||||
|
|||||||
108
tools/gen_stats.py
Normal file
108
tools/gen_stats.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# This file is part of the OpenMV project.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
# Copyright (c) 2024 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
#
|
||||||
|
# This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import zipfile
|
||||||
|
import subprocess
|
||||||
|
from operator import itemgetter
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
|
|
||||||
|
def extract_zip_files(directory):
|
||||||
|
for item in os.listdir(directory):
|
||||||
|
if item.endswith(".zip"):
|
||||||
|
with zipfile.ZipFile(os.path.join(directory, item), "r") as zip_ref:
|
||||||
|
name = os.path.splitext(item.strip())[0].split("firmware_")[1]
|
||||||
|
extract_directory = os.path.join(directory, name)
|
||||||
|
if not os.path.exists(extract_directory):
|
||||||
|
os.makedirs(extract_directory)
|
||||||
|
zip_ref.extractall(extract_directory)
|
||||||
|
|
||||||
|
|
||||||
|
def find_elf_files(directory):
|
||||||
|
elf_files = []
|
||||||
|
for root, _, files in os.walk(directory):
|
||||||
|
for file in files:
|
||||||
|
if file.endswith(".elf"):
|
||||||
|
elf_files.append(os.path.join(root, file))
|
||||||
|
return elf_files
|
||||||
|
|
||||||
|
|
||||||
|
def get_relative_path(full_path, base_dir):
|
||||||
|
return os.path.relpath(full_path, base_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def get_firmware_sizes(path):
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(["arm-none-eabi-size", path], text=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(e.stderr, file=sys.stderr)
|
||||||
|
raise e
|
||||||
|
return [int(s) for s in output.split() if s.isdigit()][0:3]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
new_firmware_dir = "new_firmware"
|
||||||
|
old_firmware_dir = "old_firmware"
|
||||||
|
|
||||||
|
# Extract zip files
|
||||||
|
extract_zip_files(old_firmware_dir)
|
||||||
|
extract_zip_files(new_firmware_dir)
|
||||||
|
|
||||||
|
# Find ELF files and their relative paths
|
||||||
|
new_elf_files = find_elf_files(new_firmware_dir)
|
||||||
|
old_elf_files = find_elf_files(old_firmware_dir)
|
||||||
|
|
||||||
|
new_elf_paths = { get_relative_path(path, new_firmware_dir): path for path in new_elf_files }
|
||||||
|
old_elf_paths = { get_relative_path(path, old_firmware_dir): path for path in old_elf_files }
|
||||||
|
|
||||||
|
# Find common ELF files based on relative paths
|
||||||
|
common_paths = set(new_elf_paths.keys()).intersection(old_elf_paths.keys())
|
||||||
|
# List of common ELF files with their paths
|
||||||
|
common_elf_files = [(new_elf_paths[rel_path], old_elf_paths[rel_path]) for rel_path in common_paths]
|
||||||
|
common_elf_files = sorted(common_elf_files, key=lambda x: x[0].split(os.sep)[1])
|
||||||
|
|
||||||
|
# Prepare the header
|
||||||
|
headers = ["Firmware", "Text Diff", "Data Diff", "BSS Diff"]
|
||||||
|
|
||||||
|
# Prepare the data
|
||||||
|
data = []
|
||||||
|
for new_path, old_path in common_elf_files:
|
||||||
|
new_sizes = get_firmware_sizes(new_path)
|
||||||
|
old_sizes = get_firmware_sizes(old_path)
|
||||||
|
|
||||||
|
text_diff = new_sizes[0] - old_sizes[0]
|
||||||
|
data_diff = new_sizes[1] - old_sizes[1]
|
||||||
|
bss_diff = new_sizes[2] - old_sizes[2]
|
||||||
|
|
||||||
|
if not any([text_diff, data_diff, bss_diff]):
|
||||||
|
continue
|
||||||
|
|
||||||
|
text_percent = (((new_sizes[0] - old_sizes[0]) / old_sizes[0]) * 100 if old_sizes[0] != 0 else 0)
|
||||||
|
data_percent = (((new_sizes[1] - old_sizes[1]) / old_sizes[1]) * 100 if old_sizes[1] != 0 else 0)
|
||||||
|
bss_percent = (((new_sizes[2] - old_sizes[2]) / old_sizes[2]) * 100 if old_sizes[2] != 0 else 0)
|
||||||
|
|
||||||
|
text_emoji = "🔺" if text_percent > 0 else "🔻" if text_percent < 0 else "➖"
|
||||||
|
data_emoji = "🔺" if data_percent > 0 else "🔻" if data_percent < 0 else "➖"
|
||||||
|
bss_emoji = "🔺" if bss_percent > 0 else "🔻" if bss_percent < 0 else "➖"
|
||||||
|
|
||||||
|
text_diff_str = f"{text_emoji}{text_percent:.2f}% ({text_diff:+})"
|
||||||
|
data_diff_str = f"{data_emoji}{data_percent:.2f}% ({data_diff:+})"
|
||||||
|
bss_diff_str = f"{bss_emoji}{bss_percent:.2f}% ({bss_diff:+})"
|
||||||
|
|
||||||
|
board_name = "_".join(old_path.split(os.sep)[1].split("_")[0:3])
|
||||||
|
file_name = os.sep.join([board_name, old_path.split(os.sep)[-1]])
|
||||||
|
data.append([file_name, text_diff_str, data_diff_str, bss_diff_str])
|
||||||
|
|
||||||
|
if data:
|
||||||
|
# Print the table
|
||||||
|
print("Code Size Report:")
|
||||||
|
print(tabulate(data, headers=headers, tablefmt="github", colalign=("left", "left", "left", "left")))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user