99import re
1010import csv
1111import json
12+ import math
1213from argparse import ArgumentParser
1314from copy import deepcopy
1415from prettytable import PrettyTable
16+ from tools .arm_pack_manager import Cache
1517
1618from utils import argparse_filestring_type , \
1719 argparse_lowercase_hyphen_type , argparse_uppercase_type
@@ -506,7 +508,7 @@ def reduce_depth(self, depth):
506508
507509 export_formats = ["json" , "csv-ci" , "table" ]
508510
509- def generate_output (self , export_format , depth , file_output = None ):
511+ def generate_output (self , export_format , depth , file_output = None , * args ):
510512 """ Generates summary of memory map data
511513
512514 Positional arguments:
@@ -531,8 +533,9 @@ def generate_output(self, export_format, depth, file_output=None):
531533
532534 to_call = {'json' : self .generate_json ,
533535 'csv-ci' : self .generate_csv ,
534- 'table' : self .generate_table }[export_format ]
535- output = to_call (file_desc )
536+ 'table' : self .generate_table ,
537+ 'bars' : self .generate_bars }[export_format ]
538+ output = to_call (file_desc , * args )
536539
537540 if file_desc is not stdout :
538541 file_desc .close ()
@@ -616,6 +619,71 @@ def generate_table(self, file_desc):
616619
617620 return output
618621
622+ def generate_bars (self , file_desc , device_name = None ):
623+ """ Generates nice looking bars that represent the memory consumption
624+
625+ Returns: string containing nice looking bars
626+ """
627+
628+ # TODO add tty detection, and width detection probably
629+ WIDTH = 72
630+ try :
631+ # NOTE this only works on linux
632+ import sys , fcntl , termios , struct
633+ height , width , _ , _ = struct .unpack ('HHHH' ,
634+ fcntl .ioctl (sys .stdout .fileno (), termios .TIOCGWINSZ ,
635+ struct .pack ('HHHH' , 0 , 0 , 0 , 0 )))
636+ WIDTH = min (width , WIDTH )
637+ except Exception :
638+ pass
639+
640+ text = self .subtotal ['.text' ]
641+ data = self .subtotal ['.data' ]
642+ bss = self .subtotal ['.bss' ]
643+ rom_used = self .mem_summary ['total_flash' ]
644+ ram_used = self .mem_summary ['static_ram' ]
645+
646+ # No device_name = no cmsis-pack = we don't know the memory layout
647+ if device_name is not None :
648+ try :
649+ cache = Cache (False , False )
650+ cmsis_part = cache .index [device_name ]
651+ rom_avail = int (cmsis_part ['memory' ]['IROM1' ]['size' ], 0 )
652+ ram_avail = int (cmsis_part ['memory' ]['IRAM1' ]['size' ], 0 )
653+ except KeyError :
654+ # If we don't have the expected regions, fall back to no device_name
655+ device_name = None
656+
657+ PREFIXES = ['' , 'K' , 'M' , 'G' , 'T' , 'P' , 'E' ]
658+ def unit (n , u = 'B' , p = 3 ):
659+ if n == 0 :
660+ return '0' + u
661+
662+ scale = math .floor (math .log (n , 1024 ))
663+ return '{1:.{0}g}{2}{3}' .format (p , n / (1024 ** scale ), PREFIXES [int (scale )], u )
664+
665+ usage = "Text {} Data {} BSS {}" .format (unit (text ), unit (data ), unit (bss ))
666+ avail = "ROM {} RAM {}" .format (unit (rom_used ), unit (ram_used ))
667+ output = ["{0} {1:>{2}}" .format (usage , avail ,
668+ abs (WIDTH - len (usage )- 1 ) if device_name is not None else 0 )]
669+
670+ if device_name is not None :
671+ for region , avail , uses in [
672+ ('ROM' , rom_avail , [('|' , text ), ('|' , data )]),
673+ ('RAM' , ram_avail , [('|' , bss ), ('|' , data )])]:
674+ barwidth = WIDTH - 17 - len (region )
675+
676+ used = sum (use for c , use in uses )
677+ bars = [(c , (barwidth * use ) // avail ) for c , use in uses ]
678+ bars .append ((' ' , barwidth - sum (width for c , width in bars )))
679+ bars = '' .join (c * width for c , width in bars )
680+
681+ output .append ("{0} [{2:<{1}}] {3:>13}" .format (
682+ region , barwidth , bars ,
683+ "{}/{}" .format (unit (used ), unit (avail ))))
684+
685+ return '\n ' .join (output )
686+
619687 toolchains = ["ARM" , "ARM_STD" , "ARM_MICRO" , "GCC_ARM" , "GCC_CR" , "IAR" ]
620688
621689 def compute_report (self ):
0 commit comments