# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import os
from benchmarks import memory
from contrib.shared_storage import page_set
from contrib.shared_storage import utils
from core import perf_benchmark
from telemetry import benchmark
from telemetry.timeline import chrome_trace_category_filter
from telemetry.web_perf import timeline_based_measurement
# Features to enable via command line.
_ENABLED_FEATURES = [
'SharedStorageAPI:ExposeDebugMessageForSettingsStatus/true',
'SharedStorageAPIM118', 'SharedStorageAPIM125',
'SharedStorageAPIEnableWALForDatabase',
'FencedFrames:implementation_type/mparch', 'FencedFramesDefaultMode',
'PrivacySandboxAdsAPIsOverride', 'DefaultAllowPrivacySandboxAttestations'
]
# Default number of times to run each shared storage action in a story.
_DEFAULT_NUM_ITERATIONS = 10
# Maximum number of times to run each shared storage action in a story.
_MAX_NUM_ITERATIONS = 10
# Default number of times to run each story.
_DEFAULT_NUM_REPEAT = 10
# Use maximum allowed trace buffer size (in KB).
_TRACE_BUFFER_SIZE = 2**32 - 1
# Timeout in seconds allowed for the browser to shutdown when asked, before
# it is killed.
_SHUTDOWN_TIMEOUT = 90
class SharedStoragePerfBase(perf_benchmark.PerfBenchmark):
SIZE = 0
verbose_cpu_metrics = False
verbose_memory_metrics = False
iterations = _DEFAULT_NUM_ITERATIONS
verbosity = 0
xvfb_process = None
options = {'pageset_repeat': _DEFAULT_NUM_REPEAT}
@property
def URL(self):
return "file://setup_worklet_and_db.html?size=%s" % self.SIZE
@classmethod
def AddBenchmarkCommandLineArgs(cls, parser):
parser.add_argument('--xvfb',
action='store_true',
default=False,
help='Run with Xvfb server if possible.')
parser.add_argument(
'--user-agent',
default='desktop',
help='Options are "desktop" (the default) and "mobile".')
parser.add_argument('--verbose-cpu-metrics',
action='store_true',
help='Enables non-UMA CPU metrics.')
parser.add_argument('--verbose-memory-metrics',
action='store_true',
help='Enables non-UMA memory metrics.')
iter_help = (f'Number of times (default {_DEFAULT_NUM_ITERATIONS}, max '
f'{_MAX_NUM_ITERATIONS}) to repeat action for each story run.')
parser.add_argument('--iterations',
type=int,
default=_DEFAULT_NUM_ITERATIONS,
help=iter_help)
@classmethod
def ProcessCommandLineArgs(cls, parser, args):
cls.verbose_cpu_metrics = args.verbose_cpu_metrics
cls.verbose_memory_metrics = args.verbose_memory_metrics
cls.iterations = args.iterations
if cls.iterations <= 0:
raise ValueError('Got invalid value %d for iterations' % cls.iterations)
if cls.iterations > _MAX_NUM_ITERATIONS:
logging.warning('The maximum allowed number of iterations is 10. ' +
'Increase pageset_repeat instead.')
cls.iterations = _MAX_NUM_ITERATIONS
if args.xvfb and utils.ShouldStartXvfb():
cls.xvfb_process = utils.StartXvfb()
def SetExtraBrowserOptions(self, options):
# `options` is an instance of `browser_options.BrowserOptions`.
if self.verbose_memory_metrics:
memory.SetExtraBrowserOptionsForMemoryMeasurement(options)
extra_args = [
'--enable-features=' + ','.join(_ENABLED_FEATURES),
'--enable-privacy-sandbox-ads-apis'
]
if self.xvfb_process:
extra_args.append('--disable-gpu')
options.AppendExtraBrowserArgs(extra_args)
# Increase the default shutdown timeout due to some long-running tests.
os.environ['CHROME_SHUTDOWN_TIMEOUT'] = str(_SHUTDOWN_TIMEOUT)
def CustomizeOptions(self, finder_options, possible_browser=None):
#`finder_options` is an instance of `browser_options.BrowserFinderOptions`.
#
# Normally, a subclass of `perf_benchmark.PerfBenchmark` should only
# override SetExtraBrowserOptions to add more browser options rather than
# overriding CustomizeOptions. We need to access the `finder_options` to
# read the verbosity level, however, and this seems to be the best way to
# do it.
super(SharedStoragePerfBase, self).CustomizeOptions(finder_options)
self.verbosity = finder_options.verbosity
def CreateCoreTimelineBasedMeasurementOptions(self):
category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
filter_string="benchmark")
if self.verbose_memory_metrics:
tbm_options = memory.CreateCoreTimelineBasedMemoryMeasurementOptions()
# The memory options only include the filters needed for memory
# measurement. We reintroduce the filters required for other metrics.
tbm_options.ExtendTraceCategoryFilter(
category_filter.filter_string.split(','))
else:
tbm_options = timeline_based_measurement.Options(category_filter)
tbm_options.config.chrome_trace_config.SetTraceBufferSizeInKb(
_TRACE_BUFFER_SIZE)
for histogram in utils.GetSharedStorageUmaHistograms():
tbm_options.config.chrome_trace_config.EnableUMAHistograms(histogram)
tbm_options.AddTimelineBasedMetric('umaMetric')
if self.verbose_cpu_metrics:
tbm_options.AddTimelineBasedMetric('limitedCpuTimeMetric')
return tbm_options
def CreateStorySet(self, options):
# `options` is an instance of `timeline_based_measurement.Options`.
return page_set.SharedStorageStorySet(
url=self.URL,
size=self.SIZE,
enable_memory_metric=self.verbose_memory_metrics,
user_agent=options.user_agent,
iterations=self.iterations,
verbosity=self.verbosity,
xvfb_process=self.xvfb_process)
@benchmark.Info(emails=['[email protected]'],
component='Blink>Storage>SharedStorage',
documentation_url='')
class SharedStoragePerfFreshDB(SharedStoragePerfBase):
SIZE = 0
@classmethod
def Name(cls):
return 'shared_storage.fresh'
@benchmark.Info(emails=['[email protected]'],
component='Blink>Storage>SharedStorage',
documentation_url='')
class SharedStoragePerfSmallDB(SharedStoragePerfBase):
SIZE = 10
@classmethod
def Name(cls):
return 'shared_storage.small'
@benchmark.Info(emails=['[email protected]'],
component='Blink>Storage>SharedStorage',
documentation_url='')
class SharedStoragePerfMediumDB(SharedStoragePerfBase):
SIZE = 1000
@classmethod
def Name(cls):
return 'shared_storage.medium'
@benchmark.Info(emails=['[email protected]'],
component='Blink>Storage>SharedStorage',
documentation_url='')
class SharedStoragePerfLargeDB(SharedStoragePerfBase):
# TODO(cammie): Update the size for 'shared_storage.large' to 10000 when
# M124 reaches stable (and with it the change in quota enfocrement).
SIZE = 9000
@classmethod
def Name(cls):
return 'shared_storage.large'