Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  android_emulator_pgo.py

  Sprache: Python
 

#!/usr/bin/env python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

import copy
import glob
import json
import os
import posixpath
import subprocess
import sys
import time

# load modules from parent dir
sys.path.insert(1, os.path.dirname(sys.path[0]))

from mozharness.base.script import BaseScript, PreScriptAction
from mozharness.mozilla.automation import EXIT_STATUS_DICT, TBPL_RETRY
from mozharness.mozilla.mozbase import MozbaseMixin
from mozharness.mozilla.testing.android import AndroidMixin
from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options

PAGES = [
    "js-input/webkit/PerformanceTests/Speedometer/index.html",
    "js-input/webkit/PerformanceTests/Speedometer3/index.html?startAutomatically=true",
    # TODO: Add support for the pgo-extended-corpus to get JetStream3 running here.
    "blueprint/sample.html",
    "blueprint/forms.html",
    "blueprint/grid.html",
    "blueprint/elements.html",
    "js-input/3d-thingy.html",
    "js-input/crypto-otp.html",
    "js-input/collator_bench.html",
    "js-input/normalizer_bench.html",
    "js-input/sunspider/3d-cube.html",
    "js-input/sunspider/3d-morph.html",
    "js-input/sunspider/3d-raytrace.html",
    "js-input/sunspider/access-binary-trees.html",
    "js-input/sunspider/access-fannkuch.html",
    "js-input/sunspider/access-nbody.html",
    "js-input/sunspider/access-nsieve.html",
    "js-input/sunspider/bitops-3bit-bits-in-byte.html",
    "js-input/sunspider/bitops-bits-in-byte.html",
    "js-input/sunspider/bitops-bitwise-and.html",
    "js-input/sunspider/bitops-nsieve-bits.html",
    "js-input/sunspider/controlflow-recursive.html",
    "js-input/sunspider/crypto-aes.html",
    "js-input/sunspider/crypto-md5.html",
    "js-input/sunspider/crypto-sha1.html",
    "js-input/sunspider/date-format-tofte.html",
    "js-input/sunspider/date-format-xparb.html",
    "js-input/sunspider/math-cordic.html",
    "js-input/sunspider/math-partial-sums.html",
    "js-input/sunspider/math-spectral-norm.html",
    "js-input/sunspider/regexp-dna.html",
    "js-input/sunspider/string-base64.html",
    "js-input/sunspider/string-fasta.html",
    "js-input/sunspider/string-tagcloud.html",
    "js-input/sunspider/string-unpack-code.html",
    "js-input/sunspider/string-validate-input.html",
]


class AndroidProfileRun(TestingMixin, BaseScript, MozbaseMixin, AndroidMixin):
    """
    Mozharness script to generate an android PGO profile using the emulator
    """

    config_options = copy.deepcopy(testing_config_options)

    def __init__(self, require_config_file=False):
        super().__init__(
            config_options=self.config_options,
            all_actions=[
                "download",
                "create-virtualenv",
                "start-emulator",
                "verify-device",
                "install",
                "run-tests",
            ],
            require_config_file=require_config_file,
            config={
                "virtualenv_modules": [],
                "virtualenv_requirements": [],
                "require_test_zip"True,
                "mozbase_requirements""mozbase_source_requirements.txt",
            },
        )

        # these are necessary since self.config is read only
        c = self.config
        self.installer_path = c.get("installer_path")
        self.device_serial = "emulator-5554"

    def query_abs_dirs(self):
        if self.abs_dirs:
            return self.abs_dirs
        abs_dirs = super().query_abs_dirs()
        dirs = {}

        dirs["abs_test_install_dir"] = os.path.join(abs_dirs["abs_src_dir"], "testing")
        # On macOS, use checkout dir; on Linux, use /builds/worker
        if sys.platform == "darwin":
            base_dir = abs_dirs["abs_src_dir"]
        else:
            base_dir = "/builds/worker"
        dirs["abs_artifacts_dir"] = os.path.join(base_dir, "artifacts")
        dirs["abs_blob_upload_dir"] = os.path.join(
            dirs["abs_artifacts_dir"], "blobber_upload_dir"
        )
        dirs["abs_workspace_dir"] = os.path.join(base_dir, "workspace")
        work_dir = os.environ.get("MOZ_FETCHES_DIR"or abs_dirs["abs_work_dir"]
        dirs["abs_xre_dir"] = os.path.join(work_dir, "hostutils")
        sdk_dirname = (
            "android-sdk-macosx" if sys.platform == "darwin" else "android-sdk-linux"
        )
        dirs["abs_sdk_dir"] = os.path.join(work_dir, sdk_dirname)
        dirs["abs_avds_dir"] = os.path.join(work_dir, "android-device")
        dirs["abs_bundletool_path"] = os.path.join(work_dir, "bundletool.jar")

        for key in dirs.keys():
            if key not in abs_dirs:
                abs_dirs[key] = dirs[key]
        self.abs_dirs = abs_dirs
        return self.abs_dirs

    ##########################################
    # Actions for AndroidProfileRun        #
    ##########################################

    def preflight_install(self):
        # in the base class, this checks for mozinstall, but we don't use it
        pass

    @PreScriptAction("create-virtualenv")
    def pre_create_virtualenv(self, action):
        dirs = self.query_abs_dirs()
        self.register_virtualenv_module(
            "marionette",
            os.path.join(dirs["abs_test_install_dir"], "marionette""client"),
        )

    def download(self):
        """
        Download host utilities
        """
        dirs = self.query_abs_dirs()
        self.xre_path = dirs["abs_xre_dir"]

    def install(self):
        """
        Install APKs on the device.
        """
        assert self.installer_path is not None, (
            "Either add installer_path to the config or use --installer-path."
        )
        self.install_android_app(self.installer_path)
        self.info("Finished installing apps for %s" % self.device_serial)

    def _wait_for_process(self, adbdevice, process_name, running, timeout=10):
        deadline = time.monotonic() + timeout
        while time.monotonic() < deadline:
            try:
                output = adbdevice.shell_output(f"pgrep {process_name}").strip()
                found = bool(output)
            except Exception:
                found = False
            if found == running:
                return True
            time.sleep(0.5)
        return False

    def _stop_and_pull_recording(self, adbdevice, recording_path, video_filename):
        try:
            self.info("Stopping screen recording...")
            try:
                adbdevice.shell_output("pkill -SIGINT screenrecord", timeout=30)
            except Exception:
                # pkill exits with 1 if no process was found; ignore and still pull
                pass
            if not self._wait_for_process(
                adbdevice, "screenrecord", running=False, timeout=15
            ):
                self.warning("Timed out waiting for screenrecord to stop")
            dirs = self.query_abs_dirs()
            blob_dir = dirs["abs_blob_upload_dir"]
            os.makedirs(blob_dir, exist_ok=True)
            video_dest = os.path.join(blob_dir, video_filename)
            adbdevice.pull(recording_path, video_dest)
            self.info(f"Screen recording saved to {video_dest}")
            adbdevice.shell_output(f"rm {recording_path}")
        except Exception as e:
            self.warning(f"Failed to stop/pull screen recording: {e}")

    def run_tests(self):
        """
        Generate the PGO profile data
        """
        from marionette_driver.marionette import Marionette
        from mozdevice import ADBDeviceFactory, ADBTimeoutError
        from mozhttpd import MozHttpd
        from mozprofile import Preferences

        app = self.query_package_name()

        IP = "10.0.2.2"
        PORT = 8888

        PATH_MAPPINGS = {
            "/js-input/webkit/PerformanceTests""third_party/webkit/PerformanceTests",
        }

        dirs = self.query_abs_dirs()
        topsrcdir = dirs["abs_src_dir"]
        adb = self.query_exe("adb")

        path_mappings = {
            k: os.path.join(topsrcdir, v) for k, v in PATH_MAPPINGS.items()
        }
        httpd = MozHttpd(
            port=PORT,
            docroot=os.path.join(topsrcdir, "build""pgo"),
            path_mappings=path_mappings,
        )
        httpd.start(block=False)

        profile_data_dir = os.path.join(topsrcdir, "testing""profiles")
        with open(os.path.join(profile_data_dir, "profiles.json")) as fh:
            base_profiles = json.load(fh)["profileserver"]

        prefpaths = [
            os.path.join(profile_data_dir, profile, "user.js")
            for profile in base_profiles
        ]

        prefs = {}
        for path in prefpaths:
            prefs.update(Preferences.read_prefs(path))

        interpolation = {"server""%s:%d" % httpd.httpd.server_address, "OOP""false"}
        for k, v in prefs.items():
            if isinstance(v, str):
                v = v.format(**interpolation)
            prefs[k] = Preferences.cast(v)

        adbdevice = ADBDeviceFactory(adb=adb, device="emulator-5554")

        outputdir = posixpath.join(adbdevice.test_root, "pgo_profile")
        jarlog = posixpath.join(outputdir, "en-US.log")
        profdata = posixpath.join(outputdir, "default_%p_random_%m.profraw")

        env = {}
        env["XPCOM_DEBUG_BREAK"] = "warn"
        env["MOZ_IN_AUTOMATION"] = "1"
        env["MOZ_JAR_LOG_FILE"] = jarlog
        env["LLVM_PROFILE_FILE"] = profdata

        if self.query_minidump_stackwalk():
            os.environ["MINIDUMP_STACKWALK"] = self.minidump_stackwalk_path
        os.environ["MINIDUMP_SAVE_PATH"] = self.query_abs_dirs()["abs_blob_upload_dir"]
        if not self.symbols_path:
            self.symbols_path = os.environ.get("MOZ_FETCHES_DIR")

        adbdevice.mkdir(outputdir, parents=True)

        # Start screen recording of PGO training
        recording_path = "/sdcard/pgo-training.mp4"
        recording_started = False
        try:
            self.info("Starting screen recording of PGO training session...")
            sdk = int(
                adbdevice.shell_output(
                    "getprop ro.build.version.sdk", timeout=5
                ).strip()
            )
            # --time-limit > 180 is only supported on Android 14 (API 34) and above
            time_limit_arg = "--time-limit 900 " if sdk >= 34 else ""
            adbdevice.shell_output(
                f"sh -c 'screenrecord --verbose {time_limit_arg}{recording_path} > /dev/null 2>&1 &'">,
                timeout=10,
            )
            if self._wait_for_process(
                adbdevice, "screenrecord", running=True, timeout=10
            ):
                recording_started = True
                self.info("Screen recording started")
            else:
                self.warning("screenrecord did not start within timeout")
        except Exception as e:
            self.warning(f"Failed to start screen recording: {e}")

        try:
            # Run Fennec a first time to initialize its profile
            driver = Marionette(
                app="fennec",
                package_name=app,
                adb_path=adb,
                bin="geckoview-androidTest.apk",
                prefs=prefs,
                connect_to_running_emulator=True,
                startup_timeout=1000,
                env=env,
                symbols_path=self.symbols_path,
            )
            driver.start_session()

            # Now generate the profile and wait for it to complete
            for page in PAGES:
                driver.navigate("http://%s:%d/%s" % (IP, PORT, page))
                timeout = 2
                if "Speedometer" in page:
                    # The Speedometer[23] test actually runs many tests internally in
                    # javascript, so it needs extra time to run through them. The
                    # emulator doesn't get very far through the whole suite, but
                    # this extra time at least lets some of them process.
                    timeout = 360
                time.sleep(timeout)

            driver.quit(in_app=True)

            if recording_started:
                self._stop_and_pull_recording(
                    adbdevice, recording_path, "pgo-training.mp4"
                )

            # Pull all the profraw files and en-US.log
            dirs = self.query_abs_dirs()
            workspace_dir = dirs["abs_workspace_dir"]
            os.makedirs(workspace_dir, exist_ok=True)
            adbdevice.pull(outputdir, workspace_dir)
        except ADBTimeoutError:
            if recording_started:
                self._stop_and_pull_recording(
                    adbdevice, recording_path, "pgo-training-partial.mp4"
                )
            self.fatal(
                "INFRA-ERROR: Failed with an ADBTimeoutError",
                EXIT_STATUS_DICT[TBPL_RETRY],
            )

        dirs = self.query_abs_dirs()
        workspace_dir = dirs["abs_workspace_dir"]
        profraw_files = glob.glob(os.path.join(workspace_dir, "*.profraw"))
        if not profraw_files:
            self.fatal(f"Could not find any profraw files in {workspace_dir}")
        elif len(profraw_files) == 1:
            self.fatal(
                "Only found 1 profraw file. Did child processes terminate early?"
            )
        merged_profdata = os.path.join(workspace_dir, "merged.profdata")
        merge_cmd = [
            os.path.join(os.environ["MOZ_FETCHES_DIR"], "clang/bin/llvm-profdata"),
            "merge",
            "-o",
            merged_profdata,
        ] + profraw_files
        rc = subprocess.call(merge_cmd)
        if rc != 0:
            self.fatal(
                "INFRA-ERROR: Failed to merge profile data. Corrupt profile?",
                EXIT_STATUS_DICT[TBPL_RETRY],
            )

        # tarfile doesn't support xz in this version of Python
        artifacts_dir = dirs["abs_artifacts_dir"]
        os.makedirs(artifacts_dir, exist_ok=True)
        tar_cmd = [
            "tar",
            "-acvf",
            os.path.join(artifacts_dir, "profdata.tar.xz"),
            "-C",
            workspace_dir,
            "merged.profdata",
            "en-US.log",
        ]
        subprocess.check_call(tar_cmd)

        httpd.stop()


if __name__ == "__main__":
    test = AndroidProfileRun()
    test.run_and_exit()

Messung V0.5 in Prozent
C=95 H=89 G=91

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet am  2026-08-23) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002