Kristofer Jonsson | 0eb6905 | 2022-12-01 17:20:31 +0100 | [diff] [blame] | 1 | # |
| 2 | # SPDX-FileCopyrightText: Copyright 2022 Arm Limited and/or its affiliates <open-source-office@arm.com> |
| 3 | # |
| 4 | # SPDX-License-Identifier: Apache-2.0 |
| 5 | # |
| 6 | # Licensed under the Apache License, Version 2.0 (the License); you may |
| 7 | # not use this file except in compliance with the License. |
| 8 | # You may obtain a copy of the License at |
| 9 | # |
| 10 | # www.apache.org/licenses/LICENSE-2.0 |
| 11 | # |
| 12 | # Unless required by applicable law or agreed to in writing, software |
| 13 | # distributed under the License is distributed on an AS IS BASIS, WITHOUT |
| 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | # See the License for the specific language governing permissions and |
| 16 | # limitations under the License. |
| 17 | # |
| 18 | |
| 19 | from ethosumonitor.inputs import * |
| 20 | from ethosumonitor.outputs import * |
| 21 | from sys import stderr, exit |
| 22 | |
| 23 | def eventLoop(input: InputInterface, output: OutputInterface): |
| 24 | count = 0 |
| 25 | |
| 26 | try: |
| 27 | while(True): |
| 28 | for record in input.readEventRecord(): |
| 29 | output.writeEventRecord(record) |
| 30 | count = count + 1 |
| 31 | except KeyboardInterrupt: |
| 32 | stderr.write(f'count={count}, input={input}\n') |
| 33 | pass |
| 34 | except EOFError: |
| 35 | pass |
| 36 | |
| 37 | output.flush() |
| 38 | |
| 39 | def getDAPLink(args): |
| 40 | return InputDAPLink(args.elf, args.target, args.reset) |
| 41 | |
| 42 | def getMem(args): |
| 43 | return InputMem(args.elf, args.memory_map) |
| 44 | |
| 45 | def getFile(args): |
| 46 | return InputFile(args.file) |
| 47 | |
| 48 | def getOutput(args): |
| 49 | if args.output_format == 'binary': |
| 50 | return OutputBinary(args.output) |
| 51 | else: |
| 52 | return OutputJson(args.output) |
| 53 | |
| 54 | def addOutputArguments(parser): |
| 55 | parser.add_argument('--output-format', choices=['binary', 'json'], default='json', help='Output format.') |
| 56 | parser.add_argument('-o', '--output', default='/dev/stdout', help='Output file.') |
| 57 | |
| 58 | def main(): |
| 59 | import argparse |
| 60 | |
| 61 | parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, |
| 62 | description='Ethos-U monitor downloading profiling data.', |
| 63 | epilog=''' |
| 64 | Event Recorder: |
| 65 | The Event Recorder library is used to write performance data to a ring buffer |
| 66 | in memory. The ring buffer has a limited size and must be continuously |
| 67 | streamed to a host machine before it overflows. |
| 68 | |
| 69 | This script demonstrates how to stream performance data using DAPLink or |
| 70 | /dev/mem. Support for other technologies can be added implementing the |
| 71 | InputInterface class in inputs.py. |
| 72 | ''') |
| 73 | subparsers = parser.add_subparsers() |
| 74 | |
| 75 | subparser = subparsers.add_parser('daplink', |
| 76 | formatter_class=argparse.RawDescriptionHelpFormatter, |
| 77 | description='Download performance data using DAPLink.', |
| 78 | epilog=''' |
| 79 | DAPLink: |
| 80 | Arm Mbed DAPLink is an open source project that enables programming and |
| 81 | debugging application software running on an Arm Cortex CPU. A host machine |
| 82 | can connect to the target device using for example USB or JTAG. |
| 83 | |
| 84 | This script demonstrates how DAPLink can be used to stream Event Recorder |
| 85 | data from a target device. The ELF file passed to the script must be the |
| 86 | same application that is running on the device, and is used to find the |
| 87 | location of the Event Recorder ring buffer. |
| 88 | |
| 89 | $ ethosu_monitor.py daplink --target mps3_an540 myapplication.elf |
| 90 | ''') |
| 91 | subparser.set_defaults(getInput=getDAPLink) |
| 92 | subparser.add_argument('--target', default='mps3_an540', help='DAPLink target platform.') |
| 93 | subparser.add_argument('-r', '--reset', action='store_true', help='Reset target.') |
| 94 | subparser.add_argument('elf', help='Elf file running on the target.') |
| 95 | addOutputArguments(subparser) |
| 96 | |
| 97 | subparser = subparsers.add_parser('memory', |
| 98 | formatter_class=argparse.RawDescriptionHelpFormatter, |
| 99 | description='Download performance data using /dev/mem.', |
| 100 | epilog=''' |
| 101 | /dev/mem: |
| 102 | For a Linux based system the Event Recorder buffer should be stored in shared |
| 103 | memory accessible from Linux. This allows Linux to read device the Event |
| 104 | Recorder ring buffer using /dev/mem. |
| 105 | |
| 106 | The address of the Event Recorder ring buffer is found parsing the ELF |
| 107 | file. Because the device and Linux do not share the same address space a |
| 108 | memory map is required to translate device addresses into host addresses. |
| 109 | Please see sample.json for reference. |
| 110 | |
| 111 | $ ethosu_monitor.py memory --memory-map config.json myapplication.elf |
| 112 | ''') |
| 113 | subparser.set_defaults(getInput=getMem) |
| 114 | subparser.add_argument('--memory-map', required=True, help='JSON file describing physical memory map of target.') |
| 115 | subparser.add_argument('elf', help='Elf file running on the target.') |
| 116 | addOutputArguments(subparser) |
| 117 | |
| 118 | subparser = subparsers.add_parser('file', |
| 119 | formatter_class=argparse.RawDescriptionHelpFormatter, |
| 120 | description='Replay performance data stored in binary file.', |
| 121 | epilog=''' |
| 122 | file: |
| 123 | Event Recorder data can be written in binary format for later processing. |
| 124 | This will likely have less latency than the default JSON format, reducing |
| 125 | the risk over ring buffer overflows. |
| 126 | |
| 127 | $ ethosu_monitor.py daplink --output-format binary --output samples.bin myapplication.elf |
| 128 | |
| 129 | The binary data can later be unpacked to JSON. |
| 130 | |
| 131 | $ ethosu_monitor.py file samples.bin --output-format json |
| 132 | ''') |
| 133 | subparser.set_defaults(getInput=getFile) |
| 134 | subparser.add_argument('file', help='Binary file containing recorded performance data.') |
| 135 | addOutputArguments(subparser) |
| 136 | |
| 137 | args = parser.parse_args() |
| 138 | |
| 139 | if 'getInput' not in args: |
| 140 | parser.print_help() |
| 141 | exit(2) |
| 142 | |
| 143 | input = args.getInput(args) |
| 144 | output = getOutput(args) |
| 145 | eventLoop(input, output) |