From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=3.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 47A6CC433E2 for ; Mon, 7 Sep 2020 20:53:20 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AF0D4215A4 for ; Mon, 7 Sep 2020 20:53:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="MEZUlVcG" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org AF0D4215A4 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:60264 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kFO8c-0002vQ-SB for qemu-devel@archiver.kernel.org; Mon, 07 Sep 2020 16:53:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:43952) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kFO7w-0002Vb-Dg for qemu-devel@nongnu.org; Mon, 07 Sep 2020 16:52:36 -0400 Received: from mail-wm1-x342.google.com ([2a00:1450:4864:20::342]:33316) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kFO7t-0005zF-Go for qemu-devel@nongnu.org; Mon, 07 Sep 2020 16:52:36 -0400 Received: by mail-wm1-x342.google.com with SMTP id e11so13015756wme.0 for ; Mon, 07 Sep 2020 13:52:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=8k3hNuOvCKxkiLvebs/i9xjFCjigeYM/uMxZiMh6mkY=; b=MEZUlVcG0Igsckm5CYSHx2dvQdKtMeQEfhfIAjNY9mkglHTh0/OtTZI7pACt5m8Uhj OqnO0XiHuOqlYsHYtuJHrhdq0G20ui7XmUDxO99HJW6030t7L9aCRPt3pWLzVNqIkn0e +2VEtrQFPWO4IIPpDRosrq1L+Ocf+Wa862WhBZ50IdCA2pZCYFifyy5cIJ1r5YhKnWeL H/971MCr4zGPpF/7Fa9tv6UxL+5DDKt+n7Pc8gsKGRmM7AEXn9KLudXzIkVof2mjdY3l FCXyplr1zVFxneA0pcSpWRPrubLhV8Xneqs2g/0KJQdl7s61D97ZmSz1UOfkIrmPcePr 2rsQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=8k3hNuOvCKxkiLvebs/i9xjFCjigeYM/uMxZiMh6mkY=; b=EB8zUKpXYUTQyvo4lmFTvWF1XSMiz9sjjooaK1YK8ehBFTmnHgSmwqRvRrn1lUpxUx pGNftcfwKF4T/TkZZGfPwe9VNLvidGL7ZZ1pIB34ItWRvCZEaKelibdx/4zF5x0GfK5x W7lgsMB8zZQJcBYVr7eyot6RnQZUjJ5/2CCaPKOUSV/4zzp5rnYt44u4lAV4RNVM6sqw +eqR8kh1oFmyNduzCqf/eD8ficmloXRvrpTNdDB79GcVFXtsWGaafIV61nfas7j2lGtc NjcPt/Qxjl/WiArdZyX1msh4rrxSvK8qyGiXMS+8/rRAWmcXOoxCiiUGX/VUBksTsP8u gNzg== X-Gm-Message-State: AOAM533dqJvO0+4CRtqPGfb+bHnBMYvS+NbrcGNc8iVqFrdj/F2FpuLX dKrNRBoLPsXbzvABwhaHM01fyJus++r0o0yNyQWDTnGp X-Google-Smtp-Source: ABdhPJxCGDI6r7Zqg9hZEqXuftD7kcZWi5WGQEMFQ309GC4evJ0+KFkNWourSyaUxRbV8MdbyXzg9mLHGC8/+rXKWmY= X-Received: by 2002:a05:600c:4104:: with SMTP id j4mr1029945wmi.36.1599511951561; Mon, 07 Sep 2020 13:52:31 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a7b:c351:0:0:0:0:0 with HTTP; Mon, 7 Sep 2020 13:52:31 -0700 (PDT) In-Reply-To: <20200828104102.4490-2-ahmedkhaledkaraman@gmail.com> References: <20200828104102.4490-1-ahmedkhaledkaraman@gmail.com> <20200828104102.4490-2-ahmedkhaledkaraman@gmail.com> From: Aleksandar Markovic Date: Mon, 7 Sep 2020 22:52:31 +0200 Message-ID: Subject: Re: [PATCH 1/9] scripts/performance: Refactor topN_perf.py To: Ahmed Karaman Content-Type: multipart/alternative; boundary="000000000000afdbe605aebf6523" Received-SPF: pass client-ip=2a00:1450:4864:20::342; envelope-from=aleksandar.qemu.devel@gmail.com; helo=mail-wm1-x342.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_PDS_OTHER_BAD_TLD=0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "ldoktor@redhat.com" , "ehabkost@redhat.com" , "jsnow@redhat.com" , "qemu-devel@nongnu.org" , "philmd@redhat.com" , "crosa@redhat.com" , "alex.bennee@linaro.org" , "rth@twiddle.net" Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" --000000000000afdbe605aebf6523 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Friday, August 28, 2020, Ahmed Karaman wrote: > - Apply pylint and flake8 formatting rules to the script. > - Use 'tempfile' instead of '/tmp' for creating temporary files. > > Reviewed-by: Aleksandar Markovic Reply Reply all Forward View Gmail in: *Mobile* | Older version | Desktop =C2=A9 2020 Google > Signed-off-by: Ahmed Karaman > --- > scripts/performance/topN_perf.py | 174 +++++++++++++++---------------- > 1 file changed, 87 insertions(+), 87 deletions(-) > > diff --git a/scripts/performance/topN_perf.py b/scripts/performance/topN_ > perf.py > index 07be195fc8..56b100da87 100755 > --- a/scripts/performance/topN_perf.py > +++ b/scripts/performance/topN_perf.py > @@ -1,72 +1,77 @@ > #!/usr/bin/env python3 > > -# Print the top N most executed functions in QEMU using perf. > -# Syntax: > -# topN_perf.py [-h] [-n] -- \ > -# [] \ > -# [] > -# > -# [-h] - Print the script arguments help message. > -# [-n] - Specify the number of top functions to print. > -# - If this flag is not specified, the tool defaults to 25. > -# > -# Example of usage: > -# topN_perf.py -n 20 -- qemu-arm coulomb_double-arm > -# > -# This file is a part of the project "TCG Continuous Benchmarking". > -# > -# Copyright (C) 2020 Ahmed Karaman > -# Copyright (C) 2020 Aleksandar Markovic 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 . > +""" > +Print the top N most executed functions in QEMU using perf. > + > +Syntax: > +topN_perf.py [-h] [-n ] -- \ > + [] \ > + [] > + > +[-h] - Print the script arguments help message. > +[-n] - Specify the number of top functions to print. > + - If this flag is not specified, the tool defaults to 25. > + > +Example of usage: > +topN_perf.py -n 20 -- qemu-arm coulomb_double-arm > + > +This file is a part of the project "TCG Continuous Benchmarking". > + > +Copyright (C) 2020 Ahmed Karaman > +Copyright (C) 2020 Aleksandar Markovic > + > +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 . > +""" > > import argparse > import os > import subprocess > import sys > +import tempfile > > > # Parse the command line arguments > -parser =3D argparse.ArgumentParser( > - usage=3D'topN_perf.py [-h] [-n] > -- ' > +PARSER =3D argparse.ArgumentParser( > + usage=3D'topN_perf.py [-h] [-n ] = -- ' > ' [] ' > ' []') > > -parser.add_argument('-n', dest=3D'top', type=3Dint, default=3D25, > +PARSER.add_argument('-n', dest=3D'top', type=3Dint, default=3D25, > help=3D'Specify the number of top functions to print= .') > > -parser.add_argument('command', type=3Dstr, nargs=3D'+', > help=3Dargparse.SUPPRESS) > +PARSER.add_argument('command', type=3Dstr, nargs=3D'+', > help=3Dargparse.SUPPRESS) > > -args =3D parser.parse_args() > +ARGS =3D PARSER.parse_args() > > # Extract the needed variables from the args > -command =3D args.command > -top =3D args.top > +COMMAND =3D ARGS.command > +TOP =3D ARGS.top > > # Insure that perf is installed > -check_perf_presence =3D subprocess.run(["which", "perf"], > - stdout=3Dsubprocess.DEVNULL) > -if check_perf_presence.returncode: > +CHECK_PERF_PRESENCE =3D subprocess.run(["which", "perf"], > + stdout=3Dsubprocess.DEVNULL, > + check=3DFalse) > +if CHECK_PERF_PRESENCE.returncode: > sys.exit("Please install perf before running the script!") > > # Insure user has previllage to run perf > -check_perf_executability =3D subprocess.run(["perf", "stat", "ls", "/"], > +CHECK_PERF_EXECUTABILITY =3D subprocess.run(["perf", "stat", "ls", "/"], > stdout=3Dsubprocess.DEVNULL, > - stderr=3Dsubprocess.DEVNULL) > -if check_perf_executability.returncode: > - sys.exit( > -""" > + stderr=3Dsubprocess.DEVNULL, > + check=3DFalse) > +if CHECK_PERF_EXECUTABILITY.returncode: > + sys.exit(""" > Error: > You may not have permission to collect stats. > > @@ -85,43 +90,42 @@ To make this setting permanent, edit /etc/sysctl.conf > too, e.g.: > kernel.perf_event_paranoid =3D -1 > > * Alternatively, you can run this script under sudo privileges. > -""" > -) > - > -# Run perf record > -perf_record =3D subprocess.run((["perf", "record", > "--output=3D/tmp/perf.data"] + > - command), > - stdout=3Dsubprocess.DEVNULL, > - stderr=3Dsubprocess.PIPE) > -if perf_record.returncode: > - os.unlink('/tmp/perf.data') > - sys.exit(perf_record.stderr.decode("utf-8")) > - > -# Save perf report output to /tmp/perf_report.out > -with open("/tmp/perf_report.out", "w") as output: > - perf_report =3D subprocess.run( > - ["perf", "report", "--input=3D/tmp/perf.data", "--stdio"], > - stdout=3Doutput, > - stderr=3Dsubprocess.PIPE) > - if perf_report.returncode: > - os.unlink('/tmp/perf.data') > - output.close() > - os.unlink('/tmp/perf_report.out') > - sys.exit(perf_report.stderr.decode("utf-8")) > - > -# Read the reported data to functions[] > -functions =3D [] > -with open("/tmp/perf_report.out", "r") as data: > - # Only read lines that are not comments (comments start with #) > - # Only read lines that are not empty > - functions =3D [line for line in data.readlines() if line and line[0] > - !=3D '#' and line[0] !=3D "\n"] > - > -# Limit the number of top functions to "top" > -number_of_top_functions =3D top if len(functions) > top else len(functio= ns) > - > -# Store the data of the top functions in top_functions[] > -top_functions =3D functions[:number_of_top_functions] > +""") > + > +# Run perf and save all intermediate files in a temporary directory > +with tempfile.TemporaryDirectory() as tmpdir: > + RECORD_PATH =3D os.path.join(tmpdir, "record.data") > + REPORT_PATH =3D os.path.join(tmpdir, "report.txt") > + > + PERF_RECORD =3D subprocess.run((["perf", "record", > "--output=3D"+RECORD_PATH] + > + COMMAND), > + stdout=3Dsubprocess.DEVNULL, > + stderr=3Dsubprocess.PIPE, > + check=3DFalse) > + if PERF_RECORD.returncode: > + sys.exit(PERF_RECORD.stderr.decode("utf-8")) > + > + with open(REPORT_PATH, "w") as output: > + PERF_REPORT =3D subprocess.run( > + ["perf", "report", "--input=3D"+RECORD_PATH, "--stdio"], > + stdout=3Doutput, > + stderr=3Dsubprocess.PIPE, > + check=3DFalse) > + if PERF_REPORT.returncode: > + sys.exit(PERF_REPORT.stderr.decode("utf-8")) > + > + # Save the reported data to FUNCTIONS[] > + with open(REPORT_PATH, "r") as data: > + # Only read lines that are not comments (comments start with #) > + # Only read lines that are not empty > + FUNCTIONS =3D [line for line in data.readlines() if line and > + line[0] !=3D '#' and line[0] !=3D "\n"] > + > +# Limit the number of top functions to "TOP" > +NO_TOP_FUNCTIONS =3D TOP if len(FUNCTIONS) > TOP else len(FUNCTIONS) > + > +# Store the data of the top functions in TOP_FUNCTIONS[] > +TOP_FUNCTIONS =3D FUNCTIONS[:NO_TOP_FUNCTIONS] > > # Print table header > print('{:>4} {:>10} {:<30} {}\n{} {} {} {}'.format('No.', > @@ -134,7 +138,7 @@ print('{:>4} {:>10} {:<30} {}\n{} {} {} > {}'.format('No.', > '-' * 25)) > > # Print top N functions > -for (index, function) in enumerate(top_functions, start=3D1): > +for (index, function) in enumerate(TOP_FUNCTIONS, start=3D1): > function_data =3D function.split() > function_percentage =3D function_data[0] > function_name =3D function_data[-1] > @@ -143,7 +147,3 @@ for (index, function) in enumerate(top_functions, > start=3D1): > function_percentage, > function_name, > function_invoker)) > - > -# Remove intermediate files > -os.unlink('/tmp/perf.data') > -os.unlink('/tmp/perf_report.out') > -- > 2.17.1 > > --000000000000afdbe605aebf6523 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable

On Friday, August 28, 2020, Ahmed Karaman <ahmedkhaledkaraman@gmail.com> wrote:
<= blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px= #ccc solid;padding-left:1ex">- Apply pylint and flake8 formatting rules to= the script.
- Use 'tempfile' instead of '/tmp' for creating temporary f= iles.


Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com&= gt;
<= /div>
Reply
Reply= all
Forward<= /div>
View Gmail in:=C2=A0Mobile=C2= =A0|=C2=A0Older versio= n=C2=A0|=C2=A0Desk= top
=C2=A9 2020 Google
=
=C2=A0
Signed-off-by: Ahmed Karaman <ahmedkhaledkaraman@gmail.com>
---
=C2=A0scripts/performance/topN_perf.py | 174 +++++++++++++++----------= ------
=C2=A01 file changed, 87 insertions(+), 87 deletions(-)

diff --git a/scripts/performance/topN_perf.py b/scripts/performance/to= pN_perf.py
index 07be195fc8..56b100da87 100755
--- a/scripts/performance/topN_perf.py
+++ b/scripts/performance/topN_perf.py
@@ -1,72 +1,77 @@
=C2=A0#!/usr/bin/env python3

-#=C2=A0 Print the top N most executed functions in QEMU using perf.
-#=C2=A0 Syntax:
-#=C2=A0 topN_perf.py [-h] [-n] <number of displayed top functions>= =C2=A0 -- \
-#=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<qemu executable> [<qem= u executable options>] \
-#=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<target executable> [<t= arget execurable options>]
-#
-#=C2=A0 [-h] - Print the script arguments help message.
-#=C2=A0 [-n] - Specify the number of top functions to print.
-#=C2=A0 =C2=A0 =C2=A0 =C2=A0- If this flag is not specified, the tool defa= ults to 25.
-#
-#=C2=A0 Example of usage:
-#=C2=A0 topN_perf.py -n 20 -- qemu-arm coulomb_double-arm
-#
-#=C2=A0 This file is a part of the project "TCG Continuous Benchmarki= ng".
-#
-#=C2=A0 Copyright (C) 2020=C2=A0 Ahmed Karaman <ahmedkhaledkaraman@gmail.com>
-#=C2=A0 Copyright (C) 2020=C2=A0 Aleksandar Markovic <aleksandar.qemu.devel@gmail.com&= gt;
-#
-#=C2=A0 This program is free software: you can redistribute it and/or modi= fy
-#=C2=A0 it under the terms of the GNU General Public License as published = by
-#=C2=A0 the Free Software Foundation, either version 2 of the License, or<= br> -#=C2=A0 (at your option) any later version.
-#
-#=C2=A0 This program is distributed in the hope that it will be useful, -#=C2=A0 but WITHOUT ANY WARRANTY; without even the implied warranty of
-#=C2=A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-#=C2=A0 GNU General Public License for more details.
-#
-#=C2=A0 You should have received a copy of the GNU General Public License<= br> -#=C2=A0 along with this program. If not, see <https://www.gnu.org/licenses/&g= t;.
+"""
+Print the top N most executed functions in QEMU using perf.
+
+Syntax:
+topN_perf.py [-h] [-n <number of displayed top functions>] -- \
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<qemu executable> [<qemu execut= able options>] \
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<target executable> [<target ex= ecurable options>]
+
+[-h] - Print the script arguments help message.
+[-n] - Specify the number of top functions to print.
+=C2=A0 =C2=A0 =C2=A0- If this flag is not specified, the tool defaults to = 25.
+
+Example of usage:
+topN_perf.py -n 20 -- qemu-arm coulomb_double-arm
+
+This file is a part of the project "TCG Continuous Benchmarking"= .
+
+Copyright (C) 2020=C2=A0 Ahmed Karaman <ahmedkhaledkaraman@gmail.com>
+Copyright (C) 2020=C2=A0 Aleksandar Markovic <aleksandar.qemu.devel@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/>.
+"""

=C2=A0import argparse
=C2=A0import os
=C2=A0import subprocess
=C2=A0import sys
+import tempfile


=C2=A0# Parse the command line arguments
-parser =3D argparse.ArgumentParser(
-=C2=A0 =C2=A0 usage=3D'topN_perf.py [-h] [-n] <number of displayed = top functions >=C2=A0 -- '
+PARSER =3D argparse.ArgumentParser(
+=C2=A0 =C2=A0 usage=3D'topN_perf.py [-h] [-n <number of displayed t= op functions>] -- '
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'<qemu executable> [<= qemu executable options>] '
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'<target executable> [&l= t;target executable options>]')

-parser.add_argument('-n', dest=3D'top', type=3Dint, defaul= t=3D25,
+PARSER.add_argument('-n', dest=3D'top', type=3Dint, defaul= t=3D25,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0help=3D'Specify the number of top functions to print.')

-parser.add_argument('command', type=3Dstr, nargs=3D'+'= ;, help=3Dargparse.SUPPRESS)
+PARSER.add_argument('command', type=3Dstr, nargs=3D'+'= ;, help=3Dargparse.SUPPRESS)

-args =3D parser.parse_args()
+ARGS =3D PARSER.parse_args()

=C2=A0# Extract the needed variables from the args
-command =3D args.command
-top =3D args.top
+COMMAND =3D ARGS.command
+TOP =3D ARGS.top

=C2=A0# Insure that perf is installed
-check_perf_presence =3D subprocess.run(["which", "perf"= ;],
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0stdout=3Dsubproc= ess.DEVNULL)
-if check_perf_presence.returncode:
+CHECK_PERF_PRESENCE =3D subprocess.run(["which", "perf"= ;],
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0stdout=3Dsubproc= ess.DEVNULL,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0check=3DFalse) +if CHECK_PERF_PRESENCE.returncode:
=C2=A0 =C2=A0 =C2=A0sys.exit("Please install perf before running the s= cript!")

=C2=A0# Insure user has previllage to run perf
-check_perf_executability =3D subprocess.run(["perf", "stat&= quot;, "ls", "/"],
+CHECK_PERF_EXECUTABILITY =3D subprocess.run(["perf", "stat&= quot;, "ls", "/"],
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0stdout=3Dsubprocess.DEVNULL,
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 s= tderr=3Dsubprocess.DEVNULL)
-if check_perf_executability.returncode:
-=C2=A0 =C2=A0 sys.exit(
-"""
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 s= tderr=3Dsubprocess.DEVNULL,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 c= heck=3DFalse)
+if CHECK_PERF_EXECUTABILITY.returncode:
+=C2=A0 =C2=A0 sys.exit("""
=C2=A0Error:
=C2=A0You may not have permission to collect stats.

@@ -85,43 +90,42 @@ To make this setting permanent, edit /etc/sysctl.conf t= oo, e.g.:
=C2=A0 =C2=A0 kernel.perf_event_paranoid =3D -1

=C2=A0* Alternatively, you can run this script under sudo privileges.
-"""
-)
-
-# Run perf record
-perf_record =3D subprocess.run((["perf", "record", &qu= ot;--output=3D/tmp/perf.data"] +
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 command),
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0stdout=3Dsubprocess.DEVNULL,
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0stderr=3Dsubprocess.PIPE)
-if perf_record.returncode:
-=C2=A0 =C2=A0 os.unlink('/tmp/perf.data')
-=C2=A0 =C2=A0 sys.exit(perf_record.stderr.decode("utf-8"))<= br> -
-# Save perf report output to /tmp/perf_report.out
-with open("/tmp/perf_report.out", "w") as output:
-=C2=A0 =C2=A0 perf_report =3D subprocess.run(
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 ["perf", "report", "-= -input=3D/tmp/perf.data", "--stdio"],
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 stdout=3Doutput,
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 stderr=3Dsubprocess.PIPE)
-=C2=A0 =C2=A0 if perf_report.returncode:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 os.unlink('/tmp/perf.data')
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 output.close()
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 os.unlink('/tmp/perf_report.out')=
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 sys.exit(perf_report.stderr.decode("= utf-8"))
-
-# Read the reported data to functions[]
-functions =3D []
-with open("/tmp/perf_report.out", "r") as data:
-=C2=A0 =C2=A0 # Only read lines that are not comments (comments start with= #)
-=C2=A0 =C2=A0 # Only read lines that are not empty
-=C2=A0 =C2=A0 functions =3D [line for line in data.readlines() if line and= line[0]
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0!=3D '#&= #39; and line[0] !=3D "\n"]
-
-# Limit the number of top functions to "top"
-number_of_top_functions =3D top if len(functions) > top else len(functi= ons)
-
-# Store the data of the top functions in top_functions[]
-top_functions =3D functions[:number_of_top_functions]
+""")
+
+# Run perf and save all intermediate files in a temporary directory
+with tempfile.TemporaryDirectory() as tmpdir:
+=C2=A0 =C2=A0 RECORD_PATH =3D os.path.join(tmpdir, "record.data"= )
+=C2=A0 =C2=A0 REPORT_PATH =3D os.path.join(tmpdir, "report.txt")=
+
+=C2=A0 =C2=A0 PERF_RECORD =3D subprocess.run((["perf", "rec= ord", "--output=3D"+RECORD_PATH] +
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 COMMAND),
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0stdout=3Dsubprocess.DEVNULL, +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0stderr=3Dsubprocess.PIPE,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0check=3DFalse)
+=C2=A0 =C2=A0 if PERF_RECORD.returncode:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 sys.exit(PERF_RECORD.stderr.decode("= utf-8"))
+
+=C2=A0 =C2=A0 with open(REPORT_PATH, "w") as output:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 PERF_REPORT =3D subprocess.run(
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ["perf", "report&= quot;, "--input=3D"+RECORD_PATH, "--stdio"],
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 stdout=3Doutput,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 stderr=3Dsubprocess.PIPE,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 check=3DFalse)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 if PERF_REPORT.returncode:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sys.exit(PERF_REPORT.stderr.decode("utf-8"))
+
+=C2=A0 =C2=A0 # Save the reported data to FUNCTIONS[]
+=C2=A0 =C2=A0 with open(REPORT_PATH, "r") as data:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 # Only read lines that are not comments (comme= nts start with #)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 # Only read lines that are not empty
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 FUNCTIONS =3D [line for line in data.readlines= () if line and
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0line[0] !=3D '#' and line[0] !=3D "\n"]
+
+# Limit the number of top functions to "TOP"
+NO_TOP_FUNCTIONS =3D TOP if len(FUNCTIONS) > TOP else len(FUNCTIONS) +
+# Store the data of the top functions in TOP_FUNCTIONS[]
+TOP_FUNCTIONS =3D FUNCTIONS[:NO_TOP_FUNCTIONS]

=C2=A0# Print table header
=C2=A0print('{:>4}=C2=A0 {:>10}=C2=A0 {:<30}=C2=A0 {}\n{}=C2= =A0 {}=C2=A0 {}=C2=A0 {}'.format('No.',
@@ -134,7 +138,7 @@ print('{:>4}=C2=A0 {:>10}=C2=A0 {:<30}=C2= =A0 {}\n{}=C2=A0 {}=C2=A0 {}=C2=A0 {}'.format('No.',
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 '-' * 25))<= br>
=C2=A0# Print top N functions
-for (index, function) in enumerate(top_functions, start=3D1):
+for (index, function) in enumerate(TOP_FUNCTIONS, start=3D1):
=C2=A0 =C2=A0 =C2=A0function_data =3D function.split()
=C2=A0 =C2=A0 =C2=A0function_percentage =3D function_data[0]
=C2=A0 =C2=A0 =C2=A0function_name =3D function_data[-1]
@@ -143,7 +147,3 @@ for (index, function) in enumerate(top_functions, start= =3D1):
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 function_percentage,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 function_name,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 function_invoker))
-
-# Remove intermediate files
-os.unlink('/tmp/perf.data')
-os.unlink('/tmp/perf_report.out')
--
2.17.1

--000000000000afdbe605aebf6523--