Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/Tools/ardupilotwaf/build_summary.py
Views: 1798
# encoding: utf-812# Copyright (C) 2016 Intel Corporation. All rights reserved.3#4# This file is free software: you can redistribute it and/or modify it5# under the terms of the GNU General Public License as published by the6# Free Software Foundation, either version 3 of the License, or7# (at your option) any later version.8#9# This file is distributed in the hope that it will be useful, but10# WITHOUT ANY WARRANTY; without even the implied warranty of11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.12# See the GNU General Public License for more details.13#14# You should have received a copy of the GNU General Public License along15# with this program. If not, see <http://www.gnu.org/licenses/>.16'''17Waf tool for printing build summary. To be used, this must be loaded in the18options(), configure() and build() functions.1920This tool expects toolchain tool to be already loaded.2122The environment variable BUILD_SUMMARY_HEADER can be used to change the default23header for the targets' summary table.2425Extra information can be printed by creating assigning a function to26bld.extra_build_summary. That function must receive bld as the first argument27and this module as the second one.2829If one target's task generator (tg) doesn't have a link_task or places the ELF30file at a place different from link_task.outputs[0], then31tg.build_summary['binary'] should be set as the Node object or a path relative32to bld.bldnode for the binary file. Otherwise, size information won't be33printed for that target.34'''35import sys3637from waflib import Context, Logs, Node38from waflib.Configure import conf39from waflib.TaskGen import before_method, feature4041MAX_TARGETS = 204243header_text = {44'target': 'Target',45'binary_path': 'Binary',46'size_text': 'Text (B)',47'size_data': 'Data (B)',48'size_bss': 'BSS (B)',49'size_total': 'Total Flash Used (B)',50'size_free_flash': 'Free Flash (B)',51'ext_flash_used': 'External Flash Used (B)',52}5354def text(label, text=''):55text = text.strip()56if text:57Logs.info('%s%s%s%s%s' % (58Logs.colors.NORMAL,59Logs.colors.BOLD,60label,61Logs.colors.NORMAL,62text))63else:64Logs.info('%s%s%s' % (65Logs.colors.NORMAL,66Logs.colors.BOLD,67label68))6970def print_table(summary_data_list, header):71max_widths = []72table = [[] for _ in range(len(summary_data_list))]7374header_row = []75for h in header:76txt = header_text.get(h, h)77header_row.append(txt)78max_width = len(txt)79for i, row_data in enumerate(summary_data_list):80data = row_data.get(h, '-')8182# Output if a piece of reporting data is not applicable, example: free_flash in SITL83if data is None:84data = "Not Applicable"8586txt = str(data)87table[i].append(txt)8889w = len(txt)90if w > max_width:91max_width = w92max_widths.append(max_width)9394sep = ' '95fmts = ['{:<%d}' % w for w in max_widths]96header_row = sep.join(fmts).format(*header_row)97text(header_row)9899line = ('-' * len(sep)).join('-' * w for w in max_widths)100print(line)101102for row in table:103fmts = []104for j, v in enumerate(row):105w = max_widths[j]106try:107float(v)108except ValueError:109fmts.append('{:<%d}' % w)110else:111fmts.append('{:>%d}' % w)112row = sep.join(fmts).format(*row)113print(row)114115def _build_summary(bld):116Logs.info('')117text('BUILD SUMMARY')118text('Build directory: ', bld.bldnode.abspath())119120targets_suppressed = False121if bld.targets == '*':122taskgens = bld.get_all_task_gen()123if len(taskgens) > MAX_TARGETS and not bld.options.summary_all:124targets_suppressed = True125taskgens = taskgens[:MAX_TARGETS]126else:127targets = bld.targets.split(',')128if len(targets) > MAX_TARGETS and not bld.options.summary_all:129targets_suppressed = True130targets = targets[:MAX_TARGETS]131taskgens = [bld.get_tgen_by_name(t) for t in targets]132133nodes = []134filtered_taskgens = []135for tg in taskgens:136if not hasattr(tg, 'build_summary'):137tg.init_summary_data()138139n = tg.build_summary.get('binary', None)140if not n:141t = getattr(tg, 'link_task', None)142if not t:143continue144n = t.outputs[0]145tg.build_summary['binary'] = str(n)146147nodes.append(n)148filtered_taskgens.append(tg)149taskgens = filtered_taskgens150151if nodes:152l = bld.size_summary(nodes)153for i, data in enumerate(l):154taskgens[i].build_summary.update(data)155156summary_data_list = [tg.build_summary for tg in taskgens]157print_table(summary_data_list, bld.env.BUILD_SUMMARY_HEADER)158159if targets_suppressed:160Logs.info('')161Logs.pprint(162'NORMAL',163'\033[0;31;1mNote: Some targets were suppressed. Use --summary-all if you want information of all targets.',164)165166if hasattr(bld, 'extra_build_summary'):167bld.extra_build_summary(bld, sys.modules[__name__])168169# totals=True means relying on -t flag to give us a "(TOTALS)" output170def _parse_size_output(s, s_all, totals=False):171172# Get the size of .crash_log to remove it from .bss reporting173# also get external flash size if applicable174crash_log_size = None175ext_flash_used = 0176if s_all is not None:177lines = s_all.splitlines()[1:]178for line in lines:179if ".crash_log" in line:180row = line.strip().split()181crash_log_size = int(row[1])182if ".extflash" in line:183row = line.strip().split()184if int(row[1]) > 0:185ext_flash_used = int(row[1])186187import re188pattern = re.compile("^.*TOTALS.*$")189lines = s.splitlines()[1:]190l = []191for line in lines:192if pattern.match(line) or totals is False:193row = line.strip().split()194195# check if crash_log wasn't found196# this will be the case for none arm boards: sitl, linux, etc.197if crash_log_size is None:198size_bss = int(row[2])199size_free_flash = None200else:201# BSS: remove the portion occupied by crash_log as the command `size binary.elf`202# reports BSS with crash_log included203size_bss = int(row[2]) - crash_log_size204size_free_flash = crash_log_size205206l.append(dict(207size_text=int(row[0]),208size_data=int(row[1]),209size_bss=size_bss,210# Total Flash Cost = Data + Text211size_total=int(row[0]) + int(row[1]) - ext_flash_used,212size_free_flash=size_free_flash,213ext_flash_used= ext_flash_used if ext_flash_used else None,214))215return l216217@conf218def size_summary(bld, nodes):219l = []220for n in nodes:221path = n222if isinstance(n, Node.Node):223path = n.path_from(bld.bldnode)224l.append(dict(binary_path=path))225226for d in l:227if bld.env.SIZE:228if bld.env.get_flat('SIZE').endswith("xtensa-esp32-elf-size"):229cmd = [bld.env.get_flat('SIZE')] + ["-t"] + [d['binary_path']]230else:231cmd = [bld.env.get_flat('SIZE')] + [d['binary_path']]232233if bld.env.get_flat('SIZE').endswith("arm-none-eabi-size"):234cmd2 = [bld.env.get_flat('SIZE')] + ["-A"] + [d['binary_path']]235out2 = bld.cmd_and_log(cmd2,236cwd=bld.bldnode.abspath(),237quiet=Context.BOTH,238)239else:240out2 = None241242out = bld.cmd_and_log(243cmd,244cwd=bld.bldnode.abspath(),245quiet=Context.BOTH,246)247if bld.env.get_flat('SIZE').endswith("xtensa-esp32-elf-size"):248parsed = _parse_size_output(out, out2, True)249else:250parsed = _parse_size_output(out, out2, False)251for i, data in enumerate(parsed):252try:253d.update(data)254except:255print("build summary debug: "+str(i)+"->"+str(data))256257return l258259@conf260def build_summary_post_fun(bld):261if not bld.env.AP_PROGRAM_AS_STLIB:262bld.add_post_fun(_build_summary)263264@feature('cprogram', 'cxxprogram')265@before_method('process_rule')266def init_summary_data(self):267self.build_summary = dict(target=self.name)268269def options(opt):270g = opt.ap_groups['build']271272g.add_option('--summary-all',273action='store_true',274help='''Print build summary for all targets. By default, only275information about the first %d targets will be printed.276''' % MAX_TARGETS)277278def configure(cfg):279size_name = 'size'280281if cfg.env.TOOLCHAIN != 'native':282size_name = cfg.env.TOOLCHAIN + '-' + size_name283284cfg.find_program(size_name, var='SIZE', mandatory=False)285286if not cfg.env.BUILD_SUMMARY_HEADER:287cfg.env.BUILD_SUMMARY_HEADER = [288'target',289'size_text',290'size_data',291'size_bss',292'size_total',293'size_free_flash',294'ext_flash_used',295]296297298