Add summary for test building

When users are building tests with `mbed compile --tests` whey will by default
get memory map breakdown report.
This can be suppresed in the future with command line switch. For now it is
visible each time users build test cases.
List is sorted by project name created with `build_project` API.

Changes:
* `build_project` now returns tuple (this breaks build_api.build_project API!)
* Memmap script got a aggregation function to print summary from small 'JSON'
  partial reports.
* Report is generated by `test_api.build_tests` function only!

Example:
```
+----------------------------------------------------------------------+--------+-----------+-------------+------------+-------+-------+-----------+
| name                                                                 | target | toolchain | total_flash | static_ram | stack |  heap | total_ram |
+----------------------------------------------------------------------+--------+-----------+-------------+------------+-------+-------+-----------+
| features-feature_ipv4-tests-mbedmicro-net-nist_internet_time_service | K64F   | GCC_ARM   |      132136 |      62288 | 32768 | 65536 |    160592 |
| features-feature_ipv4-tests-mbedmicro-net-tcp_client_echo            | K64F   | GCC_ARM   |      125613 |      62448 | 32768 | 65540 |    160756 |
| features-feature_ipv4-tests-mbedmicro-net-tcp_client_hello_world     | K64F   | GCC_ARM   |      125949 |      62448 | 32768 | 65540 |    160756 |
| features-feature_ipv4-tests-mbedmicro-net-udp_echo_client            | K64F   | GCC_ARM   |      123613 |      62276 | 32768 | 65536 |    160580 |
| features-storage-tests-cfstore-add_del                               | K64F   | GCC_ARM   |       96080 |      13052 | 32768 | 65540 |    111360 |
| features-storage-tests-cfstore-close                                 | K64F   | GCC_ARM   |       95520 |      12004 | 32768 | 65540 |    110312 |
| features-storage-tests-cfstore-create                                | K64F   | GCC_ARM   |       99144 |      13036 | 32768 | 65540 |    111344 |
| features-storage-tests-cfstore-example1                              | K64F   | GCC_ARM   |       98592 |      12368 | 32768 | 65536 |    110672 |
| features-storage-tests-cfstore-example2                              | K64F   | GCC_ARM   |       95232 |      12012 | 32768 | 65540 |    110320 |
| features-storage-tests-cfstore-example3                              | K64F   | GCC_ARM   |       95264 |      11856 | 32768 | 65536 |    110160 |
| features-storage-tests-cfstore-example4                              | K64F   | GCC_ARM   |       92632 |      12012 | 32768 | 65540 |    110320 |
| features-storage-tests-cfstore-example5                              | K64F   | GCC_ARM   |       92344 |      11856 | 32768 | 65536 |    110160 |
| features-storage-tests-cfstore-find                                  | K64F   | GCC_ARM   |       96344 |      13028 | 32768 | 65540 |    111336 |
| features-storage-tests-cfstore-find2                                 | K64F   | GCC_ARM   |       93192 |      12004 | 32768 | 65540 |    110312 |
| features-storage-tests-cfstore-flash                                 | K64F   | GCC_ARM   |       97784 |      12532 | 32768 | 65540 |    110840 |
| features-storage-tests-cfstore-flush                                 | K64F   | GCC_ARM   |       96464 |      12012 | 32768 | 65540 |    110320 |
| features-storage-tests-cfstore-flush2                                | K64F   | GCC_ARM   |       95056 |      12004 | 32768 | 65540 |    110312 |
| features-storage-tests-cfstore-init                                  | K64F   | GCC_ARM   |       93120 |      12012 | 32768 | 65540 |    110320 |
| features-storage-tests-cfstore-misc                                  | K64F   | GCC_ARM   |       96808 |      12516 | 32768 | 65540 |    110824 |
| features-storage-tests-cfstore-open                                  | K64F   | GCC_ARM   |       98632 |      12540 | 32768 | 65540 |    110848 |
| features-storage-tests-cfstore-read                                  | K64F   | GCC_ARM   |       94112 |      12540 | 32768 | 65540 |    110848 |
| features-storage-tests-cfstore-write                                 | K64F   | GCC_ARM   |       94488 |      12004 | 32768 | 65540 |    110312 |
| features-storage-tests-flash_journal-basicapi                        | K64F   | GCC_ARM   |      104712 |      21236 | 32768 | 65540 |    119544 |
| frameworks-utest-tests-unit_tests-basic_test                         | K64F   | GCC_ARM   |       71534 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-case_async_validate                | K64F   | GCC_ARM   |       74598 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-case_control_async                 | K64F   | GCC_ARM   |       74630 |      11476 | 32768 | 65540 |    109784 |
| frameworks-utest-tests-unit_tests-case_control_repeat                | K64F   | GCC_ARM   |       72790 |      11452 | 32768 | 65540 |    109760 |
| frameworks-utest-tests-unit_tests-case_selection                     | K64F   | GCC_ARM   |       72302 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-case_setup_failure                 | K64F   | GCC_ARM   |       72630 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-case_teardown_failure              | K64F   | GCC_ARM   |       72790 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-control_type                       | K64F   | GCC_ARM   |       82462 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-minimal_async_scheduler            | K64F   | GCC_ARM   |       72182 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-minimal_scheduler                  | K64F   | GCC_ARM   |       71998 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-test_assertion_failure_test_setup  | K64F   | GCC_ARM   |       71710 |      11460 | 32768 | 65540 |    109768 |
| frameworks-utest-tests-unit_tests-test_setup_case_selection_failure  | K64F   | GCC_ARM   |       71702 |      11468 | 32768 | 65540 |    109776 |
| frameworks-utest-tests-unit_tests-test_setup_failure                 | K64F   | GCC_ARM   |       71710 |      11468 | 32768 | 65540 |    109776 |
| tests-integration-basic                                              | K64F   | GCC_ARM   |       67566 |      10780 | 32768 | 65540 |    109088 |
| tests-integration-threaded_blinky                                    | K64F   | GCC_ARM   |       68326 |      10780 | 32768 | 65540 |    109088 |
| tests-mbed_drivers-c_strings                                         | K64F   | GCC_ARM   |       74438 |      11468 | 32768 | 65540 |    109776 |
| tests-mbed_drivers-callback                                          | K64F   | GCC_ARM   |       88310 |      11972 | 32768 | 65540 |    110280 |
| tests-mbed_drivers-dev_null                                          | K64F   | GCC_ARM   |       90213 |      10784 | 32768 | 65540 |    109092 |
| tests-mbed_drivers-echo                                              | K64F   | GCC_ARM   |       71918 |      11468 | 32768 | 65540 |    109776 |
| tests-mbed_drivers-generic_tests                                     | K64F   | GCC_ARM   |       77624 |      11468 | 32768 | 65540 |    109776 |
| tests-mbed_drivers-rtc                                               | K64F   | GCC_ARM   |       85854 |      11308 | 32768 | 65540 |    109616 |
| tests-mbed_drivers-stl_features                                      | K64F   | GCC_ARM   |       80726 |      11476 | 32768 | 65540 |    109784 |
| tests-mbed_drivers-ticker                                            | K64F   | GCC_ARM   |       70974 |      11308 | 32768 | 65540 |    109616 |
| tests-mbed_drivers-ticker_2                                          | K64F   | GCC_ARM   |       70790 |      11308 | 32768 | 65540 |    109616 |
| tests-mbed_drivers-ticker_3                                          | K64F   | GCC_ARM   |       71038 |      11308 | 32768 | 65540 |    109616 |
| tests-mbed_drivers-timeout                                           | K64F   | GCC_ARM   |       70886 |      11308 | 32768 | 65540 |    109616 |
| tests-mbed_drivers-wait_us                                           | K64F   | GCC_ARM   |       70414 |      11308 | 32768 | 65540 |    109616 |
| tests-mbedmicro-mbed-attributes                                      | K64F   | GCC_ARM   |       71534 |      11460 | 32768 | 65540 |    109768 |
| tests-mbedmicro-mbed-call_before_main                                | K64F   | GCC_ARM   |       73112 |      10780 | 32768 | 65540 |    109088 |
| tests-mbedmicro-mbed-cpp                                             | K64F   | GCC_ARM   |       73400 |      10780 | 32768 | 65540 |    109088 |
| tests-mbedmicro-mbed-div                                             | K64F   | GCC_ARM   |       73176 |      10780 | 32768 | 65540 |    109088 |
| tests-mbedmicro-rtos-mbed-basic                                      | K64F   | GCC_ARM   |       68390 |      10780 | 32768 | 65540 |    109088 |
| tests-mbedmicro-rtos-mbed-isr                                        | K64F   | GCC_ARM   |       74480 |      10780 | 32768 | 65540 |    109088 |
| tests-mbedmicro-rtos-mbed-mail                                       | K64F   | GCC_ARM   |       74992 |      11300 | 32768 | 65540 |    109608 |
| tests-mbedmicro-rtos-mbed-mutex                                      | K64F   | GCC_ARM   |       74048 |      10780 | 32768 | 65540 |    109088 |
| tests-mbedmicro-rtos-mbed-queue                                      | K64F   | GCC_ARM   |       74912 |      11300 | 32768 | 65540 |    109608 |
| tests-mbedmicro-rtos-mbed-semaphore                                  | K64F   | GCC_ARM   |       74296 |      10780 | 32768 | 65540 |    109088 |
| tests-mbedmicro-rtos-mbed-signals                                    | K64F   | GCC_ARM   |       74328 |      10780 | 32768 | 65540 |    109088 |
| tests-mbedmicro-rtos-mbed-threads                                    | K64F   | GCC_ARM   |       75214 |      11460 | 32768 | 65540 |    109768 |
| tests-mbedmicro-rtos-mbed-timer                                      | K64F   | GCC_ARM   |       68430 |      10780 | 32768 | 65540 |    109088 |
| tests-storage_abstraction-basicapi                                   | K64F   | GCC_ARM   |      107808 |      28908 | 32768 | 65540 |    127216 |
+----------------------------------------------------------------------+--------+-----------+-------------+------------+-------+-------+-----------+
```

Refactored after code review

Refactored parse() function

Polishing

Moved memory usage reporting function call to test.py to group all reporters in one place

Bug-fix: on ARM toolchain we were not fetching statistics from last element of memap result list
pull/2047/head
Przemek Wirkus 2016-06-28 16:34:28 +01:00
parent 458b46c803
commit 12a01f61ca
5 changed files with 186 additions and 109 deletions

View File

@ -232,6 +232,7 @@ def build_project(src_path, build_path, target, toolchain_name,
cur_result["elapsed_time"] = end - start
cur_result["output"] = toolchain.get_output()
cur_result["result"] = "OK"
cur_result["memory_usage"] = toolchain.map_outputs
add_result_to_report(report, cur_result)
@ -942,6 +943,49 @@ def print_build_results(result_list, build_name):
result += "\n"
return result
def print_build_memory_usage_results(report):
""" Generate result table with memory usage values for build results
Agregates (puts together) reports obtained from self.get_memory_summary()
@param report Report generated during build procedure. See
"""
from prettytable import PrettyTable
columns_text = ['name', 'target', 'toolchain']
columns_int = ['static_ram', 'stack', 'heap', 'total_ram', 'total_flash']
table = PrettyTable(columns_text + columns_int)
for col in columns_text:
table.align[col] = 'l'
for col in columns_int:
table.align[col] = 'r'
for target in report:
for toolchain in report[target]:
for name in report[target][toolchain]:
for dlist in report[target][toolchain][name]:
for dlistelem in dlist:
# Get 'memory_usage' record and build table with statistics
record = dlist[dlistelem]
if 'memory_usage' in record and record['memory_usage']:
# Note that summary should be in the last record of
# 'memory_usage' section. This is why we are grabbing
# last "[-1]" record.
row = [
record['description'],
record['target_name'],
record['toolchain_name'],
record['memory_usage'][-1]['summary']['static_ram'],
record['memory_usage'][-1]['summary']['stack'],
record['memory_usage'][-1]['summary']['heap'],
record['memory_usage'][-1]['summary']['total_ram'],
record['memory_usage'][-1]['summary']['total_flash'],
]
table.add_row(row)
result = "Memory map breakdown for built projects (values in Bytes):\n"
result += table.get_string(sortby='name')
return result
def write_build_report(build_report, template_filename, filename):
build_report_failing = []
build_report_passing = []

View File

@ -26,9 +26,9 @@ class MemapParser(object):
self.misc_flash_sections = ('.interrupts', '.flash_config')
self.other_sections = ('.interrupts_ram', '.init', '.ARM.extab', \
'.ARM.exidx', '.ARM.attributes', '.eh_frame', \
'.init_array', '.fini_array', '.jcr', '.stab', \
self.other_sections = ('.interrupts_ram', '.init', '.ARM.extab',
'.ARM.exidx', '.ARM.attributes', '.eh_frame',
'.init_array', '.fini_array', '.jcr', '.stab',
'.stabstr', '.ARM.exidx', '.ARM')
# sections to print info (generic for all toolchains)
@ -43,6 +43,9 @@ class MemapParser(object):
# list of all object files and mappting to module names
self.object_to_module = dict()
# Memory usage summary structure
self.mem_summary = dict()
def module_add(self, module_name, size, section):
"""
Adds a module / section to the list
@ -67,7 +70,7 @@ class MemapParser(object):
return i # should name of the section (assuming it's a known one)
if line.startswith('.'):
return 'unknown' # all others are clasified are unknown
return 'unknown' # all others are classified are unknown
else:
return False # everything else, means no change in section
@ -363,11 +366,12 @@ class MemapParser(object):
# Create table
columns = ['Module']
for i in list(self.print_sections):
columns.append(i)
columns.extend(self.print_sections)
table = PrettyTable(columns)
table.align["Module"] = "l"
for col in self.print_sections:
table.align[col] = 'r'
for i in list(self.print_sections):
table.align[i] = 'r'
@ -388,8 +392,12 @@ class MemapParser(object):
for k in self.print_sections:
row.append(self.modules[i][k])
json_obj.append({"module":i, "size":{\
k:self.modules[i][k] for k in self.print_sections}})
json_obj.append({
"module":i,
"size":{
k:self.modules[i][k] for k in self.print_sections
}
})
table.add_row(row)
@ -399,16 +407,19 @@ class MemapParser(object):
table.add_row(subtotal_row)
if export_format == 'json':
json_obj.append({\
'summary':{\
'total_static_ram':(subtotal['.data']+subtotal['.bss']),\
'allocated_heap':(subtotal['.heap']),\
'allocated_stack':(subtotal['.stack']),\
'total_ram':(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack']),\
'total_flash':(subtotal['.text']+subtotal['.data']+misc_flash_mem),}})
summary = {
'summary':{
'static_ram':(subtotal['.data']+subtotal['.bss']),
'heap':(subtotal['.heap']),
'stack':(subtotal['.stack']),
'total_ram':(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack']),
'total_flash':(subtotal['.text']+subtotal['.data']+misc_flash_mem),
}
}
file_desc.write(json.dumps(json_obj, indent=4))
if export_format == 'json':
json_to_file = json_obj + [summary]
file_desc.write(json.dumps(json_to_file, indent=4))
file_desc.write('\n')
elif export_format == 'csv-ci': # CSV format for the CI system
@ -467,19 +478,24 @@ class MemapParser(object):
if file_desc is not sys.stdout:
file_desc.close()
self.mem_summary = json_obj + [summary]
return True
def get_memory_summary(self):
"""! Object is available only after self.generate_output('json') is called
@return Return memory summary object
"""
return self.mem_summary
def parse(self, mapfile, toolchain):
"""
Parse and decode map file depending on the toolchain
"""
result = True
try:
file_input = open(mapfile, 'rt')
except IOError as error:
print "I/O error({0}): {1}".format(error.errno, error.strerror)
return False
with open(mapfile, 'rt') as file_input:
if toolchain == "ARM" or toolchain == "ARM_STD" or toolchain == "ARM_MICRO":
self.search_objects(os.path.abspath(mapfile), "ARM")
self.parse_map_file_armcc(file_input)
@ -489,11 +505,11 @@ class MemapParser(object):
self.search_objects(os.path.abspath(mapfile), toolchain)
self.parse_map_file_iar(file_input)
else:
return False
file_input.close()
return True
result = False
except IOError as error:
print "I/O error({0}): {1}".format(error.errno, error.strerror)
result = False
return result
def main():

View File

@ -29,6 +29,7 @@ sys.path.insert(0, ROOT)
from tools.test_api import test_path_to_name, find_tests, print_tests, build_tests, test_spec_from_test_builds
from tools.options import get_default_options_parser
from tools.build_api import build_project, build_library
from tools.build_api import print_build_memory_usage_results
from tools.targets import TARGET_MAP
from tools.utils import mkdir, ToolException, NotSupportedException
from tools.test_exporters import ReportExporter, ResultExporterType
@ -198,6 +199,11 @@ if __name__ == '__main__':
report_exporter = ReportExporter(ResultExporterType.JUNIT, package="build")
report_exporter.report_to_file(build_report, options.build_report_junit, test_suite_properties=build_properties)
# Print memory map summary on screen
if build_report:
print
print print_build_memory_usage_results(build_report)
print_report_exporter = ReportExporter(ResultExporterType.PRINT, package="build")
status = print_report_exporter.report(build_report)

View File

@ -46,6 +46,7 @@ from tools.paths import HOST_TESTS
from tools.utils import ToolException
from tools.utils import NotSupportedException
from tools.utils import construct_enum
from tools.memap import MemapParser
from tools.targets import TARGET_MAP
from tools.test_db import BaseDBAccess
from tools.build_api import build_project, build_mbed_libs, build_lib
@ -2038,7 +2039,6 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
build data structure"""
execution_directory = "."
base_path = norm_relative_path(build_path, execution_directory)
target_name = target if isinstance(target, str) else target.name
@ -2054,6 +2054,7 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
result = True
map_outputs_total = list()
for test_name, test_path in tests.iteritems():
test_build_path = os.path.join(build_path, test_path)
src_path = base_source_paths + [test_path]

View File

@ -285,7 +285,8 @@ class mbedToolchain:
self.silent = silent
# Print output buffer
self.output = ""
self.output = str()
self.map_outputs = list() # Place to store memmap scan results in JSON like data structures
# Build options passed by -o flag
self.options = options if options is not None else []
@ -844,7 +845,7 @@ class mbedToolchain:
self.binary(r, elf, bin)
self.mem_stats(map)
self.map_outputs = self.mem_stats(map)
self.var("compile_succeded", True)
self.var("binary", filename)
@ -900,7 +901,11 @@ class mbedToolchain:
self.notify({'type': 'var', 'key': key, 'val': value})
def mem_stats(self, map):
# Creates parser object
"""! Creates parser object
@param map Path to linker map file to parse and decode
@return Memory summary structure with memory usage statistics
None if map file can't be opened and processed
"""
toolchain = self.__class__.__name__
# Create memap object
@ -909,7 +914,7 @@ class mbedToolchain:
# Parse and decode a map file
if memap.parse(abspath(map), toolchain) is False:
self.info("Unknown toolchain for memory statistics %s" % toolchain)
return
return None
# Write output to stdout in text (pretty table) format
memap.generate_output('table')
@ -922,6 +927,11 @@ class mbedToolchain:
map_csv = splitext(map)[0] + "_map.csv"
memap.generate_output('csv-ci', map_csv)
# Here we return memory statistics structure (constructed after
# call to generate_output) which contains raw data in bytes
# about sections + summary
return memap.get_memory_summary()
# Set the configuration data
def set_config_data(self, config_data):
self.config_data = config_data