2021-10-07 00:43:44 -03:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
'''
|
|
|
|
Wrapper around elf_diff (https://github.com/noseglasses/elf_diff)
|
|
|
|
to create a html report comparing an ArduPilot build across two
|
|
|
|
branches
|
|
|
|
|
|
|
|
pip3 install --user elf_diff weasyprint
|
|
|
|
|
|
|
|
AP_FLAKE8_CLEAN
|
|
|
|
|
2021-11-04 17:33:27 -03:00
|
|
|
How to use?
|
|
|
|
Starting in the ardupilot directory.
|
|
|
|
~/ardupilot $ python Tools/scripts/size_compare_branches.py --branch=[PR_BRANCH_NAME] --vehicle=copter
|
|
|
|
|
|
|
|
Output is placed into ../ELF_DIFF_[VEHICLE_NAME]
|
2021-10-07 00:43:44 -03:00
|
|
|
'''
|
|
|
|
|
|
|
|
import optparse
|
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
import string
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
|
|
|
|
if sys.version_info[0] < 3:
|
|
|
|
running_python3 = False
|
|
|
|
else:
|
|
|
|
running_python3 = True
|
|
|
|
|
|
|
|
|
|
|
|
class SizeCompareBranches(object):
|
|
|
|
'''script to build and compare branches using elf_diff'''
|
|
|
|
|
2022-08-11 22:03:30 -03:00
|
|
|
def __init__(self,
|
|
|
|
branch=None,
|
|
|
|
master_branch="master",
|
|
|
|
board="MatekF405-Wing",
|
|
|
|
vehicle="plane",
|
|
|
|
bin_dir=None,
|
|
|
|
pdf_file=None,
|
|
|
|
extra_hwdef=None):
|
2021-10-07 00:43:44 -03:00
|
|
|
if branch is None:
|
|
|
|
raise Exception("branch required") # FIXME: narrow exception
|
|
|
|
self.master_branch = master_branch
|
|
|
|
self.branch = branch
|
|
|
|
self.board = board
|
2021-11-04 00:15:24 -03:00
|
|
|
self.vehicle = vehicle
|
2021-10-07 00:43:44 -03:00
|
|
|
self.bin_dir = bin_dir
|
|
|
|
self.pdf_file = pdf_file
|
2022-08-11 22:03:30 -03:00
|
|
|
self.extra_hwdef = extra_hwdef
|
2021-10-07 00:43:44 -03:00
|
|
|
|
|
|
|
if self.bin_dir is None:
|
|
|
|
self.bin_dir = self.find_bin_dir()
|
|
|
|
|
|
|
|
def find_bin_dir(self):
|
|
|
|
'''attempt to find where the arm-none-eabi tools are'''
|
|
|
|
binary = shutil.which("arm-none-eabi-g++")
|
|
|
|
if binary is None:
|
|
|
|
raise Exception("No arm-none-eabi-g++?")
|
|
|
|
return os.path.dirname(binary)
|
|
|
|
|
|
|
|
# vast amounts of stuff copied into here from build_binaries.py
|
|
|
|
|
|
|
|
def run_program(self, prefix, cmd_list, show_output=True, env=None):
|
|
|
|
if show_output:
|
|
|
|
self.progress("Running (%s)" % " ".join(cmd_list))
|
|
|
|
p = subprocess.Popen(cmd_list, bufsize=1, stdin=None,
|
|
|
|
stdout=subprocess.PIPE, close_fds=True,
|
|
|
|
stderr=subprocess.STDOUT, env=env)
|
|
|
|
output = ""
|
|
|
|
while True:
|
|
|
|
x = p.stdout.readline()
|
|
|
|
if len(x) == 0:
|
|
|
|
returncode = os.waitpid(p.pid, 0)
|
|
|
|
if returncode:
|
|
|
|
break
|
|
|
|
# select not available on Windows... probably...
|
|
|
|
time.sleep(0.1)
|
|
|
|
continue
|
|
|
|
if running_python3:
|
|
|
|
x = bytearray(x)
|
|
|
|
x = filter(lambda x : chr(x) in string.printable, x)
|
|
|
|
x = "".join([chr(c) for c in x])
|
|
|
|
output += x
|
|
|
|
x = x.rstrip()
|
|
|
|
if show_output:
|
|
|
|
print("%s: %s" % (prefix, x))
|
|
|
|
(_, status) = returncode
|
|
|
|
if status != 0 and show_output:
|
|
|
|
self.progress("Process failed (%s)" %
|
|
|
|
str(returncode))
|
|
|
|
raise subprocess.CalledProcessError(
|
|
|
|
returncode, cmd_list)
|
|
|
|
return output
|
|
|
|
|
|
|
|
def run_git(self, args):
|
|
|
|
'''run git with args git_args; returns git's output'''
|
|
|
|
cmd_list = ["git"]
|
|
|
|
cmd_list.extend(args)
|
|
|
|
return self.run_program("SCB-GIT", cmd_list)
|
|
|
|
|
|
|
|
def run_waf(self, args, compiler=None):
|
|
|
|
if os.path.exists("waf"):
|
|
|
|
waf = "./waf"
|
|
|
|
else:
|
|
|
|
waf = os.path.join(".", "modules", "waf", "waf-light")
|
|
|
|
cmd_list = [waf]
|
|
|
|
cmd_list.extend(args)
|
|
|
|
env = None
|
|
|
|
if compiler is not None:
|
|
|
|
# default to $HOME/arm-gcc, but allow for any path with AP_GCC_HOME environment variable
|
|
|
|
gcc_home = os.environ.get("AP_GCC_HOME", os.path.join(os.environ["HOME"], "arm-gcc"))
|
|
|
|
gcc_path = os.path.join(gcc_home, compiler, "bin")
|
|
|
|
if os.path.exists(gcc_path):
|
|
|
|
# setup PATH to point at the right compiler, and setup to use ccache
|
|
|
|
env = os.environ.copy()
|
|
|
|
env["PATH"] = gcc_path + ":" + env["PATH"]
|
|
|
|
env["CC"] = "ccache arm-none-eabi-gcc"
|
|
|
|
env["CXX"] = "ccache arm-none-eabi-g++"
|
|
|
|
else:
|
|
|
|
raise Exception("BB-WAF: Missing compiler %s" % gcc_path)
|
|
|
|
self.run_program("SCB-WAF", cmd_list, env=env)
|
|
|
|
|
|
|
|
def progress(self, string):
|
|
|
|
'''pretty-print progress'''
|
|
|
|
print("SCB: %s" % string)
|
|
|
|
|
2021-11-04 00:15:24 -03:00
|
|
|
def build_branch_into_dir(self, board, branch, vehicle, outdir):
|
2021-10-07 00:43:44 -03:00
|
|
|
self.run_git(["checkout", branch])
|
|
|
|
self.run_git(["submodule", "update", "--recursive"])
|
|
|
|
shutil.rmtree("build", ignore_errors=True)
|
2022-08-11 22:03:30 -03:00
|
|
|
waf_configure_args = ["configure", "--board", board]
|
|
|
|
if self.extra_hwdef is not None:
|
|
|
|
waf_configure_args.extend(["--extra-hwdef", self.extra_hwdef])
|
|
|
|
self.run_waf(waf_configure_args)
|
2021-11-04 00:15:24 -03:00
|
|
|
self.run_waf([vehicle])
|
2021-10-07 00:43:44 -03:00
|
|
|
shutil.rmtree(outdir, ignore_errors=True)
|
|
|
|
shutil.copytree("build", outdir)
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
outdir_1 = "/tmp/out-master"
|
|
|
|
outdir_2 = "/tmp/out-branch"
|
|
|
|
|
|
|
|
self.progress("Building branch 1")
|
2021-11-04 00:15:24 -03:00
|
|
|
self.build_branch_into_dir(self.board, self.master_branch, self.vehicle, outdir_1)
|
2021-10-07 00:43:44 -03:00
|
|
|
|
|
|
|
self.progress("Building branch 2")
|
2021-11-04 00:15:24 -03:00
|
|
|
self.build_branch_into_dir(self.board, self.branch, self.vehicle, outdir_2)
|
2021-10-07 00:43:44 -03:00
|
|
|
|
|
|
|
self.progress("Starting compare (~10 minutes!)")
|
|
|
|
|
2021-11-04 00:15:24 -03:00
|
|
|
# map from vehicle names to binary names
|
|
|
|
vehicle_map = {
|
|
|
|
"rover" : "ardurover",
|
|
|
|
"copter" : "arducopter",
|
|
|
|
"plane" : "arduplane",
|
|
|
|
"sub" : "ardusub",
|
|
|
|
"heli" : "arducopter-heli",
|
|
|
|
"blimp" : "blimp",
|
2022-03-18 22:15:41 -03:00
|
|
|
"antennatracker" : "antennatracker",
|
2022-04-10 06:01:20 -03:00
|
|
|
"AP_Periph" : "AP_Periph",
|
2021-11-04 00:15:24 -03:00
|
|
|
}
|
|
|
|
if self.vehicle in vehicle_map:
|
|
|
|
binary_filename = vehicle_map[self.vehicle]
|
|
|
|
else:
|
2022-03-18 22:15:41 -03:00
|
|
|
raise Exception("Vehicle name (%s) incorrect" % (self.vehicle))
|
2021-10-07 00:43:44 -03:00
|
|
|
|
|
|
|
elf_diff_commandline = [
|
|
|
|
"time",
|
|
|
|
"python3",
|
|
|
|
"-m", "elf_diff",
|
|
|
|
"--bin_dir", self.bin_dir,
|
|
|
|
'--bin_prefix=arm-none-eabi-',
|
|
|
|
"--old_alias", "%s %s" % (self.master_branch, binary_filename),
|
|
|
|
"--new_alias", "%s %s" % (self.branch, binary_filename),
|
2021-11-04 17:33:27 -03:00
|
|
|
"--html_dir", "../ELF_DIFF_%s" % (self.vehicle),
|
2021-10-07 00:43:44 -03:00
|
|
|
os.path.join(outdir_1, self.board, "bin", binary_filename),
|
|
|
|
os.path.join(outdir_2, self.board, "bin", binary_filename)
|
|
|
|
]
|
|
|
|
|
|
|
|
# if self.pdf_file is not None:
|
|
|
|
# elf_diff_commandline.extend(["--pdf_file", self.pdf_file])
|
|
|
|
|
|
|
|
self.run_program("SCB", elf_diff_commandline)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
parser = optparse.OptionParser("size_compare_branches.py")
|
|
|
|
parser.add_option("",
|
|
|
|
"--master-branch",
|
|
|
|
type="string",
|
|
|
|
default="master",
|
|
|
|
help="master branch to use")
|
|
|
|
parser.add_option("",
|
|
|
|
"--branch",
|
|
|
|
type="string",
|
|
|
|
default=None,
|
|
|
|
help="branch to compare")
|
2021-11-04 00:15:24 -03:00
|
|
|
parser.add_option("",
|
|
|
|
"--vehicle",
|
|
|
|
type="string",
|
|
|
|
default="plane",
|
|
|
|
help="vehicle to build for")
|
2021-10-07 00:43:44 -03:00
|
|
|
parser.add_option("",
|
|
|
|
"--board",
|
|
|
|
type="string",
|
|
|
|
default="MatekF405-Wing",
|
|
|
|
help="board to build for")
|
2022-08-11 22:03:30 -03:00
|
|
|
parser.add_option("",
|
|
|
|
"--extra-hwdef",
|
|
|
|
type="string",
|
|
|
|
default=None,
|
|
|
|
help="configure with this extra hwdef file")
|
2021-10-07 00:43:44 -03:00
|
|
|
# parser.add_option("",
|
|
|
|
# "--pdf_file",
|
|
|
|
# type="string",
|
|
|
|
# default=None,
|
|
|
|
# help="output PDF to this file")
|
|
|
|
cmd_opts, cmd_args = parser.parse_args()
|
|
|
|
|
|
|
|
# we require --branch rather than taking a fixed-position argument
|
|
|
|
# so that in the future we can assume the user wants to test the
|
|
|
|
# currently checked out branch. That requires a bit of work...
|
|
|
|
if cmd_opts.branch is None:
|
|
|
|
raise Exception("--branch must be supplied") # FIXME: narrow exception
|
|
|
|
|
|
|
|
x = SizeCompareBranches(
|
|
|
|
branch=cmd_opts.branch,
|
|
|
|
master_branch=cmd_opts.master_branch,
|
|
|
|
board=cmd_opts.board,
|
2021-11-04 00:15:24 -03:00
|
|
|
vehicle=cmd_opts.vehicle,
|
2022-08-11 22:03:30 -03:00
|
|
|
extra_hwdef=cmd_opts.extra_hwdef,
|
2021-10-07 00:43:44 -03:00
|
|
|
# pdf_file=cmd_opts.pdf_file
|
|
|
|
)
|
|
|
|
x.run()
|