1#!/usr/bin/env python 2# 3# Copyright 2019 Espressif Systems (Shanghai) PTE LTD 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17# This is python script to process various types trace data streams in SystemView format. 18# Trace data can be provided in multiple trace files (one per CPU). After processing phase 19# script prints report for every type of trace data stream which was found. 20# 21 22import argparse 23import json 24import logging 25import os.path 26import signal 27import sys 28import traceback 29 30import espytrace.apptrace as apptrace 31import espytrace.sysview as sysview 32 33 34def main(): 35 36 verbosity_levels = [ 37 logging.CRITICAL, 38 logging.ERROR, 39 logging.WARNING, 40 logging.INFO, 41 logging.DEBUG 42 ] 43 44 parser = argparse.ArgumentParser(description='ESP32 SEGGER SystemView Trace Parsing Tool') 45 46 parser.add_argument('trace_sources', help='Trace data sources. Format: [file://]/path/to/file.', nargs='+', type=str) 47 parser.add_argument('--elf-file', '-b', help='Path to program ELF file.', type=str, default='') 48 parser.add_argument('--tmo', '-w', help='Data wait timeout in sec. -1: infinite, 0: no wait', type=int, default=0) 49 parser.add_argument('--dump-events', '-d', help='Dump all events.', action='store_true') 50 parser.add_argument('--print-events', '-p', help='Print events of selected types. By default only reports are printed', action='store_true') 51 parser.add_argument('--include-events', '-i', help='Events types to be included into report.', type=str, choices=['heap', 'log', 'all'], default='all') 52 parser.add_argument('--toolchain', '-t', help='Toolchain prefix.', type=str, default='xtensa-esp32-elf-') 53 parser.add_argument('--events-map', '-e', help='Events map file.', type=str, default=os.path.join(os.path.dirname(__file__), 'SYSVIEW_FreeRTOS.txt')) 54 parser.add_argument('--to-json', '-j', help='Print JSON.', action='store_true', default=False) 55 parser.add_argument('--verbose', '-v', help='Verbosity level. Default 1', choices=range(0, len(verbosity_levels)), type=int, default=1) 56 args = parser.parse_args() 57 58 def sig_int_handler(signum, frame): 59 reader.cleanup() 60 61 signal.signal(signal.SIGINT, sig_int_handler) 62 63 include_events = {'heap': False, 'log': False} 64 if args.include_events == 'all': 65 for k in include_events: 66 include_events[k] = True 67 elif args.include_events == 'heap': 68 include_events['heap'] = True 69 elif args.include_events == 'log': 70 include_events['log'] = True 71 72 logging.basicConfig(level=verbosity_levels[args.verbose], format='[%(levelname)s] %(message)s') 73 74 # parse trace files 75 parsers = [] 76 for i, trace_source in enumerate(args.trace_sources): 77 try: 78 parser = sysview.SysViewMultiTraceDataParser(print_events=False, core_id=i) 79 if include_events['heap']: 80 parser.add_stream_parser(sysview.SysViewTraceDataParser.STREAMID_HEAP, 81 sysview.SysViewHeapTraceDataParser(print_events=False, core_id=i)) 82 if include_events['log']: 83 parser.add_stream_parser(sysview.SysViewTraceDataParser.STREAMID_LOG, 84 sysview.SysViewLogTraceDataParser(print_events=False, core_id=i)) 85 parsers.append(parser) 86 except Exception as e: 87 logging.error('Failed to create data parser (%s)!', e) 88 traceback.print_exc() 89 sys.exit(2) 90 reader = apptrace.reader_create(trace_source, args.tmo) 91 if not reader: 92 logging.error('Failed to create trace reader!') 93 sys.exit(2) 94 try: 95 # logging.info("Parse trace from '{}'...".format(trace_source)) 96 logging.info("Parse trace from '%s'...", trace_source) 97 sysview.parse_trace(reader, parser, args.events_map) 98 logging.info('Parsing completed.') 99 except (apptrace.ReaderTimeoutError, apptrace.ReaderShutdownRequest) as e: 100 logging.info('Stop parsing trace. (%s)', e) 101 except Exception as e: 102 logging.error('Failed to parse trace (%s)!', e) 103 parser.cleanup() 104 traceback.print_exc() 105 sys.exit(2) 106 finally: 107 reader.cleanup() 108 109 # merge and process traces 110 try: 111 proc = sysview.SysViewMultiStreamTraceDataProcessor(traces=parsers, print_events=args.dump_events, keep_all_events=True if args.to_json else False) 112 if include_events['heap']: 113 proc.add_stream_processor(sysview.SysViewTraceDataParser.STREAMID_HEAP, 114 sysview.SysViewHeapTraceDataProcessor(args.toolchain, args.elf_file, root_proc=proc, print_heap_events=args.print_events)) 115 if include_events['log']: 116 proc.add_stream_processor(sysview.SysViewTraceDataParser.STREAMID_LOG, 117 sysview.SysViewLogTraceDataProcessor(root_proc=proc, print_log_events=args.print_events)) 118 except Exception as e: 119 logging.error('Failed to create data processor (%s)!', e) 120 traceback.print_exc() 121 sys.exit(2) 122 123 try: 124 logging.info("Process events from '%s'...", args.trace_sources) 125 proc.merge_and_process() 126 logging.info('Processing completed.') 127 except Exception as e: 128 logging.error('Failed to process trace (%s)!', e) 129 traceback.print_exc() 130 sys.exit(2) 131 finally: 132 if args.to_json: 133 print(json.dumps(proc, cls=sysview.SysViewTraceDataJsonEncoder, indent=4, separators=(',', ': '), sort_keys=True)) 134 else: 135 proc.print_report() 136 proc.cleanup() 137 138 139if __name__ == '__main__': 140 main() 141