зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1656235 - support visual metrics r=acreskey,sparky
Differential Revision: https://phabricator.services.mozilla.com/D85561
This commit is contained in:
Родитель
5a38472369
Коммит
abb4969c3e
|
@ -5,11 +5,18 @@ from mozperftest.layers import Layers
|
|||
from mozperftest.metrics.perfherder import Perfherder
|
||||
from mozperftest.metrics.consoleoutput import ConsoleOutput
|
||||
from mozperftest.metrics.notebookupload import Notebook
|
||||
from mozperftest.metrics.visualmetrics import VisualMetrics
|
||||
|
||||
|
||||
def get_layers():
|
||||
return Perfherder, ConsoleOutput, Notebook
|
||||
return VisualMetrics, Perfherder, ConsoleOutput, Notebook
|
||||
|
||||
|
||||
def pick_metrics(env, flavor, mach_cmd):
|
||||
return Layers(env, mach_cmd, get_layers())
|
||||
if flavor in ("desktop-browser", "mobile-browser"):
|
||||
layers = get_layers()
|
||||
else:
|
||||
# we don't need VisualMetrics for xpcshell
|
||||
layers = Perfherder, ConsoleOutput, Notebook
|
||||
|
||||
return Layers(env, mach_cmd, layers)
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
# 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 subprocess
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import errno
|
||||
from pathlib import Path
|
||||
|
||||
from mozfile import which
|
||||
from mozperftest.layers import Layer
|
||||
from mozperftest.utils import silence
|
||||
|
||||
METRICS_FIELDS = (
|
||||
"SpeedIndex",
|
||||
"FirstVisualChange",
|
||||
"LastVisualChange",
|
||||
"VisualProgress",
|
||||
"videoRecordingStart",
|
||||
)
|
||||
|
||||
|
||||
class VisualData:
|
||||
def open_data(self, data):
|
||||
res = {
|
||||
"name": "visualmetrics",
|
||||
"subtest": data["name"],
|
||||
"data": [
|
||||
{"file": "visualmetrics", "value": value, "xaxis": xaxis}
|
||||
for xaxis, value in enumerate(data["values"])
|
||||
],
|
||||
}
|
||||
return res
|
||||
|
||||
def transform(self, data):
|
||||
return data
|
||||
|
||||
merge = transform
|
||||
|
||||
|
||||
class VisualMetrics(Layer):
|
||||
"""Wrapper around Browsertime's visualmetrics.py script
|
||||
"""
|
||||
|
||||
name = "visualmetrics"
|
||||
activated = False
|
||||
arguments = {}
|
||||
|
||||
def setup(self):
|
||||
self.metrics = []
|
||||
self.metrics_fields = []
|
||||
|
||||
# making sure we have ffmpeg and imagemagick available
|
||||
for tool in ("ffmpeg", "magick"):
|
||||
if sys.platform in ("win32", "msys"):
|
||||
tool += ".exe"
|
||||
path = which(tool)
|
||||
if not path:
|
||||
raise OSError(errno.ENOENT, f"Could not find {tool}")
|
||||
|
||||
def run(self, metadata):
|
||||
if "VISUALMETRICS_PY" not in os.environ:
|
||||
raise OSError(
|
||||
"The VISUALMETRICS_PY environment variable is not set."
|
||||
"Make sure you run the browsertime layer"
|
||||
)
|
||||
path = Path(os.environ["VISUALMETRICS_PY"])
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(str(path))
|
||||
|
||||
self.visualmetrics = path
|
||||
treated = 0
|
||||
|
||||
for result in metadata.get_results():
|
||||
result_dir = result.get("results")
|
||||
if result_dir is None:
|
||||
continue
|
||||
result_dir = Path(result_dir)
|
||||
if not result_dir.is_dir():
|
||||
continue
|
||||
browsertime_json = Path(result_dir, "browsertime.json")
|
||||
if not browsertime_json.exists():
|
||||
continue
|
||||
treated += self.run_visual_metrics(browsertime_json)
|
||||
|
||||
self.info(f"Treated {treated} videos.")
|
||||
if len(self.metrics) > 0:
|
||||
metadata.add_result(
|
||||
{
|
||||
"name": "visualmetrics",
|
||||
"framework": {"name": "mozperftest"},
|
||||
"transformer": "mozperftest.metrics.visualmetrics:VisualData",
|
||||
"results": self.metrics,
|
||||
}
|
||||
)
|
||||
|
||||
# we also extend --perfherder-metrics and --console-metrics if they
|
||||
# are activated
|
||||
def add_to_option(name):
|
||||
existing = self.get_arg(name, [])
|
||||
for field in self.metrics_fields:
|
||||
existing.append({"name": field, "unit": "ms"})
|
||||
self.env.set_arg(name, existing)
|
||||
|
||||
if self.get_arg("perfherder"):
|
||||
add_to_option("perfherder-metrics")
|
||||
|
||||
if self.get_arg("console"):
|
||||
add_to_option("console-metrics")
|
||||
|
||||
else:
|
||||
self.warning("No video was treated.")
|
||||
return metadata
|
||||
|
||||
def run_command(self, *cmd):
|
||||
cmd = list(cmd)
|
||||
self.debug(f"Running command {' '.join(cmd)}")
|
||||
env = dict(os.environ)
|
||||
path = [
|
||||
p
|
||||
for p in env["PATH"].split(os.pathsep)
|
||||
if p != self.mach_cmd.virtualenv_manager.bin_path
|
||||
]
|
||||
env["PATH"] = os.pathsep.join(path)
|
||||
try:
|
||||
res = subprocess.check_output(cmd, universal_newlines=True, env=env)
|
||||
self.debug("Command succeeded", result=res)
|
||||
return 0, res
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.debug("Command failed", cmd=cmd, status=e.returncode, output=e.output)
|
||||
return e.returncode, e.output
|
||||
|
||||
def run_visual_metrics(self, browsertime_json):
|
||||
verbose = self.get_arg("verbose")
|
||||
self.info(f"Looking at {browsertime_json}")
|
||||
|
||||
class _display:
|
||||
def __enter__(self, *args, **kw):
|
||||
return self
|
||||
|
||||
__exit__ = __enter__
|
||||
|
||||
may_silence = not verbose and silence or _display
|
||||
|
||||
with browsertime_json.open() as f:
|
||||
browsertime_json_data = json.loads(f.read())
|
||||
|
||||
videos = 0
|
||||
for site in browsertime_json_data:
|
||||
for video in site["files"]["video"]:
|
||||
videos += 1
|
||||
video_path = browsertime_json.parent / video
|
||||
res = "[]"
|
||||
with may_silence():
|
||||
code, res = self.run_command(
|
||||
str(self.visualmetrics), "--video", str(video_path), "--json"
|
||||
)
|
||||
if code != 0:
|
||||
raise IOError(str(res))
|
||||
try:
|
||||
res = json.loads(res)
|
||||
except json.JSONDecodeError:
|
||||
self.error(
|
||||
"Could not read the json output from" " visualmetrics.py"
|
||||
)
|
||||
raise
|
||||
|
||||
for name, value in res.items():
|
||||
if name in ("VisualProgress",):
|
||||
self._expand_visual_progress(name, value)
|
||||
else:
|
||||
self.append_metrics(name, value)
|
||||
|
||||
return videos
|
||||
|
||||
def _expand_visual_progress(self, name, value):
|
||||
def _split_percent(val):
|
||||
# value is of the form "567=94%"
|
||||
val = val.split("=")
|
||||
value, percent = val[0].strip(), val[1].strip()
|
||||
if percent.endswith("%"):
|
||||
percent = percent[:-1]
|
||||
return int(percent), int(value)
|
||||
|
||||
percents = [_split_percent(elmt) for elmt in value.split(",")]
|
||||
|
||||
# we want to keep the first added value for each percent
|
||||
# so the trick here is to create a dict() with the reversed list
|
||||
percents = dict(reversed(percents))
|
||||
|
||||
# we are keeping the last 5 percents
|
||||
percents = list(percents.items())
|
||||
percents.sort()
|
||||
for percent, value in percents[:5]:
|
||||
self.append_metrics(f"{name}{percent}", value)
|
||||
|
||||
def append_metrics(self, name, value):
|
||||
if name not in self.metrics_fields:
|
||||
self.metrics_fields.append(name)
|
||||
self.metrics.append(
|
||||
{"name": name, "values": [value], "lowerIsBetter": True, "unit": "ms"}
|
||||
)
|
|
@ -12,15 +12,11 @@ from pathlib import Path
|
|||
|
||||
from mozperftest.utils import install_package
|
||||
from mozperftest.test.noderunner import NodeRunner
|
||||
from mozperftest.test.browsertime.setup import (
|
||||
system_prerequisites,
|
||||
append_system_env,
|
||||
)
|
||||
from mozperftest.test.browsertime.script import ScriptInfo
|
||||
|
||||
|
||||
BROWSERTIME_SRC_ROOT = Path(__file__).parent
|
||||
PILLOW_VERSION = "6.2.1"
|
||||
PILLOW_VERSION = "7.2.0"
|
||||
PYSSIM_VERSION = "0.4"
|
||||
|
||||
|
||||
|
@ -122,7 +118,20 @@ class BrowsertimeRunner(NodeRunner):
|
|||
@property
|
||||
def browsertime_js(self):
|
||||
root = os.environ.get("BROWSERTIME", self.state_path)
|
||||
return Path(root, "node_modules", "browsertime", "bin", "browsertime.js")
|
||||
path = Path(root, "node_modules", "browsertime", "bin", "browsertime.js")
|
||||
if path.exists():
|
||||
os.environ["BROWSERTIME_JS"] = str(path)
|
||||
return path
|
||||
|
||||
@property
|
||||
def visualmetrics_py(self):
|
||||
root = os.environ.get("BROWSERTIME", self.state_path)
|
||||
path = Path(
|
||||
root, "node_modules", "browsertime", "browsertime", "visualmetrics.py"
|
||||
)
|
||||
if path.exists():
|
||||
os.environ["VISUALMETRICS_PY"] = str(path)
|
||||
return path
|
||||
|
||||
def setup(self):
|
||||
"""Install browsertime and visualmetrics.py prerequisites and the Node.js package.
|
||||
|
@ -148,14 +157,13 @@ class BrowsertimeRunner(NodeRunner):
|
|||
|
||||
# check if the browsertime package has been deployed correctly
|
||||
# for this we just check for the browsertime directory presence
|
||||
if self.browsertime_js.exists() and not self.get_arg("clobber"):
|
||||
if (
|
||||
self.visualmetrics_py.exists()
|
||||
and self.browsertime_js.exists()
|
||||
and not self.get_arg("clobber")
|
||||
):
|
||||
return
|
||||
|
||||
if install_url is None:
|
||||
system_prerequisites(
|
||||
str(self.state_path), str(self.artifact_cache_path), self.log, self.info
|
||||
)
|
||||
|
||||
# preparing ~/.mozbuild/browsertime
|
||||
for file in ("package.json", "package-lock.json"):
|
||||
src = BROWSERTIME_SRC_ROOT / file
|
||||
|
@ -223,10 +231,6 @@ class BrowsertimeRunner(NodeRunner):
|
|||
no_optional=install_url or automation,
|
||||
)
|
||||
|
||||
def append_env(self, append_path=True):
|
||||
env = super(BrowsertimeRunner, self).append_env(append_path)
|
||||
return append_system_env(env, str(self.state_path), append_path)
|
||||
|
||||
def extra_default_args(self, args=[]):
|
||||
# Add Mozilla-specific default arguments. This is tricky because browsertime is quite
|
||||
# loose about arguments; repeat arguments are generally accepted but then produce
|
||||
|
@ -332,6 +336,10 @@ class BrowsertimeRunner(NodeRunner):
|
|||
if self.get_arg("verbose"):
|
||||
args += ["-vvv"]
|
||||
|
||||
# if the visualmetrics layer is activated, we want to feed it
|
||||
if self.get_arg("visualmetrics"):
|
||||
args += ["--video", "true"]
|
||||
|
||||
extra_options = self.get_arg("extra-options")
|
||||
if extra_options:
|
||||
for option in extra_options.split(","):
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
# 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 os
|
||||
import stat
|
||||
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
from shutil_which import which
|
||||
|
||||
from mozbuild.util import mkdir
|
||||
import mozpack.path as mozpath
|
||||
|
||||
from mozbuild.action.tooltool import unpack_file
|
||||
from mozbuild.artifact_cache import ArtifactCache
|
||||
|
||||
from mozperftest.utils import host_platform
|
||||
|
||||
|
||||
AUTOMATION = "MOZ_AUTOMATION" in os.environ
|
||||
GECKO_RELEASES = (
|
||||
"https://github.com/ncalexan/geckodriver/releases/download/v0.24.0-android"
|
||||
)
|
||||
|
||||
|
||||
# Map from `host_platform()` to a `fetch`-like syntax.
|
||||
host_fetches = {
|
||||
"darwin": {
|
||||
"ffmpeg": {
|
||||
"type": "static-url",
|
||||
"url": GECKO_RELEASES + "/ffmpeg-4.1.1-macos64-static.zip", # noqa
|
||||
# An extension to `fetch` syntax.
|
||||
"path": "ffmpeg-4.1.1-macos64-static",
|
||||
}
|
||||
},
|
||||
"linux64": {
|
||||
"ffmpeg": {
|
||||
"type": "static-url",
|
||||
"url": GECKO_RELEASES + "/ffmpeg-4.1.4-i686-static.tar.xz", # noqa
|
||||
# An extension to `fetch` syntax.
|
||||
"path": "ffmpeg-4.1.4-i686-static",
|
||||
},
|
||||
# TODO: install a static ImageMagick. All easily available binaries are
|
||||
# not statically linked, so they will (mostly) fail at runtime due to
|
||||
# missing dependencies. For now we require folks to install ImageMagick
|
||||
# globally with their package manager of choice.
|
||||
},
|
||||
"win64": {
|
||||
"ffmpeg": {
|
||||
"type": "static-url",
|
||||
"url": GECKO_RELEASES + "/ffmpeg-4.1.1-win64-static.zip", # noqa
|
||||
# An extension to `fetch` syntax.
|
||||
"path": "ffmpeg-4.1.1-win64-static",
|
||||
},
|
||||
"ImageMagick": {
|
||||
"type": "static-url",
|
||||
# 'url': 'https://imagemagick.org/download/binaries/ImageMagick-7.0.8-39-portable-Q16-x64.zip', # noqa
|
||||
# imagemagick.org doesn't keep old versions; the mirror below does.
|
||||
"url": "https://ftp.icm.edu.pl/packages/ImageMagick/binaries/ImageMagick-7.0.8-39-portable-Q16-x64.zip", # noqa
|
||||
# An extension to `fetch` syntax.
|
||||
"path": "ImageMagick-7.0.8",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def system_prerequisites(state_path, artifact_cache_path, log, info):
|
||||
"""Install browsertime and visualmetrics.py prerequisites.
|
||||
"""
|
||||
if not AUTOMATION and host_platform().startswith("linux"):
|
||||
# On Linux ImageMagick needs to be installed manually, and `mach bootstrap` doesn't
|
||||
# do that (yet). Provide some guidance.
|
||||
im_programs = ("compare", "convert", "mogrify")
|
||||
for im_program in im_programs:
|
||||
prog = which(im_program)
|
||||
if not prog:
|
||||
raise Exception(
|
||||
"Error: On Linux, ImageMagick must be on the PATH. "
|
||||
"Install ImageMagick manually and try again (or update PATH). "
|
||||
"On Ubuntu and Debian, try `sudo apt-get install imagemagick`. "
|
||||
"On Fedora, try `sudo dnf install imagemagick`. "
|
||||
"On CentOS, try `sudo yum install imagemagick`."
|
||||
)
|
||||
|
||||
# Download the visualmetrics.py requirements.
|
||||
artifact_cache = ArtifactCache(artifact_cache_path, log=log, skip_cache=False)
|
||||
|
||||
fetches = host_fetches[host_platform()]
|
||||
for tool, fetch in sorted(fetches.items()):
|
||||
archive = artifact_cache.fetch(fetch["url"])
|
||||
# TODO: assert type, verify sha256 (and size?).
|
||||
|
||||
if fetch.get("unpack", True):
|
||||
cwd = os.getcwd()
|
||||
try:
|
||||
mkdir(state_path)
|
||||
os.chdir(state_path)
|
||||
info("Unpacking temporary location {path}", path=archive)
|
||||
|
||||
if "win64" in host_platform() and "imagemagick" in tool.lower():
|
||||
# Windows archive does not contain a subfolder
|
||||
# so we make one for it here
|
||||
mkdir(fetch.get("path"))
|
||||
os.chdir(os.path.join(state_path, fetch.get("path")))
|
||||
unpack_file(archive)
|
||||
os.chdir(state_path)
|
||||
else:
|
||||
unpack_file(archive)
|
||||
|
||||
# Make sure the expected path exists after extraction
|
||||
path = os.path.join(state_path, fetch.get("path"))
|
||||
if not os.path.exists(path):
|
||||
raise Exception("Cannot find an extracted directory: %s" % path)
|
||||
|
||||
try:
|
||||
# Some archives provide binaries that don't have the
|
||||
# executable bit set so we need to set it here
|
||||
for root, dirs, files in os.walk(path):
|
||||
for edir in dirs:
|
||||
loc_to_change = os.path.join(root, edir)
|
||||
st = os.stat(loc_to_change)
|
||||
os.chmod(loc_to_change, st.st_mode | stat.S_IEXEC)
|
||||
for efile in files:
|
||||
loc_to_change = os.path.join(root, efile)
|
||||
st = os.stat(loc_to_change)
|
||||
os.chmod(loc_to_change, st.st_mode | stat.S_IEXEC)
|
||||
except Exception as e:
|
||||
raise Exception(
|
||||
"Could not set executable bit in %s, error: %s" % (path, str(e))
|
||||
)
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
def append_system_env(env, state_path, append_path=True):
|
||||
fetches = host_fetches[host_platform()]
|
||||
|
||||
# Ensure that bare `ffmpeg` and ImageMagick commands
|
||||
# {`convert`,`compare`,`mogrify`} are found. The `visualmetrics.py`
|
||||
# script doesn't take these as configuration, so we do this (for now).
|
||||
# We should update the script itself to accept this configuration.
|
||||
path = env.get("PATH", "").split(os.pathsep)
|
||||
path_to_ffmpeg = mozpath.join(state_path, fetches["ffmpeg"]["path"])
|
||||
|
||||
path_to_imagemagick = None
|
||||
if "ImageMagick" in fetches:
|
||||
path_to_imagemagick = mozpath.join(state_path, fetches["ImageMagick"]["path"])
|
||||
|
||||
if path_to_imagemagick:
|
||||
# ImageMagick ships ffmpeg (on Windows, at least) so we
|
||||
# want to ensure that our ffmpeg goes first, just in case.
|
||||
path.insert(
|
||||
0,
|
||||
state_path
|
||||
if host_platform().startswith("win")
|
||||
else mozpath.join(path_to_imagemagick, "bin"),
|
||||
) # noqa
|
||||
path.insert(
|
||||
0,
|
||||
path_to_ffmpeg
|
||||
if host_platform().startswith("linux")
|
||||
else mozpath.join(path_to_ffmpeg, "bin"),
|
||||
) # noqa
|
||||
|
||||
# On windows, we need to add the ImageMagick directory to the path
|
||||
# otherwise compare won't be found, and the built-in OS convert
|
||||
# method will be used instead of the ImageMagick one.
|
||||
if "win64" in host_platform() and path_to_imagemagick:
|
||||
# Bug 1596237 - In the windows ImageMagick distribution, the ffmpeg
|
||||
# binary is directly located in the root directory, so here we
|
||||
# insert in the 3rd position to avoid taking precedence over ffmpeg
|
||||
path.insert(2, path_to_imagemagick)
|
||||
|
||||
# On macOs, we can't install our own ImageMagick because the
|
||||
# System Integrity Protection (SIP) won't let us set DYLD_LIBRARY_PATH
|
||||
# unless we deactivate SIP with "csrutil disable".
|
||||
# So we're asking the user to install it.
|
||||
#
|
||||
# if ImageMagick was installed via brew, we want to make sure we
|
||||
# include the PATH
|
||||
if host_platform() == "darwin":
|
||||
for p in os.environ["PATH"].split(os.pathsep):
|
||||
p = p.strip()
|
||||
if not p or p in path:
|
||||
continue
|
||||
path.append(p)
|
||||
|
||||
if path_to_imagemagick:
|
||||
env.update(
|
||||
{
|
||||
# See https://imagemagick.org/script/download.php.
|
||||
# Harmless on other platforms.
|
||||
"LD_LIBRARY_PATH": mozpath.join(path_to_imagemagick, "lib"),
|
||||
"DYLD_LIBRARY_PATH": mozpath.join(path_to_imagemagick, "lib"),
|
||||
"MAGICK_HOME": path_to_imagemagick,
|
||||
}
|
||||
)
|
||||
|
||||
return env
|
|
@ -0,0 +1,999 @@
|
|||
[
|
||||
{
|
||||
"info": {
|
||||
"browsertime": {
|
||||
"version": "8.3.0"
|
||||
},
|
||||
"url": "https://www.bbc.com/news/world-middle-east-53598965",
|
||||
"timestamp": "2020-08-03T11:18:37+02:00",
|
||||
"connectivity": {
|
||||
"engine": "external",
|
||||
"profile": "native"
|
||||
},
|
||||
"extra": {},
|
||||
"alias": "pageload"
|
||||
},
|
||||
"files": {
|
||||
"video": [
|
||||
"pages/www.bbc.com/news/world-middle-east-53598965/data/video/1.mp4"
|
||||
],
|
||||
"screenshot": [],
|
||||
"timeline": [],
|
||||
"consoleLog": [],
|
||||
"netLog": [],
|
||||
"perfLog": []
|
||||
},
|
||||
"cdp": {
|
||||
"performance": []
|
||||
},
|
||||
"timestamps": [
|
||||
"2020-08-03T11:18:12+02:00"
|
||||
],
|
||||
"browserScripts": [
|
||||
{
|
||||
"browser": {
|
||||
"appConstants": {
|
||||
"ACCESSIBILITY": true,
|
||||
"ANDROID_PACKAGE_NAME": "org.mozilla.firefox",
|
||||
"ASAN": false,
|
||||
"ASAN_REPORTER": false,
|
||||
"BROWSER_CHROME_URL": "chrome://browser/content/browser.xhtml",
|
||||
"DEBUG": false,
|
||||
"DEBUG_JS_MODULES": "",
|
||||
"DLL_PREFIX": "lib",
|
||||
"DLL_SUFFIX": ".dylib",
|
||||
"EARLY_BETA_OR_EARLIER": true,
|
||||
"ENABLE_REMOTE_AGENT": true,
|
||||
"FENNEC_NIGHTLY": false,
|
||||
"HAVE_SHELL_SERVICE": true,
|
||||
"HAVE_USR_LIB64_DIR": false,
|
||||
"MENUBAR_CAN_AUTOHIDE": false,
|
||||
"MOZILLA_OFFICIAL": false,
|
||||
"MOZ_ALLOW_ADDON_SIDELOAD": false,
|
||||
"MOZ_ALLOW_LEGACY_EXTENSIONS": false,
|
||||
"MOZ_ANDROID_HISTORY": false,
|
||||
"MOZ_APP_BASENAME": "Firefox",
|
||||
"MOZ_APP_NAME": "firefox",
|
||||
"MOZ_APP_VERSION": "81.0a1",
|
||||
"MOZ_APP_VERSION_DISPLAY": "81.0a1",
|
||||
"MOZ_BING_API_CLIENTID": "no-bing-api-clientid",
|
||||
"MOZ_BING_API_KEY": "no-bing-api-key",
|
||||
"MOZ_BITS_DOWNLOAD": false,
|
||||
"MOZ_BUILDID": "2020073017",
|
||||
"MOZ_BUILD_APP": "browser",
|
||||
"MOZ_CODE_COVERAGE": false,
|
||||
"MOZ_CRASHREPORTER": true,
|
||||
"MOZ_DATA_REPORTING": true,
|
||||
"MOZ_DEV_EDITION": false,
|
||||
"MOZ_GECKO_PROFILER": true,
|
||||
"MOZ_GOOGLE_LOCATION_SERVICE_API_KEY": "no-google-location-service-api-key",
|
||||
"MOZ_GOOGLE_SAFEBROWSING_API_KEY": "no-google-safebrowsing-api-key",
|
||||
"MOZ_MACBUNDLE_NAME": "Nightly.app",
|
||||
"MOZ_MAINTENANCE_SERVICE": false,
|
||||
"MOZ_MOZILLA_API_KEY": "no-mozilla-api-key",
|
||||
"MOZ_NEW_CERT_STORAGE": true,
|
||||
"MOZ_NEW_NOTIFICATION_STORE": true,
|
||||
"MOZ_NEW_XULSTORE": true,
|
||||
"MOZ_NORMANDY": true,
|
||||
"MOZ_OFFICIAL_BRANDING": false,
|
||||
"MOZ_PLACES": true,
|
||||
"MOZ_REQUIRE_SIGNING": false,
|
||||
"MOZ_RUST_FXA_CLIENT": true,
|
||||
"MOZ_SANDBOX": false,
|
||||
"MOZ_SERVICES_HEALTHREPORT": true,
|
||||
"MOZ_SERVICES_SYNC": false,
|
||||
"MOZ_SWITCHBOARD": false,
|
||||
"MOZ_SYSTEM_NSS": false,
|
||||
"MOZ_TELEMETRY_ON_BY_DEFAULT": false,
|
||||
"MOZ_TELEMETRY_REPORTING": false,
|
||||
"MOZ_UNSIGNED_SCOPES": 0,
|
||||
"MOZ_UPDATER": true,
|
||||
"MOZ_UPDATE_AGENT": false,
|
||||
"MOZ_UPDATE_CHANNEL": "default",
|
||||
"MOZ_WEBRTC": true,
|
||||
"MOZ_WIDGET_GTK": false,
|
||||
"MOZ_WIDGET_TOOLKIT": "cocoa",
|
||||
"NIGHTLY_BUILD": true,
|
||||
"OMNIJAR_NAME": "omni.ja",
|
||||
"RELEASE_OR_BETA": false,
|
||||
"SOURCE_REVISION_URL": "",
|
||||
"TELEMETRY_PING_FORMAT_VERSION": 4,
|
||||
"TSAN": false,
|
||||
"XP_UNIX": true,
|
||||
"isPlatformAndVersionAtLeast": {},
|
||||
"isPlatformAndVersionAtMost": {},
|
||||
"platform": "macosx",
|
||||
"unixstyle": "other"
|
||||
},
|
||||
"asyncAppConstants": {
|
||||
"ACCESSIBILITY": true,
|
||||
"ANDROID_PACKAGE_NAME": "org.mozilla.firefox",
|
||||
"ASAN": false,
|
||||
"ASAN_REPORTER": false,
|
||||
"BROWSER_CHROME_URL": "chrome://browser/content/browser.xhtml",
|
||||
"DEBUG": false,
|
||||
"DEBUG_JS_MODULES": "",
|
||||
"DLL_PREFIX": "lib",
|
||||
"DLL_SUFFIX": ".dylib",
|
||||
"EARLY_BETA_OR_EARLIER": true,
|
||||
"ENABLE_REMOTE_AGENT": true,
|
||||
"FENNEC_NIGHTLY": false,
|
||||
"HAVE_SHELL_SERVICE": true,
|
||||
"HAVE_USR_LIB64_DIR": false,
|
||||
"MENUBAR_CAN_AUTOHIDE": false,
|
||||
"MOZILLA_OFFICIAL": false,
|
||||
"MOZ_ALLOW_ADDON_SIDELOAD": false,
|
||||
"MOZ_ALLOW_LEGACY_EXTENSIONS": false,
|
||||
"MOZ_ANDROID_HISTORY": false,
|
||||
"MOZ_APP_BASENAME": "Firefox",
|
||||
"MOZ_APP_NAME": "firefox",
|
||||
"MOZ_APP_VERSION": "81.0a1",
|
||||
"MOZ_APP_VERSION_DISPLAY": "81.0a1",
|
||||
"MOZ_BING_API_CLIENTID": "no-bing-api-clientid",
|
||||
"MOZ_BING_API_KEY": "no-bing-api-key",
|
||||
"MOZ_BITS_DOWNLOAD": false,
|
||||
"MOZ_BUILDID": "200730174322",
|
||||
"MOZ_BUILD_APP": "browser",
|
||||
"MOZ_CODE_COVERAGE": false,
|
||||
"MOZ_CRASHREPORTER": true,
|
||||
"MOZ_DATA_REPORTING": true,
|
||||
"MOZ_DEV_EDITION": false,
|
||||
"MOZ_GECKO_PROFILER": true,
|
||||
"MOZ_GOOGLE_LOCATION_SERVICE_API_KEY": "no-google-location-service-api-key",
|
||||
"MOZ_GOOGLE_SAFEBROWSING_API_KEY": "no-google-safebrowsing-api-key",
|
||||
"MOZ_MACBUNDLE_NAME": "Nightly.app",
|
||||
"MOZ_MAINTENANCE_SERVICE": false,
|
||||
"MOZ_MOZILLA_API_KEY": "no-mozilla-api-key",
|
||||
"MOZ_NEW_CERT_STORAGE": true,
|
||||
"MOZ_NEW_NOTIFICATION_STORE": true,
|
||||
"MOZ_NEW_XULSTORE": true,
|
||||
"MOZ_NORMANDY": true,
|
||||
"MOZ_OFFICIAL_BRANDING": false,
|
||||
"MOZ_PLACES": true,
|
||||
"MOZ_REQUIRE_SIGNING": false,
|
||||
"MOZ_RUST_FXA_CLIENT": true,
|
||||
"MOZ_SANDBOX": false,
|
||||
"MOZ_SERVICES_HEALTHREPORT": true,
|
||||
"MOZ_SERVICES_SYNC": false,
|
||||
"MOZ_SWITCHBOARD": false,
|
||||
"MOZ_SYSTEM_NSS": false,
|
||||
"MOZ_TELEMETRY_ON_BY_DEFAULT": false,
|
||||
"MOZ_TELEMETRY_REPORTING": false,
|
||||
"MOZ_UNSIGNED_SCOPES": 0,
|
||||
"MOZ_UPDATER": true,
|
||||
"MOZ_UPDATE_AGENT": false,
|
||||
"MOZ_UPDATE_CHANNEL": "default",
|
||||
"MOZ_WEBRTC": true,
|
||||
"MOZ_WIDGET_GTK": false,
|
||||
"MOZ_WIDGET_TOOLKIT": "cocoa",
|
||||
"NIGHTLY_BUILD": true,
|
||||
"OMNIJAR_NAME": "omni.ja",
|
||||
"RELEASE_OR_BETA": false,
|
||||
"SOURCE_REVISION_URL": "",
|
||||
"TELEMETRY_PING_FORMAT_VERSION": 4,
|
||||
"TSAN": false,
|
||||
"XP_UNIX": true,
|
||||
"isPlatformAndVersionAtLeast": {},
|
||||
"isPlatformAndVersionAtMost": {},
|
||||
"platform": "macosx",
|
||||
"unixstyle": "other"
|
||||
},
|
||||
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:81.0) Gecko/20100101 Firefox/81.0",
|
||||
"windowSize": "1366x768"
|
||||
},
|
||||
"pageinfo": {
|
||||
"documentHeight": 8937,
|
||||
"documentSize": {
|
||||
"decodedBodySize": 270461,
|
||||
"encodedBodySize": 67482,
|
||||
"transferSize": 68337
|
||||
},
|
||||
"documentTitle": "Coronavirus: Iran cover-up of deaths revealed by data leak - BBC News",
|
||||
"documentWidth": 1366,
|
||||
"domElements": 1348,
|
||||
"navigationStartTime": 1596629,
|
||||
"nextHopProtocol": "h2",
|
||||
"resources": {
|
||||
"count": 91,
|
||||
"duration": 26360.459999999992
|
||||
},
|
||||
"responsive": true,
|
||||
"url": "https://www.bbc.com/news/world-middle-east-53598965",
|
||||
"visualElements": {
|
||||
"heroes": [
|
||||
{
|
||||
"filename": "_113766981_iranhospital.jpg",
|
||||
"height": 363,
|
||||
"name": "LargestImage",
|
||||
"width": 646,
|
||||
"x": 195,
|
||||
"y": 403
|
||||
},
|
||||
{
|
||||
"filename": null,
|
||||
"height": 72,
|
||||
"name": "Heading",
|
||||
"width": 645,
|
||||
"x": 195,
|
||||
"y": 196
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
"height": 694,
|
||||
"width": 1366
|
||||
}
|
||||
}
|
||||
},
|
||||
"timings": {
|
||||
"firstPaint": 1084,
|
||||
"loadEventEnd": 8274,
|
||||
"navigationTiming": {
|
||||
"connectStart": 20,
|
||||
"domComplete": 8238,
|
||||
"domContentLoadedEventEnd": 4165,
|
||||
"domContentLoadedEventStart": 4159,
|
||||
"domInteractive": 1415,
|
||||
"domainLookupEnd": 20,
|
||||
"domainLookupStart": 20,
|
||||
"duration": 8274,
|
||||
"fetchStart": 20,
|
||||
"loadEventEnd": 8274,
|
||||
"loadEventStart": 8264,
|
||||
"redirectEnd": 0,
|
||||
"redirectStart": 0,
|
||||
"requestStart": 29,
|
||||
"responseEnd": 117,
|
||||
"responseStart": 117,
|
||||
"secureConnectionStart": 0,
|
||||
"startTime": 0,
|
||||
"unloadEventEnd": 124,
|
||||
"unloadEventStart": 120,
|
||||
"workerStart": 0
|
||||
},
|
||||
"pageTimings": {
|
||||
"backEndTime": 117,
|
||||
"domContentLoadedTime": 4159,
|
||||
"domInteractiveTime": 1415,
|
||||
"domainLookupTime": 0,
|
||||
"frontEndTime": 8147,
|
||||
"pageDownloadTime": 0,
|
||||
"pageLoadTime": 8264,
|
||||
"redirectionTime": 0,
|
||||
"serverConnectionTime": 0,
|
||||
"serverResponseTime": 88
|
||||
},
|
||||
"rumSpeedIndex": 5542,
|
||||
"serverTimings": [],
|
||||
"timeToContentfulPaint": 1124,
|
||||
"timeToDomContentFlushed": 4158,
|
||||
"timeToFirstInteractive": 11858,
|
||||
"userTimings": {
|
||||
"marks": [],
|
||||
"measures": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"visualMetrics": [],
|
||||
"cpu": [],
|
||||
"extras": [
|
||||
{}
|
||||
],
|
||||
"fullyLoaded": [],
|
||||
"errors": [
|
||||
[]
|
||||
],
|
||||
"statistics": {
|
||||
"browser": {
|
||||
"appConstants": {
|
||||
"MOZ_BUILDID": {
|
||||
"median": 2020073017,
|
||||
"mean": 2020073017,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 2020073017,
|
||||
"p10": 2020073017,
|
||||
"p90": 2020073017,
|
||||
"p99": 2020073017,
|
||||
"max": 2020073017
|
||||
},
|
||||
"MOZ_UNSIGNED_SCOPES": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"TELEMETRY_PING_FORMAT_VERSION": {
|
||||
"median": 4,
|
||||
"mean": 4,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 4,
|
||||
"p10": 4,
|
||||
"p90": 4,
|
||||
"p99": 4,
|
||||
"max": 4
|
||||
}
|
||||
},
|
||||
"asyncAppConstants": {
|
||||
"MOZ_BUILDID": {
|
||||
"median": 2020073017,
|
||||
"mean": 2020073017,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 2020073017,
|
||||
"p10": 2020073017,
|
||||
"p90": 2020073017,
|
||||
"p99": 2020073017,
|
||||
"max": 2020073017
|
||||
},
|
||||
"MOZ_UNSIGNED_SCOPES": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"TELEMETRY_PING_FORMAT_VERSION": {
|
||||
"median": 4,
|
||||
"mean": 4,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 4,
|
||||
"p10": 4,
|
||||
"p90": 4,
|
||||
"p99": 4,
|
||||
"max": 4
|
||||
}
|
||||
}
|
||||
},
|
||||
"pageinfo": {
|
||||
"documentHeight": {
|
||||
"median": 8937,
|
||||
"mean": 8937,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 8937,
|
||||
"p10": 8937,
|
||||
"p90": 8937,
|
||||
"p99": 8937,
|
||||
"max": 8937
|
||||
},
|
||||
"documentSize": {
|
||||
"decodedBodySize": {
|
||||
"median": 270461,
|
||||
"mean": 270461,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 270461,
|
||||
"p10": 270461,
|
||||
"p90": 270461,
|
||||
"p99": 270461,
|
||||
"max": 270461
|
||||
},
|
||||
"encodedBodySize": {
|
||||
"median": 67482,
|
||||
"mean": 67482,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 67482,
|
||||
"p10": 67482,
|
||||
"p90": 67482,
|
||||
"p99": 67482,
|
||||
"max": 67482
|
||||
},
|
||||
"transferSize": {
|
||||
"median": 68337,
|
||||
"mean": 68337,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 68337,
|
||||
"p10": 68337,
|
||||
"p90": 68337,
|
||||
"p99": 68337,
|
||||
"max": 68337
|
||||
}
|
||||
},
|
||||
"documentWidth": {
|
||||
"median": 1366,
|
||||
"mean": 1366,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 1366,
|
||||
"p10": 1366,
|
||||
"p90": 1366,
|
||||
"p99": 1366,
|
||||
"max": 1366
|
||||
},
|
||||
"domElements": {
|
||||
"median": 1348,
|
||||
"mean": 1348,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 1348,
|
||||
"p10": 1348,
|
||||
"p90": 1348,
|
||||
"p99": 1348,
|
||||
"max": 1348
|
||||
},
|
||||
"navigationStartTime": {
|
||||
"median": 1596629,
|
||||
"mean": 1596629,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 1596629,
|
||||
"p10": 1596629,
|
||||
"p90": 1596629,
|
||||
"p99": 1596629,
|
||||
"max": 1596629
|
||||
},
|
||||
"resources": {
|
||||
"count": {
|
||||
"median": 91,
|
||||
"mean": 91,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 91,
|
||||
"p10": 91,
|
||||
"p90": 91,
|
||||
"p99": 91,
|
||||
"max": 91
|
||||
},
|
||||
"duration": {
|
||||
"median": 26360,
|
||||
"mean": 26360,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 26360,
|
||||
"p10": 26360,
|
||||
"p90": 26360,
|
||||
"p99": 26360,
|
||||
"max": 26360
|
||||
}
|
||||
},
|
||||
"visualElements": {
|
||||
"heroes": [
|
||||
{
|
||||
"height": {
|
||||
"median": 363,
|
||||
"mean": 363,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 363,
|
||||
"p10": 363,
|
||||
"p90": 363,
|
||||
"p99": 363,
|
||||
"max": 363
|
||||
},
|
||||
"width": {
|
||||
"median": 646,
|
||||
"mean": 646,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 646,
|
||||
"p10": 646,
|
||||
"p90": 646,
|
||||
"p99": 646,
|
||||
"max": 646
|
||||
},
|
||||
"x": {
|
||||
"median": 195,
|
||||
"mean": 195,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 195,
|
||||
"p10": 195,
|
||||
"p90": 195,
|
||||
"p99": 195,
|
||||
"max": 195
|
||||
},
|
||||
"y": {
|
||||
"median": 403,
|
||||
"mean": 403,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 403,
|
||||
"p10": 403,
|
||||
"p90": 403,
|
||||
"p99": 403,
|
||||
"max": 403
|
||||
}
|
||||
},
|
||||
{
|
||||
"height": {
|
||||
"median": 72,
|
||||
"mean": 72,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 72,
|
||||
"p10": 72,
|
||||
"p90": 72,
|
||||
"p99": 72,
|
||||
"max": 72
|
||||
},
|
||||
"width": {
|
||||
"median": 645,
|
||||
"mean": 645,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 645,
|
||||
"p10": 645,
|
||||
"p90": 645,
|
||||
"p99": 645,
|
||||
"max": 645
|
||||
},
|
||||
"x": {
|
||||
"median": 195,
|
||||
"mean": 195,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 195,
|
||||
"p10": 195,
|
||||
"p90": 195,
|
||||
"p99": 195,
|
||||
"max": 195
|
||||
},
|
||||
"y": {
|
||||
"median": 196,
|
||||
"mean": 196,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 196,
|
||||
"p10": 196,
|
||||
"p90": 196,
|
||||
"p99": 196,
|
||||
"max": 196
|
||||
}
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
"height": {
|
||||
"median": 694,
|
||||
"mean": 694,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 694,
|
||||
"p10": 694,
|
||||
"p90": 694,
|
||||
"p99": 694,
|
||||
"max": 694
|
||||
},
|
||||
"width": {
|
||||
"median": 1366,
|
||||
"mean": 1366,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 1366,
|
||||
"p10": 1366,
|
||||
"p90": 1366,
|
||||
"p99": 1366,
|
||||
"max": 1366
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"timings": {
|
||||
"firstPaint": {
|
||||
"median": 1084,
|
||||
"mean": 1084,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 1084,
|
||||
"p10": 1084,
|
||||
"p90": 1084,
|
||||
"p99": 1084,
|
||||
"max": 1084
|
||||
},
|
||||
"loadEventEnd": {
|
||||
"median": 8274,
|
||||
"mean": 8274,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 8274,
|
||||
"p10": 8274,
|
||||
"p90": 8274,
|
||||
"p99": 8274,
|
||||
"max": 8274
|
||||
},
|
||||
"navigationTiming": {
|
||||
"connectStart": {
|
||||
"median": 20,
|
||||
"mean": 20,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 20,
|
||||
"p10": 20,
|
||||
"p90": 20,
|
||||
"p99": 20,
|
||||
"max": 20
|
||||
},
|
||||
"domComplete": {
|
||||
"median": 8238,
|
||||
"mean": 8238,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 8238,
|
||||
"p10": 8238,
|
||||
"p90": 8238,
|
||||
"p99": 8238,
|
||||
"max": 8238
|
||||
},
|
||||
"domContentLoadedEventEnd": {
|
||||
"median": 4165,
|
||||
"mean": 4165,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 4165,
|
||||
"p10": 4165,
|
||||
"p90": 4165,
|
||||
"p99": 4165,
|
||||
"max": 4165
|
||||
},
|
||||
"domContentLoadedEventStart": {
|
||||
"median": 4159,
|
||||
"mean": 4159,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 4159,
|
||||
"p10": 4159,
|
||||
"p90": 4159,
|
||||
"p99": 4159,
|
||||
"max": 4159
|
||||
},
|
||||
"domInteractive": {
|
||||
"median": 1415,
|
||||
"mean": 1415,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 1415,
|
||||
"p10": 1415,
|
||||
"p90": 1415,
|
||||
"p99": 1415,
|
||||
"max": 1415
|
||||
},
|
||||
"domainLookupEnd": {
|
||||
"median": 20,
|
||||
"mean": 20,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 20,
|
||||
"p10": 20,
|
||||
"p90": 20,
|
||||
"p99": 20,
|
||||
"max": 20
|
||||
},
|
||||
"domainLookupStart": {
|
||||
"median": 20,
|
||||
"mean": 20,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 20,
|
||||
"p10": 20,
|
||||
"p90": 20,
|
||||
"p99": 20,
|
||||
"max": 20
|
||||
},
|
||||
"duration": {
|
||||
"median": 8274,
|
||||
"mean": 8274,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 8274,
|
||||
"p10": 8274,
|
||||
"p90": 8274,
|
||||
"p99": 8274,
|
||||
"max": 8274
|
||||
},
|
||||
"fetchStart": {
|
||||
"median": 20,
|
||||
"mean": 20,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 20,
|
||||
"p10": 20,
|
||||
"p90": 20,
|
||||
"p99": 20,
|
||||
"max": 20
|
||||
},
|
||||
"loadEventEnd": {
|
||||
"median": 8274,
|
||||
"mean": 8274,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 8274,
|
||||
"p10": 8274,
|
||||
"p90": 8274,
|
||||
"p99": 8274,
|
||||
"max": 8274
|
||||
},
|
||||
"loadEventStart": {
|
||||
"median": 8264,
|
||||
"mean": 8264,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 8264,
|
||||
"p10": 8264,
|
||||
"p90": 8264,
|
||||
"p99": 8264,
|
||||
"max": 8264
|
||||
},
|
||||
"redirectEnd": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"redirectStart": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"requestStart": {
|
||||
"median": 29,
|
||||
"mean": 29,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 29,
|
||||
"p10": 29,
|
||||
"p90": 29,
|
||||
"p99": 29,
|
||||
"max": 29
|
||||
},
|
||||
"responseEnd": {
|
||||
"median": 117,
|
||||
"mean": 117,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 117,
|
||||
"p10": 117,
|
||||
"p90": 117,
|
||||
"p99": 117,
|
||||
"max": 117
|
||||
},
|
||||
"responseStart": {
|
||||
"median": 117,
|
||||
"mean": 117,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 117,
|
||||
"p10": 117,
|
||||
"p90": 117,
|
||||
"p99": 117,
|
||||
"max": 117
|
||||
},
|
||||
"secureConnectionStart": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"startTime": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"unloadEventEnd": {
|
||||
"median": 124,
|
||||
"mean": 124,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 124,
|
||||
"p10": 124,
|
||||
"p90": 124,
|
||||
"p99": 124,
|
||||
"max": 124
|
||||
},
|
||||
"unloadEventStart": {
|
||||
"median": 120,
|
||||
"mean": 120,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 120,
|
||||
"p10": 120,
|
||||
"p90": 120,
|
||||
"p99": 120,
|
||||
"max": 120
|
||||
},
|
||||
"workerStart": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
}
|
||||
},
|
||||
"pageTimings": {
|
||||
"backEndTime": {
|
||||
"median": 117,
|
||||
"mean": 117,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 117,
|
||||
"p10": 117,
|
||||
"p90": 117,
|
||||
"p99": 117,
|
||||
"max": 117
|
||||
},
|
||||
"domContentLoadedTime": {
|
||||
"median": 4159,
|
||||
"mean": 4159,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 4159,
|
||||
"p10": 4159,
|
||||
"p90": 4159,
|
||||
"p99": 4159,
|
||||
"max": 4159
|
||||
},
|
||||
"domInteractiveTime": {
|
||||
"median": 1415,
|
||||
"mean": 1415,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 1415,
|
||||
"p10": 1415,
|
||||
"p90": 1415,
|
||||
"p99": 1415,
|
||||
"max": 1415
|
||||
},
|
||||
"domainLookupTime": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"frontEndTime": {
|
||||
"median": 8147,
|
||||
"mean": 8147,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 8147,
|
||||
"p10": 8147,
|
||||
"p90": 8147,
|
||||
"p99": 8147,
|
||||
"max": 8147
|
||||
},
|
||||
"pageDownloadTime": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"pageLoadTime": {
|
||||
"median": 8264,
|
||||
"mean": 8264,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 8264,
|
||||
"p10": 8264,
|
||||
"p90": 8264,
|
||||
"p99": 8264,
|
||||
"max": 8264
|
||||
},
|
||||
"redirectionTime": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"serverConnectionTime": {
|
||||
"median": 0,
|
||||
"mean": 0,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 0,
|
||||
"p10": 0,
|
||||
"p90": 0,
|
||||
"p99": 0,
|
||||
"max": 0
|
||||
},
|
||||
"serverResponseTime": {
|
||||
"median": 88,
|
||||
"mean": 88,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 88,
|
||||
"p10": 88,
|
||||
"p90": 88,
|
||||
"p99": 88,
|
||||
"max": 88
|
||||
}
|
||||
},
|
||||
"rumSpeedIndex": {
|
||||
"median": 5542,
|
||||
"mean": 5542,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 5542,
|
||||
"p10": 5542,
|
||||
"p90": 5542,
|
||||
"p99": 5542,
|
||||
"max": 5542
|
||||
},
|
||||
"timeToContentfulPaint": {
|
||||
"median": 1124,
|
||||
"mean": 1124,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 1124,
|
||||
"p10": 1124,
|
||||
"p90": 1124,
|
||||
"p99": 1124,
|
||||
"max": 1124
|
||||
},
|
||||
"timeToDomContentFlushed": {
|
||||
"median": 4158,
|
||||
"mean": 4158,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 4158,
|
||||
"p10": 4158,
|
||||
"p90": 4158,
|
||||
"p99": 4158,
|
||||
"max": 4158
|
||||
},
|
||||
"timeToFirstInteractive": {
|
||||
"median": 11858,
|
||||
"mean": 11858,
|
||||
"mdev": 0,
|
||||
"stddev": 0,
|
||||
"min": 11858,
|
||||
"p10": 11858,
|
||||
"p90": 11858,
|
||||
"p99": 11858,
|
||||
"max": 11858
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
Двоичные данные
python/mozperftest/mozperftest/tests/data/browsertime-results-video/pages/www.bbc.com/data/video/1.mp4
Normal file
Двоичные данные
python/mozperftest/mozperftest/tests/data/browsertime-results-video/pages/www.bbc.com/data/video/1.mp4
Normal file
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -15,6 +15,7 @@ EXAMPLE_TESTS_DIR = os.path.join(HERE, "data", "samples")
|
|||
EXAMPLE_TEST = os.path.join(EXAMPLE_TESTS_DIR, "perftest_example.js")
|
||||
EXAMPLE_XPCSHELL_TEST = Path(EXAMPLE_TESTS_DIR, "test_xpcshell.js")
|
||||
BT_DATA = Path(HERE, "data", "browsertime-results", "browsertime.json")
|
||||
BT_DATA_VIDEO = Path(HERE, "data", "browsertime-results-video", "browsertime.json")
|
||||
DMG = Path(HERE, "data", "firefox.dmg")
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env python
|
||||
import mozunit
|
||||
from unittest import mock
|
||||
import os
|
||||
import json
|
||||
import pytest
|
||||
|
||||
from mozperftest.tests.support import (
|
||||
get_running_env,
|
||||
EXAMPLE_TEST,
|
||||
temp_file,
|
||||
BT_DATA_VIDEO,
|
||||
)
|
||||
from mozperftest.environment import METRICS
|
||||
|
||||
VM_RES = {
|
||||
"SpeedIndex": 1031,
|
||||
"FirstVisualChange": 533,
|
||||
"LastVisualChange": 3166,
|
||||
"VisualProgress": (
|
||||
"0=0, 533=63, 700=63, 733=63, 900=63, 933=63, 1233=54,"
|
||||
"1333=54, 1366=56, 1500=56, 1633=96, 1800=96, 1933=96,"
|
||||
"2133=96, 2200=96, 2366=96, 2533=96, 2566=96, 2600=96,"
|
||||
"2733=96, 2833=96, 2933=96, 3000=96, 3133=96,3166=100"
|
||||
),
|
||||
"videoRecordingStart": 0,
|
||||
}
|
||||
|
||||
|
||||
def get_res(*args, **kw):
|
||||
return json.dumps(VM_RES)
|
||||
|
||||
|
||||
@mock.patch("mozperftest.test.browsertime.runner.install_package")
|
||||
@mock.patch(
|
||||
"mozperftest.test.noderunner.NodeRunner.verify_node_install", new=lambda x: True
|
||||
)
|
||||
@mock.patch(
|
||||
"mozperftest.test.browsertime.runner.BrowsertimeRunner._setup_node_packages",
|
||||
new=lambda x, y: None,
|
||||
)
|
||||
@mock.patch("mozperftest.metrics.visualmetrics.which", new=lambda path: "ok")
|
||||
@mock.patch("subprocess.check_output", new=get_res)
|
||||
def test_visual_metrics(device):
|
||||
os.environ["VISUALMETRICS_PY"] = ""
|
||||
mach_cmd, metadata, env = get_running_env(
|
||||
visualmetrics=True, perfherder=True, verbose=True
|
||||
)
|
||||
metrics = env.layers[METRICS]
|
||||
env.set_arg("tests", [str(EXAMPLE_TEST)])
|
||||
|
||||
metadata.add_result({"results": str(BT_DATA_VIDEO.parent), "name": "browsertime"})
|
||||
|
||||
with temp_file() as output:
|
||||
env.set_arg("output", output)
|
||||
with metrics as m:
|
||||
metadata = m(metadata)
|
||||
|
||||
output_file = metadata.get_output()
|
||||
with open(output_file) as f:
|
||||
output = json.loads(f.read())
|
||||
|
||||
# Check some metadata
|
||||
assert output["application"]["name"] == "firefox"
|
||||
visual_metrics = [i["name"] for i in output["suites"][1]["subtests"]]
|
||||
assert "VisualProgress96" in visual_metrics
|
||||
|
||||
|
||||
@mock.patch("mozperftest.test.browsertime.runner.install_package")
|
||||
@mock.patch(
|
||||
"mozperftest.test.noderunner.NodeRunner.verify_node_install", new=lambda x: True
|
||||
)
|
||||
@mock.patch(
|
||||
"mozperftest.test.browsertime.runner.BrowsertimeRunner._setup_node_packages",
|
||||
new=lambda x, y: None,
|
||||
)
|
||||
@mock.patch("mozperftest.metrics.visualmetrics.which", new=lambda path: None)
|
||||
def test_visual_metrics_no_ffmpeg(device):
|
||||
os.environ["VISUALMETRICS_PY"] = ""
|
||||
mach_cmd, metadata, env = get_running_env(
|
||||
visualmetrics=True, perfherder=True, verbose=True
|
||||
)
|
||||
metrics = env.layers[METRICS]
|
||||
env.set_arg("tests", [str(EXAMPLE_TEST)])
|
||||
metadata.add_result({"results": str(BT_DATA_VIDEO.parent), "name": "browsertime"})
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
with metrics as m:
|
||||
metadata = m(metadata)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mozunit.main()
|
|
@ -9,7 +9,8 @@ from setuptools import setup
|
|||
PACKAGE_NAME = "mozperftest"
|
||||
PACKAGE_VERSION = "0.2"
|
||||
|
||||
deps = ["regex", "jsonschema", "mozlog >= 6.0", "mozdevice >= 4.0.0", "mozproxy", "mozinfo"]
|
||||
deps = ["regex", "jsonschema", "mozlog >= 6.0", "mozdevice >= 4.0.0", "mozproxy",
|
||||
"mozinfo", "mozfile"]
|
||||
|
||||
setup(
|
||||
name=PACKAGE_NAME,
|
||||
|
|
Загрузка…
Ссылка в новой задаче