- Apply pylint and flake8 formatting rules to the script. - Move syntax and usage exmaple to main() docstring. - Update get_jit_line() to only detect the main jit call. - Use mypy for specifying parameters and return types in functions.
Signed-off-by: Ahmed Karaman <ahmedkhaledkara...@gmail.com> --- scripts/performance/dissect.py | 123 ++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 55 deletions(-) diff --git a/scripts/performance/dissect.py b/scripts/performance/dissect.py index bf24f50922..d4df884b75 100755 --- a/scripts/performance/dissect.py +++ b/scripts/performance/dissect.py @@ -1,34 +1,27 @@ #!/usr/bin/env python3 -# Print the percentage of instructions spent in each phase of QEMU -# execution. -# -# Syntax: -# dissect.py [-h] -- <qemu executable> [<qemu executable options>] \ -# <target executable> [<target executable options>] -# -# [-h] - Print the script arguments help message. -# -# Example of usage: -# dissect.py -- qemu-arm coulomb_double-arm -# -# This file is a part of the project "TCG Continuous Benchmarking". -# -# Copyright (C) 2020 Ahmed Karaman <ahmedkhaledkara...@gmail.com> -# Copyright (C) 2020 Aleksandar Markovic <aleksandar.qemu.de...@gmail.com> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. +""" +Print the percentage of instructions spent in each phase of QEMU +execution. + +This file is a part of the project "TCG Continuous Benchmarking". + +Copyright (C) 2020 Ahmed Karaman <ahmedkhaledkara...@gmail.com> +Copyright (C) 2020 Aleksandar Markovic <aleksandar.qemu.de...@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. +""" import argparse import os @@ -36,23 +29,26 @@ import subprocess import sys import tempfile +from typing import List + -def get_JIT_line(callgrind_data): +def get_jit_line(callgrind_data: List[str]) -> int: """ Search for the first instance of the JIT call in the callgrind_annotate output when ran using --tree=caller This is equivalent to the self number of instructions of JIT. Parameters: - callgrind_data (list): callgrind_annotate output + callgrind_data (List[str]): callgrind_annotate output Returns: (int): Line number """ line = -1 - for i in range(len(callgrind_data)): - if callgrind_data[i].strip('\n') and \ - callgrind_data[i].split()[-1] == "[???]": + for (i, callgrind_datum) in enumerate(callgrind_data): + if callgrind_datum.strip('\n') and \ + callgrind_datum.split()[-1] == "[???]" and \ + callgrind_datum.split()[1] == "*": line = i break if line == -1: @@ -61,6 +57,18 @@ def get_JIT_line(callgrind_data): def main(): + """ + Parse the command line arguments then start the execution. + Syntax: + dissect.py [-h] -- <qemu executable> [<qemu executable options>] \ + <target executable> [<target executable options>] + + [-h] - Print the script arguments help message. + + Example of usage: + dissect.py -- qemu-arm coulomb_double-arm + """ + # Parse the command line arguments parser = argparse.ArgumentParser( usage='dissect.py [-h] -- ' @@ -76,7 +84,7 @@ def main(): # Insure that valgrind is installed check_valgrind = subprocess.run( - ["which", "valgrind"], stdout=subprocess.DEVNULL) + ["which", "valgrind"], stdout=subprocess.DEVNULL, check=False) if check_valgrind.returncode: sys.exit("Please install valgrind before running the script.") @@ -93,7 +101,8 @@ def main(): "--callgrind-out-file=" + data_path] + command), stdout=subprocess.DEVNULL, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + check=False) if callgrind.returncode: sys.exit(callgrind.stderr.decode("utf-8")) @@ -102,7 +111,8 @@ def main(): callgrind_annotate = subprocess.run( ["callgrind_annotate", data_path, "--tree=caller"], stdout=output, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + check=False) if callgrind_annotate.returncode: sys.exit(callgrind_annotate.stderr.decode("utf-8")) @@ -120,25 +130,28 @@ def main(): total_instructions = int(total_instructions.replace(',', '')) # Line number with the JIT self number of instructions - JIT_self_instructions_line_number = get_JIT_line(callgrind_data) + jit_self_instructions_line_number = get_jit_line(callgrind_data) # Get the JIT self number of instructions - JIT_self_instructions_line_data = \ - callgrind_data[JIT_self_instructions_line_number] - JIT_self_instructions = JIT_self_instructions_line_data.split()[0] - JIT_self_instructions = int(JIT_self_instructions.replace(',', '')) + jit_self_instructions_line_data = \ + callgrind_data[jit_self_instructions_line_number] + jit_self_instructions = jit_self_instructions_line_data.split()[0] + jit_self_instructions = int(jit_self_instructions.replace(',', '')) # Line number with the JIT self + inclusive number of instructions - # It's the line above the first JIT call when running with --tree=caller - JIT_total_instructions_line_number = JIT_self_instructions_line_number-1 + # It's the line above the first JIT call when running with + # --tree=caller + jit_total_instructions_line_number = \ + jit_self_instructions_line_number-1 # Get the JIT self + inclusive number of instructions - JIT_total_instructions_line_data = \ - callgrind_data[JIT_total_instructions_line_number] - JIT_total_instructions = JIT_total_instructions_line_data.split()[0] - JIT_total_instructions = int(JIT_total_instructions.replace(',', '')) + jit_total_instructions_line_data = \ + callgrind_data[jit_total_instructions_line_number] + jit_total_instructions = jit_total_instructions_line_data.split()[0] + jit_total_instructions = int(jit_total_instructions.replace(',', '')) # Calculate number of instructions in helpers and code generation - helpers_instructions = JIT_total_instructions-JIT_self_instructions - code_generation_instructions = total_instructions-JIT_total_instructions + helpers_instructions = jit_total_instructions-jit_self_instructions + code_generation_instructions = \ + total_instructions-jit_total_instructions # Print results (Insert commas in large numbers) # Print total number of instructions @@ -149,12 +162,12 @@ def main(): print('{:<20}{:>20}\t{:>6.3f}%'. format("Code Generation:", format(code_generation_instructions, ","), - (code_generation_instructions / total_instructions) * 100)) - # Print JIT instructions and percentage + (code_generation_instructions/total_instructions)*100)) + # Print jit instructions and percentage print('{:<20}{:>20}\t{:>6.3f}%'. - format("JIT Execution:", - format(JIT_self_instructions, ","), - (JIT_self_instructions / total_instructions) * 100)) + format("jit Execution:", + format(jit_self_instructions, ","), + (jit_self_instructions / total_instructions) * 100)) # Print helpers instructions and percentage print('{:<20}{:>20}\t{:>6.3f}%'. format("Helpers:", -- 2.17.1