diff options
| author | hathach <[email protected]> | 2025-12-02 12:50:31 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2025-12-02 13:01:49 +0700 |
| commit | c859744784cc396ae0993a16a1935b10fbd9b797 (patch) | |
| tree | 6f7c3487dacad035922f1f3c18e5411dd39003da | |
| parent | a337a6d337c0cdd50981ba2040aee99966ae3152 (diff) | |
adding metrics for computing average compiled size
| -rw-r--r-- | examples/device/CMakeLists.txt | 63 | ||||
| -rw-r--r-- | examples/dual/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | examples/host/CMakeLists.txt | 20 | ||||
| -rw-r--r-- | hw/bsp/family_support.cmake | 6 | ||||
| -rwxr-xr-x | tools/build.py | 4 | ||||
| -rwxr-xr-x | tools/get_deps.py | 2 | ||||
| -rw-r--r-- | tools/metrics.py | 134 |
7 files changed, 193 insertions, 46 deletions
diff --git a/examples/device/CMakeLists.txt b/examples/device/CMakeLists.txt index eb625ea51..660df67cb 100644 --- a/examples/device/CMakeLists.txt +++ b/examples/device/CMakeLists.txt @@ -6,31 +6,38 @@ project(tinyusb_device_examples C CXX ASM) family_initialize_project(tinyusb_device_examples ${CMAKE_CURRENT_LIST_DIR}) # family_add_subdirectory will filter what to actually add based on selected FAMILY -family_add_subdirectory(audio_4_channel_mic) -family_add_subdirectory(audio_test) -family_add_subdirectory(audio_4_channel_mic_freertos) -family_add_subdirectory(audio_test_freertos) -family_add_subdirectory(audio_test_multi_rate) -family_add_subdirectory(board_test) -family_add_subdirectory(cdc_dual_ports) -family_add_subdirectory(cdc_msc) -family_add_subdirectory(cdc_msc_freertos) -family_add_subdirectory(cdc_uac2) -family_add_subdirectory(dfu) -family_add_subdirectory(dfu_runtime) -family_add_subdirectory(dynamic_configuration) -family_add_subdirectory(hid_boot_interface) -family_add_subdirectory(hid_composite) -family_add_subdirectory(hid_composite_freertos) -family_add_subdirectory(hid_generic_inout) -family_add_subdirectory(hid_multiple_interface) -family_add_subdirectory(midi_test) -family_add_subdirectory(msc_dual_lun) -family_add_subdirectory(mtp) -family_add_subdirectory(net_lwip_webserver) -family_add_subdirectory(uac2_headset) -family_add_subdirectory(uac2_speaker_fb) -family_add_subdirectory(usbtmc) -family_add_subdirectory(video_capture) -family_add_subdirectory(video_capture_2ch) -family_add_subdirectory(webusb_serial) +set(EXAMPLE_LIST + audio_4_channel_mic + audio_4_channel_mic_freertos + audio_test + audio_test_freertos + audio_test_multi_rate + board_test + cdc_dual_ports + cdc_msc + cdc_msc_freertos + cdc_uac2 + dfu + dfu_runtime + dynamic_configuration + hid_boot_interface + hid_composite + hid_composite_freertos + hid_generic_inout + hid_multiple_interface + midi_test + midi_test_freertos + msc_dual_lun + mtp + net_lwip_webserver + uac2_headset + uac2_speaker_fb + usbtmc + video_capture + video_capture_2ch + webusb_serial + ) + +foreach (example ${EXAMPLE_LIST}) + family_add_subdirectory(${example}) +endforeach () diff --git a/examples/dual/CMakeLists.txt b/examples/dual/CMakeLists.txt index c5e3ffce4..4978f1fab 100644 --- a/examples/dual/CMakeLists.txt +++ b/examples/dual/CMakeLists.txt @@ -9,6 +9,12 @@ if (FAMILY STREQUAL "rp2040" AND NOT TARGET tinyusb_pico_pio_usb) message("Skipping dual host/device mode examples as Pico-PIO-USB is not available") else () # family_add_subdirectory will filter what to actually add based on selected FAMILY - family_add_subdirectory(host_hid_to_device_cdc) - family_add_subdirectory(host_info_to_device_cdc) + set(EXAMPLE_LIST + host_hid_to_device_cdc + host_info_to_device_cdc + ) + + foreach (example ${EXAMPLE_LIST}) + family_add_subdirectory(${example}) + endforeach () endif () diff --git a/examples/host/CMakeLists.txt b/examples/host/CMakeLists.txt index 2783dd84e..f8e0ce692 100644 --- a/examples/host/CMakeLists.txt +++ b/examples/host/CMakeLists.txt @@ -6,10 +6,16 @@ project(tinyusb_host_examples C CXX ASM) family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR}) # family_add_subdirectory will filter what to actually add based on selected FAMILY -family_add_subdirectory(bare_api) -family_add_subdirectory(cdc_msc_hid) -family_add_subdirectory(cdc_msc_hid_freertos) -family_add_subdirectory(device_info) -family_add_subdirectory(hid_controller) -family_add_subdirectory(midi_rx) -family_add_subdirectory(msc_file_explorer) +set(EXAMPLE_LIST + bare_api + cdc_msc_hid + cdc_msc_hid_freertos + device_info + hid_controller + midi_rx + msc_file_explorer + ) + +foreach (example ${EXAMPLE_LIST}) + family_add_subdirectory(${example}) +endforeach () diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 1f91d0910..e7dfc19c8 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -231,12 +231,6 @@ function(family_add_linkermap TARGET) separate_arguments(LINKERMAP_OPTION_LIST UNIX_COMMAND ${LINKERMAP_OPTION}) endif () - if (ARGC GREATER 1) - separate_arguments(ARG_OPTION_LIST UNIX_COMMAND ${ARGV1}) - list(APPEND LINKERMAP_OPTION_LIST ${ARG_OPTION_LIST}) - endif () - - # target add_custom_target(${TARGET}-linkermap COMMAND python ${LINKERMAP_PY} -j -m ${LINKERMAP_OPTION_LIST} $<TARGET_FILE:${TARGET}>.map VERBATIM diff --git a/tools/build.py b/tools/build.py index 5328a987f..692853297 100755 --- a/tools/build.py +++ b/tools/build.py @@ -113,8 +113,8 @@ def cmake_board(board, build_args, build_flags_on): else: rcmd = run_cmd([ 'cmake', 'examples', '-B', build_dir, '-GNinja', - f'-DBOARD={board}', '-DCMAKE_BUILD_TYPE=MinSizeRel', - '-DLINKERMAP_OPTION=-q -f tinyusb/src', *build_args, *build_flags + f'-DBOARD={board}', '-DCMAKE_BUILD_TYPE=MinSizeRel', '-DLINKERMAP_OPTION=-q -f tinyusb/src', + *build_args, *build_flags ]) if rcmd.returncode == 0: cmd = [ diff --git a/tools/get_deps.py b/tools/get_deps.py index 47cc5c7dd..5fb7e022c 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -15,7 +15,7 @@ deps_mandatory = { '159e31b689577dbf69cf0683bbaffbd71fa5ee10', 'all'], 'tools/linkermap': ['https://github.com/hathach/linkermap.git', - '1f47651142646398c7746e109ae0481732aeb564', + 'ac1228d5bbde1e54cb2e17e928662094ae19c51d', 'all'], 'tools/uf2': ['https://github.com/microsoft/uf2.git', 'c594542b2faa01cc33a2b97c9fbebc38549df80a', diff --git a/tools/metrics.py b/tools/metrics.py new file mode 100644 index 000000000..d972d3681 --- /dev/null +++ b/tools/metrics.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +"""Calculate average size from multiple linker map files.""" + +import argparse +import sys +import os + +# Add linkermap module to path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'linkermap')) +import linkermap + + +def combine_maps(map_files, filters=None): + """Combine multiple map files into a list of json_data. + + Args: + map_files: List of paths to linker map files or JSON files + filters: List of path substrings to filter object files (default: []) + + Returns: + all_json_data: Dictionary with mapfiles list and data from each map file + """ + import json + + filters = filters or [] + all_json_data = {"mapfiles": [], "data": []} + + for map_file in map_files: + if not os.path.exists(map_file): + print(f"Warning: {map_file} not found, skipping", file=sys.stderr) + continue + + try: + if map_file.endswith('.json'): + with open(map_file, 'r', encoding='utf-8') as f: + json_data = json.load(f) + # Apply path filters to JSON data + if filters: + filtered_files = [ + f for f in json_data["files"] + if f.get("path") and any(filt in f["path"] for filt in filters) + ] + json_data["files"] = filtered_files + else: + json_data = linkermap.analyze_map(map_file, filters=filters) + all_json_data["mapfiles"].append(map_file) + all_json_data["data"].append(json_data) + except Exception as e: + print(f"Warning: Failed to analyze {map_file}: {e}", file=sys.stderr) + continue + + return all_json_data + + +def compute_avg(all_json_data): + """Compute average sizes from combined json_data. + + Args: + all_json_data: Dictionary with mapfiles and data from combine_maps() + + Returns: + json_average: Dictionary with averaged size data + """ + if not all_json_data["data"]: + return None + + # Collect all sections preserving order + all_sections = [] + for json_data in all_json_data["data"]: + for s in json_data["sections"]: + if s not in all_sections: + all_sections.append(s) + + # Merge files with the same 'file' value and compute averages + file_accumulator = {} # key: file name, value: {"sections": {section: [sizes]}, "totals": [totals]} + + for json_data in all_json_data["data"]: + for f in json_data["files"]: + fname = f["file"] + if fname not in file_accumulator: + file_accumulator[fname] = {"sections": {}, "totals": [], "path": f.get("path")} + file_accumulator[fname]["totals"].append(f["total"]) + for section, size in f["sections"].items(): + if section in file_accumulator[fname]["sections"]: + file_accumulator[fname]["sections"][section].append(size) + else: + file_accumulator[fname]["sections"][section] = [size] + + # Build json_average with averaged values + files_average = [] + for fname, data in file_accumulator.items(): + avg_total = round(sum(data["totals"]) / len(data["totals"])) + avg_sections = {} + for section, sizes in data["sections"].items(): + avg_sections[section] = round(sum(sizes) / len(sizes)) + files_average.append({ + "file": fname, + "path": data["path"], + "sections": avg_sections, + "total": avg_total + }) + + json_average = { + "mapfiles": all_json_data["mapfiles"], + "sections": all_sections, + "files": files_average + } + + return json_average + + +def main(): + parser = argparse.ArgumentParser(description='Calculate average size from linker map files') + parser.add_argument('files', nargs='+', help='Path to map file(s)') + parser.add_argument('-f', '--filter', dest='filters', action='append', default=[], + help='Only include object files whose path contains this substring (can be repeated)') + parser.add_argument('-o', '--out', dest='out', default='metrics', + help='Output path basename for JSON and Markdown files (default: metrics)') + args = parser.parse_args() + + all_json_data = combine_maps(args.files, args.filters) + json_average = compute_avg(all_json_data) + + if json_average is None: + print("No valid map files found", file=sys.stderr) + sys.exit(1) + + linkermap.print_summary(json_average, False) + linkermap.write_json(json_average, args.out + '.json') + linkermap.write_markdown(json_average, args.out + '.md') + + +if __name__ == '__main__': + main() |
