mirror of
				https://github.com/esp8266/Arduino.git
				synced 2025-11-03 14:33:37 +03:00 
			
		
		
		
	Table output for segment size script (#8551)
* Table output for segment size script Also include maximum aka total for every segment key Re-format the file and clean-up the resulting data dict * revert to line output * used, percentage * unicodes * shorter desc, headers
This commit is contained in:
		
							
								
								
									
										192
									
								
								tools/sizes.py
									
									
									
									
									
								
							
							
						
						
									
										192
									
								
								tools/sizes.py
									
									
									
									
									
								
							@@ -17,74 +17,156 @@
 | 
				
			|||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
					# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from __future__ import print_function
 | 
					 | 
				
			||||||
import argparse
 | 
					import argparse
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_segment_hints(iram):
 | 
					 | 
				
			||||||
    hints = {}
 | 
					 | 
				
			||||||
    hints['ICACHE'] = '          - flash instruction cache'
 | 
					 | 
				
			||||||
    hints['IROM'] = '         - code in flash         (default or ICACHE_FLASH_ATTR)'
 | 
					 | 
				
			||||||
    hints['IRAM'] = '  / ' + str(iram) + ' - code in IRAM          (IRAM_ATTR, ISRs...)'
 | 
					 | 
				
			||||||
    hints['DATA'] = ')         - initialized variables (global, static) in RAM/HEAP'
 | 
					 | 
				
			||||||
    hints['RODATA'] = ') / 81920 - constants             (global, static) in RAM/HEAP'
 | 
					 | 
				
			||||||
    hints['BSS'] = ')         - zeroed variables      (global, static) in RAM/HEAP'
 | 
					 | 
				
			||||||
    return hints
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_segment_sizes(elf, path):
 | 
					def get_segment_sizes(elf, path, mmu):
 | 
				
			||||||
    sizes = {}
 | 
					    iram_size = 0
 | 
				
			||||||
    sizes['ICACHE'] = 0
 | 
					    iheap_size = 0
 | 
				
			||||||
    sizes['IROM'] = 0
 | 
					    icache_size = 32168
 | 
				
			||||||
    sizes['IRAM'] = 0
 | 
					
 | 
				
			||||||
    sizes['DATA'] = 0
 | 
					    for line in mmu.split():
 | 
				
			||||||
    sizes['RODATA'] = 0
 | 
					        words = line.split("=")
 | 
				
			||||||
    sizes['BSS'] = 0
 | 
					        if line.startswith("-DMMU_IRAM_SIZE"):
 | 
				
			||||||
    p = subprocess.Popen([path + "/xtensa-lx106-elf-size", '-A', elf], stdout=subprocess.PIPE, universal_newlines=True )
 | 
					            iram_size = int(words[1], 16)
 | 
				
			||||||
    lines = p.stdout.readlines()
 | 
					        elif line.startswith("-DMMU_ICACHE_SIZE"):
 | 
				
			||||||
 | 
					            icache_size = int(words[1], 16)
 | 
				
			||||||
 | 
					        elif line.startswith("-DMMU_SEC_HEAP_SIZE"):
 | 
				
			||||||
 | 
					            iheap_size = int(words[1], 16)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sizes = [
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					            "Variables and constants in RAM (global, static)",
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "DATA": 0,
 | 
				
			||||||
 | 
					                    "RODATA": 0,
 | 
				
			||||||
 | 
					                    "BSS": 0,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                80192,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					            "Instruction RAM (IRAM_ATTR, ICACHE_RAM_ATTR)",
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "ICACHE": icache_size,
 | 
				
			||||||
 | 
					                    "IHEAP": iheap_size,
 | 
				
			||||||
 | 
					                    "IRAM": 0,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                65536,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        ["Code in flash (default, ICACHE_FLASH_ATTR)", [{"IROM": 0}, 1048576]],
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    section_mapping = (
 | 
				
			||||||
 | 
					        (".irom0.text", "IROM"),
 | 
				
			||||||
 | 
					        (".text", "IRAM"),
 | 
				
			||||||
 | 
					        (".data", "DATA"),
 | 
				
			||||||
 | 
					        (".rodata", "RODATA"),
 | 
				
			||||||
 | 
					        (".bss", "BSS"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cmd = [os.path.join(path, "xtensa-lx106-elf-size"), "-A", elf]
 | 
				
			||||||
 | 
					    with subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) as proc:
 | 
				
			||||||
 | 
					        lines = proc.stdout.readlines()
 | 
				
			||||||
        for line in lines:
 | 
					        for line in lines:
 | 
				
			||||||
            words = line.split()
 | 
					            words = line.split()
 | 
				
			||||||
        if line.startswith('.irom0.text'):
 | 
					            for section, target in section_mapping:
 | 
				
			||||||
            sizes['IROM'] = sizes['IROM'] + int(words[1])
 | 
					                if not line.startswith(section):
 | 
				
			||||||
        elif line.startswith('.text'): # Gets .text and .text1
 | 
					                    continue
 | 
				
			||||||
            sizes['IRAM'] = sizes['IRAM'] + int(words[1])
 | 
					                for group, (segments, total) in sizes:
 | 
				
			||||||
        elif line.startswith('.data'): # Gets .text and .text1
 | 
					                    if target in segments:
 | 
				
			||||||
            sizes['DATA'] = sizes['DATA'] + int(words[1])
 | 
					                        segments[target] += int(words[1])
 | 
				
			||||||
        elif line.startswith('.rodata'): # Gets .text and .text1
 | 
					                        assert segments[target] <= total
 | 
				
			||||||
            sizes['RODATA'] = sizes['RODATA'] + int(words[1])
 | 
					
 | 
				
			||||||
        elif line.startswith('.bss'): # Gets .text and .text1
 | 
					 | 
				
			||||||
            sizes['BSS'] = sizes['BSS'] + int(words[1])
 | 
					 | 
				
			||||||
    return sizes
 | 
					    return sizes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_mmu_sizes(mmu, sizes):
 | 
					
 | 
				
			||||||
    iram = 0x8000
 | 
					def percentage(lhs, rhs):
 | 
				
			||||||
    sizes['ICACHE'] = 0x8000
 | 
					    return "{}%".format(int(100.0 * float(lhs) / float(rhs)))
 | 
				
			||||||
    lines = mmu.split(' ')
 | 
					
 | 
				
			||||||
    for line in lines:
 | 
					
 | 
				
			||||||
        words = line.split('=')
 | 
					HINTS = {
 | 
				
			||||||
        if line.startswith('-DMMU_IRAM_SIZE'):
 | 
					    "ICACHE": "reserved space for flash instruction cache",
 | 
				
			||||||
            iram = int(words[1], 16)
 | 
					    "IRAM": "code in IRAM",
 | 
				
			||||||
        elif line.startswith('-DMMU_ICACHE_SIZE'):
 | 
					    "IHEAP": "secondary heap space",
 | 
				
			||||||
            sizes['ICACHE'] = int(words[1], 16)
 | 
					    "IROM": "code in flash",
 | 
				
			||||||
    return [iram, sizes]
 | 
					    "DATA": "initialized variables",
 | 
				
			||||||
 | 
					    "RODATA": "constants",
 | 
				
			||||||
 | 
					    "BSS": "zeroed variables",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def safe_prefix(n, length):
 | 
				
			||||||
 | 
					    if n == length:
 | 
				
			||||||
 | 
					        return "`--"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return "|--"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def prefix(n, length):
 | 
				
			||||||
 | 
					    if n == length:
 | 
				
			||||||
 | 
					        return "└──"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return "├──"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def filter_segments(segments):
 | 
				
			||||||
 | 
					    used = 0
 | 
				
			||||||
 | 
					    number = 0
 | 
				
			||||||
 | 
					    available = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (segment, size) in segments.items():
 | 
				
			||||||
 | 
					        if not size:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        used += size
 | 
				
			||||||
 | 
					        number += 1
 | 
				
			||||||
 | 
					        available.append((number, segment, size))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (number, used, available)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main():
 | 
					def main():
 | 
				
			||||||
    parser = argparse.ArgumentParser(description='Report the different segment sizes of a compiled ELF file')
 | 
					    parser = argparse.ArgumentParser(
 | 
				
			||||||
    parser.add_argument('-e', '--elf', action='store', required=True, help='Path to the Arduino sketch ELF')
 | 
					        description="Report the different segment sizes of a compiled ELF file"
 | 
				
			||||||
    parser.add_argument('-p', '--path', action='store', required=True, help='Path to Xtensa toolchain binaries')
 | 
					    )
 | 
				
			||||||
    parser.add_argument('-i', '--mmu', action='store', required=False, help='MMU build options')
 | 
					    parser.add_argument(
 | 
				
			||||||
 | 
					        "-e",
 | 
				
			||||||
 | 
					        "--elf",
 | 
				
			||||||
 | 
					        action="store",
 | 
				
			||||||
 | 
					        required=True,
 | 
				
			||||||
 | 
					        help="Path to the Arduino sketch ELF",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser.add_argument(
 | 
				
			||||||
 | 
					        "-p",
 | 
				
			||||||
 | 
					        "--path",
 | 
				
			||||||
 | 
					        action="store",
 | 
				
			||||||
 | 
					        required=True,
 | 
				
			||||||
 | 
					        help="Path to Xtensa toolchain binaries",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser.add_argument(
 | 
				
			||||||
 | 
					        "-i", "--mmu", action="store", required=False, help="MMU build options"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    args = parser.parse_args()
 | 
					    args = parser.parse_args()
 | 
				
			||||||
    sizes = get_segment_sizes(args.elf, args.path)
 | 
					    sizes = get_segment_sizes(args.elf, args.path, args.mmu)
 | 
				
			||||||
    [iram, sizes] = get_mmu_sizes(args.mmu, sizes)
 | 
					 | 
				
			||||||
    hints = get_segment_hints(iram)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sys.stderr.write("Executable segment sizes:" + os.linesep)
 | 
					    for group, (segments, total) in sizes:
 | 
				
			||||||
    for k in sizes.keys():
 | 
					        number, used, segments = filter_segments(segments)
 | 
				
			||||||
        sys.stderr.write("%-7s: %-5d %s %s" % (k, sizes[k], hints[k], os.linesep))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0
 | 
					        print(f". {group:<8}, used {used} / {total} bytes ({percentage(used, total)})")
 | 
				
			||||||
 | 
					        print("|   SEGMENT  BYTES    DESCRIPTION")
 | 
				
			||||||
 | 
					        for n, segment, size in segments:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                print(f"{prefix(n, number)} ", end="")
 | 
				
			||||||
 | 
					            except UnicodeEncodeError:
 | 
				
			||||||
 | 
					                print(f"{safe_prefix(n, number)} ", end="")
 | 
				
			||||||
 | 
					            print(f"{segment:<8} {size:<8} {HINTS[segment]:<16}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					
 | 
				
			||||||
    sys.exit(main())
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user