mirror of https://github.com/ARMmbed/mbed-os.git
Handling output of parallelized test building.
This makes use of the reports generated by the building of tests to prevent output from interleaving when the build is parallelized. This required some changes to memap to return a generated string from the 'generate_output' function. I also had an option to stop the prints from memap to prevent text from interleavingpull/3227/head
parent
d1eaefe688
commit
09a09f70b7
|
@ -9,6 +9,7 @@ import csv
|
|||
import json
|
||||
import argparse
|
||||
from prettytable import PrettyTable
|
||||
from StringIO import StringIO
|
||||
|
||||
from utils import argparse_filestring_type, \
|
||||
argparse_lowercase_hyphen_type, argparse_uppercase_type
|
||||
|
@ -396,7 +397,7 @@ class MemapParser(object):
|
|||
|
||||
export_formats = ["json", "csv-ci", "table"]
|
||||
|
||||
def generate_output(self, export_format, file_output=None):
|
||||
def generate_output(self, export_format, file_output=None, silent=False):
|
||||
""" Generates summary of memory map data
|
||||
|
||||
Positional arguments:
|
||||
|
@ -407,6 +408,9 @@ class MemapParser(object):
|
|||
"""
|
||||
|
||||
try:
|
||||
if silent:
|
||||
file_desc = None
|
||||
else:
|
||||
if file_output:
|
||||
file_desc = open(file_output, 'wb')
|
||||
else:
|
||||
|
@ -418,27 +422,34 @@ class MemapParser(object):
|
|||
to_call = {'json': self.generate_json,
|
||||
'csv-ci': self.generate_csv,
|
||||
'table': self.generate_table}[export_format]
|
||||
to_call(file_desc)
|
||||
output_string = to_call(file_desc)
|
||||
|
||||
if file_desc is not sys.stdout:
|
||||
if file_desc is not sys.stdout and file_desc is not None:
|
||||
file_desc.close()
|
||||
|
||||
return output_string
|
||||
|
||||
def generate_json(self, file_desc):
|
||||
"""Generate a json file from a memory map
|
||||
|
||||
Positional arguments:
|
||||
file_desc - the file to write out the final report to
|
||||
"""
|
||||
file_desc.write(json.dumps(self.mem_report, indent=4))
|
||||
output = json.dumps(self.mem_report, indent=4)
|
||||
if file_desc:
|
||||
file_desc.write(output)
|
||||
file_desc.write('\n')
|
||||
|
||||
return output
|
||||
|
||||
def generate_csv(self, file_desc):
|
||||
"""Generate a CSV file from a memoy map
|
||||
|
||||
Positional arguments:
|
||||
file_desc - the file to write out the final report to
|
||||
"""
|
||||
csv_writer = csv.writer(file_desc, delimiter=',',
|
||||
string_io = StringIO()
|
||||
csv_writer = csv.writer(string_io, delimiter=',',
|
||||
quoting=csv.QUOTE_MINIMAL)
|
||||
|
||||
csv_module_section = []
|
||||
|
@ -472,6 +483,11 @@ class MemapParser(object):
|
|||
csv_writer.writerow(csv_module_section)
|
||||
csv_writer.writerow(csv_sizes)
|
||||
|
||||
if file_desc:
|
||||
file_desc.write(string_io.getvalue())
|
||||
|
||||
return string_io.getvalue()
|
||||
|
||||
def generate_table(self, file_desc):
|
||||
"""Generate a table from a memoy map
|
||||
|
||||
|
@ -504,28 +520,32 @@ class MemapParser(object):
|
|||
|
||||
table.add_row(subtotal_row)
|
||||
|
||||
file_desc.write(table.get_string())
|
||||
file_desc.write('\n')
|
||||
output = table.get_string()
|
||||
output += '\n'
|
||||
|
||||
if self.mem_summary['heap'] == 0:
|
||||
file_desc.write("Allocated Heap: unknown\n")
|
||||
output += "Allocated Heap: unknown\n"
|
||||
else:
|
||||
file_desc.write("Allocated Heap: %s bytes\n" %
|
||||
str(self.mem_summary['heap']))
|
||||
output += "Allocated Heap: %s bytes\n" % \
|
||||
str(self.mem_summary['heap'])
|
||||
|
||||
if self.mem_summary['stack'] == 0:
|
||||
file_desc.write("Allocated Stack: unknown\n")
|
||||
output += "Allocated Stack: unknown\n"
|
||||
else:
|
||||
file_desc.write("Allocated Stack: %s bytes\n" %
|
||||
str(self.mem_summary['stack']))
|
||||
output += "Allocated Stack: %s bytes\n" % \
|
||||
str(self.mem_summary['stack'])
|
||||
|
||||
file_desc.write("Total Static RAM memory (data + bss): %s bytes\n" %
|
||||
(str(self.mem_summary['static_ram'])))
|
||||
file_desc.write(
|
||||
"Total RAM memory (data + bss + heap + stack): %s bytes\n"
|
||||
% (str(self.mem_summary['total_ram'])))
|
||||
file_desc.write("Total Flash memory (text + data + misc): %s bytes\n" %
|
||||
(str(self.mem_summary['total_flash'])))
|
||||
output += "Total Static RAM memory (data + bss): %s bytes\n" % \
|
||||
str(self.mem_summary['static_ram'])
|
||||
output += "Total RAM memory (data + bss + heap + stack): %s bytes\n" % \
|
||||
str(self.mem_summary['total_ram'])
|
||||
output += "Total Flash memory (text + data + misc): %s bytes\n" % \
|
||||
str(self.mem_summary['total_flash'])
|
||||
|
||||
if file_desc:
|
||||
file_desc.write(output)
|
||||
|
||||
return output
|
||||
|
||||
toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "IAR"]
|
||||
|
||||
|
|
|
@ -2071,6 +2071,19 @@ def norm_relative_path(path, start):
|
|||
|
||||
|
||||
def build_test_worker(*args, **kwargs):
|
||||
"""This is a worker function for the parallel building of tests. The `args`
|
||||
and `kwargs` are passed directly to `build_project`. It returns a dictionary
|
||||
with the following structure:
|
||||
|
||||
{
|
||||
'result': `True` if no exceptions were thrown, `False` otherwise
|
||||
'reason': Instance of exception that was thrown on failure
|
||||
'bin_file': Path to the created binary if `build_project` was
|
||||
successful. Not present otherwise
|
||||
'kwargs': The keyword arguments that were passed to `build_project`.
|
||||
This includes arguments that were modified (ex. report)
|
||||
}
|
||||
"""
|
||||
bin_file = None
|
||||
ret = {
|
||||
'result': False,
|
||||
|
@ -2138,7 +2151,8 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
|
|||
'properties': properties,
|
||||
'verbose': verbose,
|
||||
'app_config': app_config,
|
||||
'build_profile': build_profile
|
||||
'build_profile': build_profile,
|
||||
'silent': True
|
||||
}
|
||||
|
||||
results.append(p.apply_async(build_test_worker, args, kwargs))
|
||||
|
@ -2161,13 +2175,16 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
|
|||
worker_result = r.get()
|
||||
results.remove(r)
|
||||
|
||||
# Take report from the kwargs and merge it into existing report
|
||||
report_entry = worker_result['kwargs']['report'][target_name][toolchain_name]
|
||||
for test_key in report_entry.keys():
|
||||
report[target_name][toolchain_name][test_key] = report_entry[test_key]
|
||||
|
||||
for test_key in worker_result['kwargs']['report'][target_name][toolchain_name].keys():
|
||||
report[target_name][toolchain_name][test_key] = worker_result['kwargs']['report'][target_name][toolchain_name][test_key]
|
||||
|
||||
# Set the overall result to a failure if a build failure occurred
|
||||
if not worker_result['result'] and not isinstance(worker_result['reason'], NotSupportedException):
|
||||
result = False
|
||||
|
||||
# Adding binary path to test build result
|
||||
if worker_result['result'] and 'bin_file' in worker_result:
|
||||
bin_file = norm_relative_path(worker_result['bin_file'], execution_directory)
|
||||
|
||||
|
@ -2179,7 +2196,9 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
|
|||
]
|
||||
}
|
||||
|
||||
# TODO: add 'Image: bin_file' print statement here
|
||||
test_key = worker_result['kwargs']['project_id'].upper()
|
||||
print report[target_name][toolchain_name][test_key][0][0]['output'].rstrip()
|
||||
print 'Image: %s\n' % bin_file
|
||||
|
||||
except ToolException, err:
|
||||
if p._taskqueue.queue:
|
||||
|
|
|
@ -1076,7 +1076,7 @@ class mbedToolchain:
|
|||
return None
|
||||
|
||||
# Write output to stdout in text (pretty table) format
|
||||
memap.generate_output('table')
|
||||
self.info(memap.generate_output('table', silent=True))
|
||||
|
||||
# Write output to file in JSON format
|
||||
map_out = splitext(map)[0] + "_map.json"
|
||||
|
|
Loading…
Reference in New Issue