Skip to content

Commit

Permalink
Merge pull request #5929 from ARMmbed/prettybars
Browse files Browse the repository at this point in the history
Add pretty bars for compile output
  • Loading branch information
cmonr committed Jan 29, 2018
2 parents 6da5d54 + 471d99c commit 702eaff
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 10 deletions.
18 changes: 12 additions & 6 deletions tools/build_api.py
Expand Up @@ -27,6 +27,7 @@
from time import time
from intelhex import IntelHex
from json import load, dump
from tools.arm_pack_manager import Cache

from tools.utils import mkdir, run_cmd, run_cmd_ext, NotSupportedException,\
ToolException, InvalidReleaseTargetException, intelhex_offset
Expand Down Expand Up @@ -547,19 +548,24 @@ def build_project(src_paths, build_path, target, toolchain_name,
memap_instance = getattr(toolchain, 'memap_instance', None)
memap_table = ''
if memap_instance:
# Write output to stdout in text (pretty table) format
memap_table = memap_instance.generate_output('table', stats_depth)

real_stats_depth = stats_depth if stats_depth is None else 2
memap_table = memap_instance.generate_output('table', real_stats_depth)
if not silent:
print memap_table
if not stats_depth:
memap_bars = memap_instance.generate_output('bars',
real_stats_depth, None,
getattr(toolchain.target, 'device_name', None))
print memap_bars
else:
print memap_table

# Write output to file in JSON format
map_out = join(build_path, name + "_map.json")
memap_instance.generate_output('json', stats_depth, map_out)
memap_instance.generate_output('json', real_stats_depth, map_out)

# Write output to file in CSV format for the CI
map_csv = join(build_path, name + "_map.csv")
memap_instance.generate_output('csv-ci', stats_depth, map_csv)
memap_instance.generate_output('csv-ci', real_stats_depth, map_csv)

resources.detect_duplicates(toolchain)

Expand Down
2 changes: 1 addition & 1 deletion tools/make.py
Expand Up @@ -116,7 +116,7 @@
"--stats-depth",
type=int,
dest="stats_depth",
default=2,
default=None,
help="Depth level for static memory report")

# Local run
Expand Down
74 changes: 71 additions & 3 deletions tools/memap.py
Expand Up @@ -9,9 +9,11 @@
import re
import csv
import json
import math
from argparse import ArgumentParser
from copy import deepcopy
from prettytable import PrettyTable
from tools.arm_pack_manager import Cache

from utils import argparse_filestring_type, \
argparse_lowercase_hyphen_type, argparse_uppercase_type
Expand Down Expand Up @@ -506,7 +508,7 @@ def reduce_depth(self, depth):

export_formats = ["json", "csv-ci", "table"]

def generate_output(self, export_format, depth, file_output=None):
def generate_output(self, export_format, depth, file_output=None, *args):
""" Generates summary of memory map data
Positional arguments:
Expand All @@ -531,8 +533,9 @@ def generate_output(self, export_format, depth, file_output=None):

to_call = {'json': self.generate_json,
'csv-ci': self.generate_csv,
'table': self.generate_table}[export_format]
output = to_call(file_desc)
'table': self.generate_table,
'bars': self.generate_bars}[export_format]
output = to_call(file_desc, *args)

if file_desc is not stdout:
file_desc.close()
Expand Down Expand Up @@ -616,6 +619,71 @@ def generate_table(self, file_desc):

return output

def generate_bars(self, file_desc, device_name=None):
""" Generates nice looking bars that represent the memory consumption
Returns: string containing nice looking bars
"""

# TODO add tty detection, and width detection probably
WIDTH = 72
try:
# NOTE this only works on linux
import sys, fcntl, termios, struct
height, width, _, _ = struct.unpack('HHHH',
fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ,
struct.pack('HHHH', 0, 0, 0, 0)))
WIDTH = min(width, WIDTH)
except Exception:
pass

text = self.subtotal['.text']
data = self.subtotal['.data']
bss = self.subtotal['.bss']
rom_used = self.mem_summary['total_flash']
ram_used = self.mem_summary['static_ram']

# No device_name = no cmsis-pack = we don't know the memory layout
if device_name is not None:
try:
cache = Cache(False, False)
cmsis_part = cache.index[device_name]
rom_avail = int(cmsis_part['memory']['IROM1']['size'], 0)
ram_avail = int(cmsis_part['memory']['IRAM1']['size'], 0)
except KeyError:
# If we don't have the expected regions, fall back to no device_name
device_name = None

PREFIXES = ['', 'K', 'M', 'G', 'T', 'P', 'E']
def unit(n, u='B', p=3):
if n == 0:
return '0' + u

scale = math.floor(math.log(n, 1024))
return '{1:.{0}g}{2}{3}'.format(p, n/(1024**scale), PREFIXES[int(scale)], u)

usage = "Text {} Data {} BSS {}".format(unit(text), unit(data), unit(bss))
avail = "ROM {} RAM {}".format(unit(rom_used), unit(ram_used))
output = ["{0} {1:>{2}}".format(usage, avail,
abs(WIDTH-len(usage)-1) if device_name is not None else 0)]

if device_name is not None:
for region, avail, uses in [
('ROM', rom_avail, [('|', text), ('|', data)]),
('RAM', ram_avail, [('|', bss), ('|', data)])]:
barwidth = WIDTH-17 - len(region)

used = sum(use for c, use in uses)
bars = [(c, (barwidth*use) // avail) for c, use in uses]
bars.append((' ', barwidth - sum(width for c, width in bars)))
bars = ''.join(c*width for c, width in bars)

output.append("{0} [{2:<{1}}] {3:>13}".format(
region, barwidth, bars,
"{}/{}".format(unit(used), unit(avail))))

return '\n'.join(output)

toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "GCC_CR", "IAR"]

def compute_report(self):
Expand Down

0 comments on commit 702eaff

Please sign in to comment.