From nobody Fri Sep 12 01:11:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED258EB64DD for ; Wed, 9 Aug 2023 13:21:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232874AbjHINVg (ORCPT ); Wed, 9 Aug 2023 09:21:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42924 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231527AbjHINVd (ORCPT ); Wed, 9 Aug 2023 09:21:33 -0400 Received: from mail-pf1-x42d.google.com (mail-pf1-x42d.google.com [IPv6:2607:f8b0:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3E4B1C1; Wed, 9 Aug 2023 06:21:32 -0700 (PDT) Received: by mail-pf1-x42d.google.com with SMTP id d2e1a72fcca58-686fc0d3c92so4648020b3a.0; Wed, 09 Aug 2023 06:21:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1691587292; x=1692192092; h=content-disposition:mime-version:message-id:subject:to:from:date :from:to:cc:subject:date:message-id:reply-to; bh=9ixXrYInOwbnust1iCQWifpopRByO26tK6/cFi3PNE8=; b=kpQ6Nb+Lm3xixX/liDhf+kh7rGU/z48VcDL7x9xYH0yep0DzjCAgqWS9h0EI4c2cA8 nHqE0R5rQqYyStNvEZMwgNm7r9CFWTm3KuvYv7cwpuTk5Aepj1GcIVlS1Xl8utEvY+bS sZsikb/6c/ddTR4rAnZdZ1c91ZRYh9KF/dQS50QuH30CFAjpPbsdBGI4aj+U1EcyxmMg 6KDhPioxt6EIEd4p8UETeJHTeL+8NMdmpDwFKRkaRmktAoBbFMVIXAWbdZLzGUFYp2h3 OyUyZNEBQ97DPQydgrZS+HYqilCt/yfiEZvtAObG23ijRXf1a22CynunynNGdBJFW/7A pHKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1691587292; x=1692192092; h=content-disposition:mime-version:message-id:subject:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=9ixXrYInOwbnust1iCQWifpopRByO26tK6/cFi3PNE8=; b=TCwxZNCj5zdqbOFuvaiP9AWrowirl8J4NAYbiXuxCUaclXJBV/vIFGYA3GWXHIKBBn Q9GzpRGAI0NxJ8q83dnOVSu/Dij0ZynQ9DptErtC5a5qmQ73zBiuZeHVArTdqlXnsfsf pvmYyQcyBi9nC39qRbJKWI3rMj1ajG+6CBHVSv4r7SsZILcLMA150uFe3lZnMTPPQDcr qNzQRLOt7fjW0DhMd1UQv2Aljdrie5pFAYV/i5sI5wvaq4efNd9ivPW0o9Yqzwn+Yav2 sawUAzzch/HJaM++KGFK7KjMn6N+JTui2JsDfaj3EDCrDuIbSMy4awIygx0PXHryTsN8 q/2g== X-Gm-Message-State: AOJu0YxPNW0aXhMdcXwCmJfkPI5L1t3Mcg+2TK9CgIYBGSCy45Jod+pp 3aj9ze+FpN0RU/KE2dDPYRxxmbLsPlqksCn6 X-Google-Smtp-Source: AGHT+IFFDWFxqVeSFefqRMfIg9pubGdTS9x7sHORAEl/6a4eZ7lxUSbf8NwRjir+bpnssKyQDkK9jQ== X-Received: by 2002:a05:6a20:8427:b0:13b:a4fd:3017 with SMTP id c39-20020a056a20842700b0013ba4fd3017mr2952205pzd.46.1691587291362; Wed, 09 Aug 2023 06:21:31 -0700 (PDT) Received: from yoga ([202.131.132.149]) by smtp.gmail.com with ESMTPSA id j18-20020a62b612000000b00677af363905sm9870810pff.59.2023.08.09.06.21.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 09 Aug 2023 06:21:31 -0700 (PDT) Date: Wed, 9 Aug 2023 18:51:22 +0530 From: Anup Sharma To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Ian Rogers , Adrian Hunter , Anup Sharma , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RESEND PATCH] perf scripts python: launch the profiler UI on the default browser with the appropriate URL Message-ID: MIME-Version: 1.0 Content-Disposition: inline Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" All required libraries have been imported and make sure that none of them are external dependencies. To achieve this, created a virt env and verified. Modified usage information and added combined command. Modified the main() function to read the --save-only command-line option and set the output_file variable accordingly. Modified the trace_end() function to check for the output_file variable. If it is set, the profiler data is saved to a local file in Gecko Profile format, or the profiler.firefox.com is opened on the default browse= r. Included trace_begin() to initialize the Firefox Profiler and launch the default browser to display the profiler.firefox.com. Added a new function launchFirefox() to start a local server and launch the profiler UI on the default browser with the appropriate URL. Created the "CORSRequestHandler" class to enable Cross-Origin Resource Shar= ing. Summary: This integration now includes a exiting feature to conveniently host the Gecko Profile data on a local server and open it directly in the default web browser. This means that users can now effortlessly visualize and analyze the profiler results with just a single click. The addition of the --save-only command-line option allows users to save the profiler output to a local file in Gecko Profile format, but the real highlight lies in the capability to seamlessly launch a local server, making the data accessible to Firefox Profiler via a web browser. In addition, it's important to highlight that all data are hosted locally, eliminating any concerns about data privacy rules and regulations. Signed-off-by: Anup Sharma Tested-by: Ian Rogers --- tools/perf/scripts/python/gecko.py | 70 +++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/tools/perf/scripts/python/gecko.py b/tools/perf/scripts/python= /gecko.py index 278c3aed282a..bc5a72f94bfa 100644 --- a/tools/perf/scripts/python/gecko.py +++ b/tools/perf/scripts/python/gecko.py @@ -1,4 +1,4 @@ -# firefox-gecko-converter.py - Convert perf record output to Firefox's gec= ko profile format +# gecko.py - Convert perf record output to Firefox's gecko profile format # SPDX-License-Identifier: GPL-2.0 # # The script converts perf.data to Gecko Profile Format, @@ -7,14 +7,26 @@ # Usage: # # perf record -a -g -F 99 sleep 60 -# perf script report gecko > output.json +# perf script report gecko +# +# Combined: +# +# perf script gecko -F 99 -a sleep 60 =20 import os import sys +import time import json +import string +import random import argparse +import threading +import webbrowser +import urllib.parse +from os import system from functools import reduce from dataclasses import dataclass, field +from http.server import HTTPServer, SimpleHTTPRequestHandler, test from typing import List, Dict, Optional, NamedTuple, Set, Tuple, Any =20 # Add the Perf-Trace-Util library to the Python path @@ -40,9 +52,15 @@ CATEGORIES =3D None # The product name is used by the profiler UI to show the Operating system= and Processor. PRODUCT =3D os.popen('uname -op').read().strip() =20 +# store the output file +output_file =3D None + # Here key =3D tid, value =3D Thread tid_to_thread =3D dict() =20 +# The HTTP server is used to serve the profile to the profiler UI. +http_server_thread =3D None + # The category index is used by the profiler UI to show the color of the f= lame graph. USER_CATEGORY_INDEX =3D 0 KERNEL_CATEGORY_INDEX =3D 1 @@ -278,9 +296,19 @@ def process_event(param_dict: Dict) -> None: tid_to_thread[tid] =3D thread thread._add_sample(comm=3Dcomm, stack=3Dstack, time_ms=3Dtime_stamp) =20 +def trace_begin() -> None: + global output_file + if (output_file is None): + print("Staring Firefox Profiler on your default browser...") + global http_server_thread + http_server_thread =3D threading.Thread(target=3Dtest, args=3D(CORSReque= stHandler, HTTPServer,)) + http_server_thread.daemon =3D True + http_server_thread.start() + # Trace_end runs at the end and will be used to aggregate # the data into the final json object and print it out to stdout. def trace_end() -> None: + global output_file threads =3D [thread._to_json_dict() for thread in tid_to_thread.values()] =20 # Schema: https://github.com/firefox-devtools/profiler/blob/53970305b51b9= b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L305 @@ -305,22 +333,50 @@ def trace_end() -> None: "processes": [], "pausedRanges": [], } - json.dump(gecko_profile_with_meta, sys.stdout, indent=3D2) + # launch the profiler on local host if not specified --save-only args, ot= herwise print to file + if (output_file is None): + output_file =3D 'gecko_profile.json' + with open(output_file, 'w') as f: + json.dump(gecko_profile_with_meta, f, indent=3D2) + launchFirefox(output_file) + time.sleep(1) + print(f'[ perf gecko: Captured and wrote into {output_file} ]') + else: + print(f'[ perf gecko: Captured and wrote into {output_file} ]') + with open(output_file, 'w') as f: + json.dump(gecko_profile_with_meta, f, indent=3D2) + +# Used to enable Cross-Origin Resource Sharing (CORS) for requests coming = from 'https://profiler.firefox.com', allowing it to access resources from t= his server. +class CORSRequestHandler(SimpleHTTPRequestHandler): + def end_headers (self): + self.send_header('Access-Control-Allow-Origin', 'https://profiler.firefo= x.com') + SimpleHTTPRequestHandler.end_headers(self) + +# start a local server to serve the gecko_profile.json file to the profile= r.firefox.com +def launchFirefox(file): + safe_string =3D urllib.parse.quote_plus(f'http://localhost:8000/{file}') + url =3D 'https://profiler.firefox.com/from-url/' + safe_string + webbrowser.open(f'{url}') =20 def main() -> None: + global output_file global CATEGORIES - parser =3D argparse.ArgumentParser(description=3D"Convert perf.data to Fi= refox\'s Gecko Profile format") + parser =3D argparse.ArgumentParser(description=3D"Convert perf.data to Fi= refox\'s Gecko Profile format which can be uploaded to profiler.firefox.com= for visualization") =20 # Add the command-line options # Colors must be defined according to this: # https://github.com/firefox-devtools/profiler/blob/50124adbfa488adba6e26= 74a8f2618cf34b59cd2/res/css/categories.css - parser.add_argument('--user-color', default=3D'yellow', help=3D'Color for= the User category') - parser.add_argument('--kernel-color', default=3D'orange', help=3D'Color f= or the Kernel category') + parser.add_argument('--user-color', default=3D'yellow', help=3D'Color for= the User category', choices=3D['yellow', 'blue', 'purple', 'green', 'orang= e', 'red', 'grey', 'magenta']) + parser.add_argument('--kernel-color', default=3D'orange', help=3D'Color f= or the Kernel category', choices=3D['yellow', 'blue', 'purple', 'green', 'o= range', 'red', 'grey', 'magenta']) + # If --save-only is specified, the output will be saved to a file instead= of opening Firefox's profiler directly. + parser.add_argument('--save-only', help=3D'Save the output to a file inst= ead of opening Firefox\'s profiler') + # Parse the command-line arguments args =3D parser.parse_args() # Access the values provided by the user user_color =3D args.user_color kernel_color =3D args.kernel_color + output_file =3D args.save_only =20 CATEGORIES =3D [ { @@ -336,4 +392,4 @@ def main() -> None: ] =20 if __name__ =3D=3D '__main__': - main() + main() --=20 2.34.1