code_relocation: Cache list of obj files

As part of relocation, this script matches each source file to its
corresponding object file. This matching is done inside of get_obj_filename
which is called once per source file.

get_obj_filename traverses the entire build directory on every invocation.
This is unnecessary since built object files don't change. On a
sufficiently large project (like mine), this script takes over a minute and
the majority of that time is spent needlessly traversing the build
directory again and again.

Caching the list of object files enables this script to run in less than a
second.

I tested by building my project (which enables the relocation script) and
comparing memory breakdown before / after.

Signed-off-by: Galen Krulce <gkrulce@meta.com>
This commit is contained in:
Galen Krulce 2025-02-24 21:27:57 -08:00 committed by Benjamin Cabé
commit 5ae9f44825

View file

@ -44,7 +44,6 @@ this will place data and bss inside SRAM2.
import sys
import argparse
import os
import glob
import re
import warnings
@ -491,19 +490,18 @@ def parse_args():
help="Verbose Output")
args = parser.parse_args()
def gen_all_obj_files(searchpath):
return list(Path(searchpath).rglob('*.o')) + list(Path(searchpath).rglob('*.obj'))
# return the absolute path for the object file.
def get_obj_filename(searchpath, filename):
def get_obj_filename(all_obj_files, filename):
# get the object file name which is almost always pended with .obj
obj_filename = filename.split("/")[-1] + ".obj"
for dirpath, _, files in os.walk(searchpath):
for filename1 in files:
if filename1 == obj_filename:
if filename.split("/")[-2] in dirpath.split("/")[-1]:
fullname = os.path.join(dirpath, filename1)
return fullname
for obj_file in all_obj_files:
if obj_file.name == obj_filename:
if filename.split("/")[-2] in obj_file.parent.name:
return str(obj_file)
# Extracts all possible components for the input string:
# <mem_region>[\ :program_header]:<flag_1>[;<flag_2>...]:<file_1>[;<file_2>...][,filter]
@ -587,6 +585,7 @@ def main():
mpu_align = {}
parse_args()
searchpath = args.directory
all_obj_files = gen_all_obj_files(searchpath)
linker_file = args.output
sram_data_linker_file = args.output_sram_data
sram_bss_linker_file = args.output_sram_bss
@ -602,7 +601,7 @@ def main():
full_list_of_sections: 'dict[SectionKind, list[OutputSection]]' = defaultdict(list)
for filename, symbol_filter in files:
obj_filename = get_obj_filename(searchpath, filename)
obj_filename = get_obj_filename(all_obj_files, filename)
# the obj file wasn't found. Probably not compiled.
if not obj_filename:
continue