Switch to assuming python3. Fix minor pylint issues on line length, repeated compares, not using f-strings and variable case. Add type hints and check with mypy.
Showing the changes to tools/perf/scripts/python (1 of 1 file). Show all
Unified · Split
| @@ -18,7 +18,6 @@ · 17 unmodified lines | ||
| 18 | 18 | # pylint: disable=missing-class-docstring |
| 19 | 19 | # pylint: disable=missing-function-docstring |
| 20 | 20 | |
| 21 | −from __future__ import print_function | |
| 22 | 21 | import argparse |
| 23 | 22 | import hashlib |
| 24 | 23 | import io |
| @@ -26,9 +25,10 @@ import json · 1 unmodified line | ||
| 26 | 25 | import os |
| 27 | 26 | import subprocess |
| 28 | 27 | import sys |
| 28 | +from typing import Dict, Optional, Union | |
| 29 | 29 | import urllib.request |
| 30 | 30 | |
| 31 | −minimal_html = """<head> | |
| 31 | +MINIMAL_HTML = """<head> | |
| 32 | 32 | <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/d3-flamegraph.css"> |
| 33 | 33 | </head> |
| 34 | 34 | <body> |
| @@ -50,20 +50,20 @@ minimal_html = """<head> · 15 unmodified lines | ||
| 50 | 50 | |
| 51 | 51 | # pylint: disable=too-few-public-methods |
| 52 | 52 | class Node: |
| 53 | − def __init__(self, name, libtype): | |
| 53 | + def __init__(self, name: str, libtype: str): | |
| 54 | 54 | self.name = name |
| 55 | 55 | # "root" | "kernel" | "" |
| 56 | 56 | # "" indicates user space |
| 57 | 57 | self.libtype = libtype |
| 58 | − self.value = 0 | |
| 59 | − self.children = [] | |
| 58 | + self.value: int = 0 | |
| 59 | + self.children: list[Node] = [] | |
| 60 | 60 | |
| 61 | − def to_json(self): | |
| 61 | + def to_json(self) -> Dict[str, Union[str, int, list[Dict]]]: | |
| 62 | 62 | return { |
| 63 | 63 | "n": self.name, |
| 64 | 64 | "l": self.libtype, |
| 65 | 65 | "v": self.value, |
| 66 | − "c": self.children | |
| 66 | + "c": [x.to_json() for x in self.children] | |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | 69 | |
| @@ -73,7 +73,7 @@ class FlameGraphCLI: · 3 unmodified lines | ||
| 73 | 73 | self.stack = Node("all", "root") |
| 74 | 74 | |
| 75 | 75 | @staticmethod |
| 76 | − def get_libtype_from_dso(dso): | |
| 76 | + def get_libtype_from_dso(dso: Optional[str]) -> str: | |
| 77 | 77 | """ |
| 78 | 78 | when kernel-debuginfo is installed, |
| 79 | 79 | dso points to /usr/lib/debug/lib/modules/*/vmlinux |
| @@ -84,7 +84,7 @@ class FlameGraphCLI: · 4 unmodified lines | ||
| 84 | 84 | return "" |
| 85 | 85 | |
| 86 | 86 | @staticmethod |
| 87 | − def find_or_create_node(node, name, libtype): | |
| 87 | + def find_or_create_node(node: Node, name: str, libtype: str) -> Node: | |
| 88 | 88 | for child in node.children: |
| 89 | 89 | if child.name == name: |
| 90 | 90 | return child |
| @@ -93,7 +93,7 @@ class FlameGraphCLI: · 2 unmodified lines | ||
| 93 | 93 | node.children.append(child) |
| 94 | 94 | return child |
| 95 | 95 | |
| 96 | − def process_event(self, event): | |
| 96 | + def process_event(self, event) -> None: | |
| 97 | 97 | # ignore events where the event name does not match |
| 98 | 98 | # the one specified by the user |
| 99 | 99 | if self.args.event_name and event.get("ev_name") != self.args.event_name: |
| @@ -106,7 +106,7 @@ class FlameGraphCLI: · 6 unmodified lines | ||
| 106 | 106 | comm = event["comm"] |
| 107 | 107 | libtype = "kernel" |
| 108 | 108 | else: |
| 109 | − comm = "{} ({})".format(event["comm"], pid) | |
| 109 | + comm = f"{event['comm']} ({pid})" | |
| 110 | 110 | libtype = "" |
| 111 | 111 | node = self.find_or_create_node(self.stack, comm, libtype) |
| 112 | 112 | |
| @@ -121,7 +121,7 @@ class FlameGraphCLI: · 8 unmodified lines | ||
| 121 | 121 | node = self.find_or_create_node(node, name, libtype) |
| 122 | 122 | node.value += 1 |
| 123 | 123 | |
| 124 | − def get_report_header(self): | |
| 124 | + def get_report_header(self) -> str: | |
| 125 | 125 | if self.args.input == "-": |
| 126 | 126 | # when this script is invoked with "perf script flamegraph", |
| 127 | 127 | # no perf.data is created and we cannot read the header of it |
| @@ -131,7 +131,8 @@ class FlameGraphCLI: · 3 unmodified lines | ||
| 131 | 131 | # if the file name other than perf.data is given, |
| 132 | 132 | # we read the header of that file |
| 133 | 133 | if self.args.input: |
| 134 | − output = subprocess.check_output(["perf", "report", "--header-only", "-i", self.args.input]) | |
| 134 | + output = subprocess.check_output(["perf", "report", "--header-only", | |
| 135 | + "-i", self.args.input]) | |
| 135 | 136 | else: |
| 136 | 137 | output = subprocess.check_output(["perf", "report", "--header-only"]) |
| 137 | 138 | |
| @@ -140,10 +141,10 @@ class FlameGraphCLI: · 2 unmodified lines | ||
| 140 | 141 | result += "\nFocused event: " + self.args.event_name |
| 141 | 142 | return result |
| 142 | 143 | except Exception as err: # pylint: disable=broad-except |
| 143 | − print("Error reading report header: {}".format(err), file=sys.stderr) | |
| 144 | + print(f"Error reading report header: {err}", file=sys.stderr) | |
| 144 | 145 | return "" |
| 145 | 146 | |
| 146 | − def trace_end(self): | |
| 147 | + def trace_end(self) -> None: | |
| 147 | 148 | stacks_json = json.dumps(self.stack, default=lambda x: x.to_json()) |
| 148 | 149 | |
| 149 | 150 | if self.args.format == "html": |
| @@ -167,7 +168,8 @@ graph template (--template PATH) or use another output format (--format · 17 unmodified lines | ||
| 167 | 168 | FORMAT).""", |
| 168 | 169 | file=sys.stderr) |
| 169 | 170 | if self.args.input == "-": |
| 170 | − print("""Not attempting to download Flame Graph template as script command line | |
| 171 | + print( | |
| 172 | +"""Not attempting to download Flame Graph template as script command line | |
| 171 | 173 | input is disabled due to using live mode. If you want to download the |
| 172 | 174 | template retry without live mode. For example, use 'perf record -a -g |
| 173 | 175 | -F 99 sleep 60' and 'perf script report flamegraph'. Alternatively, |
| @@ -176,37 +178,40 @@ https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/templates/d3-flamegraph-b · 2 unmodified lines | ||
| 176 | 178 | and place it at: |
| 177 | 179 | /usr/share/d3-flame-graph/d3-flamegraph-base.html""", |
| 178 | 180 | file=sys.stderr) |
| 179 | − quit() | |
| 181 | + sys.exit(1) | |
| 180 | 182 | s = None |
| 181 | − while s != "y" and s != "n": | |
| 182 | − s = input("Do you wish to download a template from cdn.jsdelivr.net? (this warning can be suppressed with --allow-download) [yn] ").lower() | |
| 183 | + while s not in ["y", "n"]: | |
| 184 | + s = input("Do you wish to download a template from cdn.jsdelivr.net?" + | |
| 185 | + "(this warning can be suppressed with --allow-download) [yn] " | |
| 186 | + ).lower() | |
| 183 | 187 | if s == "n": |
| 184 | − quit() | |
| 185 | − template = "https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/templates/d3-flamegraph-base.html" | |
| 188 | + sys.exit(1) | |
| 189 | + template = ("https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/templates/" | |
| 190 | + "d3-flamegraph-base.html") | |
| 186 | 191 | template_md5sum = "143e0d06ba69b8370b9848dcd6ae3f36" |
| 187 | 192 | |
| 188 | 193 | try: |
| 189 | − with urllib.request.urlopen(template) as template: | |
| 194 | + with urllib.request.urlopen(template) as url_template: | |
| 190 | 195 | output_str = "".join([ |
| 191 | − l.decode("utf-8") for l in template.readlines() | |
| 196 | + l.decode("utf-8") for l in url_template.readlines() | |
| 192 | 197 | ]) |
| 193 | 198 | except Exception as err: |
| 194 | 199 | print(f"Error reading template {template}: {err}\n" |
| 195 | 200 | "a minimal flame graph will be generated", file=sys.stderr) |
| 196 | − output_str = minimal_html | |
| 201 | + output_str = MINIMAL_HTML | |
| 197 | 202 | template_md5sum = None |
| 198 | 203 | |
| 199 | 204 | if template_md5sum: |
| 200 | 205 | download_md5sum = hashlib.md5(output_str.encode("utf-8")).hexdigest() |
| 201 | 206 | if download_md5sum != template_md5sum: |
| 202 | 207 | s = None |
| 203 | − while s != "y" and s != "n": | |
| 208 | + while s not in ["y", "n"]: | |
| 204 | 209 | s = input(f"""Unexpected template md5sum. |
| 205 | 210 | {download_md5sum} != {template_md5sum}, for: |
| 206 | 211 | {output_str} |
| 207 | 212 | continue?[yn] """).lower() |
| 208 | 213 | if s == "n": |
| 209 | − quit() | |
| 214 | + sys.exit(1) | |
| 210 | 215 | |
| 211 | 216 | output_str = output_str.replace("/** @options_json **/", options_json) |
| 212 | 217 | output_str = output_str.replace("/** @flamegraph_json **/", stacks_json) |
| @@ -220,12 +225,12 @@ continue?[yn] """).lower() · 7 unmodified lines | ||
| 220 | 225 | with io.open(sys.stdout.fileno(), "w", encoding="utf-8", closefd=False) as out: |
| 221 | 226 | out.write(output_str) |
| 222 | 227 | else: |
| 223 | − print("dumping data to {}".format(output_fn)) | |
| 228 | + print(f"dumping data to {output_fn}") | |
| 224 | 229 | try: |
| 225 | 230 | with io.open(output_fn, "w", encoding="utf-8") as out: |
| 226 | 231 | out.write(output_str) |
| 227 | 232 | except IOError as err: |
| 228 | − print("Error writing output file: {}".format(err), file=sys.stderr) | |
| 233 | + print(f"Error writing output file: {err}", file=sys.stderr) | |
| 229 | 234 | sys.exit(1) |
| 230 | 235 | |
| 231 | 236 | |