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 interleaving
pull/3227/head
Brian Daniels 2016-10-11 14:33:24 -05:00 committed by Anna Bridge
parent d1eaefe688
commit 09a09f70b7
3 changed files with 69 additions and 30 deletions

View File

@ -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,10 +408,13 @@ class MemapParser(object):
"""
try:
if file_output:
file_desc = open(file_output, 'wb')
if silent:
file_desc = None
else:
file_desc = sys.stdout
if file_output:
file_desc = open(file_output, 'wb')
else:
file_desc = sys.stdout
except IOError as error:
print "I/O error({0}): {1}".format(error.errno, error.strerror)
return False
@ -418,19 +422,25 @@ 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))
file_desc.write('\n')
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
@ -438,7 +448,8 @@ class MemapParser(object):
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"]

View File

@ -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:

View File

@ -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"