chromium/tools/perf/contrib/cluster_telemetry/ad_tagging_ct.py

# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from benchmarks import memory
from contrib.cluster_telemetry import ct_benchmarks_util, page_set
from core import perf_benchmark
import py_utils
from telemetry import benchmark
from telemetry.page import cache_temperature
from telemetry.timeline import chrome_trace_category_filter
from telemetry.web_perf import timeline_based_measurement

_NAVIGATION_TIMEOUT = 180
_QUIESCENCE_TIMEOUT = 30


# Benchmark to measure various UMA histograms relevant to AdTagging as well as
# CPU usage on page loads. These measurements will help to determine the
# accuracy of AdTagging.
@benchmark.Info(emails=['[email protected]', '[email protected]'],
                component='UI>Browser>AdFilter')
class AdTaggingClusterTelemetry(perf_benchmark.PerfBenchmark):
  @classmethod
  def AddBenchmarkCommandLineArgs(cls, parser):
    ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser)
    parser.add_argument(
        '--additional-histograms',
        help='Comma-separated list of additional UMA histograms to record.')
    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.')

  @classmethod
  def ProcessCommandLineArgs(cls, parser, args):
    ct_benchmarks_util.ValidateCommandLineArgs(parser, args)
    cls.additional_histograms = []
    if args.additional_histograms is not None:
      cls.additional_histograms = args.additional_histograms.split(',')
    cls.enable_limited_cpu_time_metric = args.verbose_cpu_metrics
    cls.enable_memory_metric = args.verbose_memory_metrics

  def GetExtraOutDirectories(self):
    # The indexed filter list does not end up in a build directory on cluster
    # telemetry; so we add its location here.
    return ['/b/s/w/ir/out/telemetry_isolates']

  def SetExtraBrowserOptions(self, options):
    if self.enable_memory_metric:
      memory.SetExtraBrowserOptionsForMemoryMeasurement(options)

  def CreateCoreTimelineBasedMeasurementOptions(self):
    category_filter = chrome_trace_category_filter.CreateLowOverheadFilter()
    if self.enable_memory_metric:
      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)

    uma_histograms = [
        'PageLoad.Clients.Ads.AllPages.NonAdNetworkBytes',
        'PageLoad.Clients.Ads.AllPages.PercentNetworkBytesAds',
        'PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Total2',
        'PageLoad.Clients.Ads.Cpu.AdFrames.Aggregate.TotalUsage2',
        'PageLoad.Clients.Ads.Cpu.FullPage.TotalUsage2',
        'PageLoad.Clients.Ads.FrameCounts.AdFrames.Total',
        'PageLoad.Clients.Ads.Resources.Bytes.Ads2',
        'PageLoad.Cpu.TotalUsage',
        'PageLoad.PaintTiming.NavigationToFirstContentfulPaint',
        'SubresourceFilter.PageLoad.NumSubresourceLoads.MatchedRules',
    ]
    uma_histograms.extend(self.additional_histograms)
    for histogram in uma_histograms:
      tbm_options.config.chrome_trace_config.EnableUMAHistograms(histogram)

    tbm_options.AddTimelineBasedMetric('umaMetric')
    if self.enable_limited_cpu_time_metric:
      tbm_options.AddTimelineBasedMetric('limitedCpuTimeMetric')

    return tbm_options

  def CreateStorySet(self, options):
    enable_memory_metric = self.enable_memory_metric

    def NavigateToPageAndLeavePage(self, action_runner):
      url = self.file_path_url_with_scheme if self.is_file else self.url
      action_runner.Navigate(url,
                             self.script_to_evaluate_on_commit,
                             timeout_in_seconds=_NAVIGATION_TIMEOUT)
      try:
        py_utils.WaitFor(action_runner.tab.HasReachedQuiescence,
                         timeout=_QUIESCENCE_TIMEOUT)
      except py_utils.TimeoutException:
        pass

      # We measure memory after the wait as we want a proxy for page memory.
      if enable_memory_metric:
        action_runner.MeasureMemory(deterministic_mode=True)

      # Navigate away to an untracked page to trigger recording of page load
      # metrics
      action_runner.Navigate('about:blank',
                             self.script_to_evaluate_on_commit,
                             timeout_in_seconds=_NAVIGATION_TIMEOUT)

    return page_set.CTPageSet(
        options.urls_list,
        options.user_agent,
        options.archive_data_file,
        run_navigate_steps_callback=NavigateToPageAndLeavePage,
        cache_temperature=cache_temperature.COLD)

  @classmethod
  def Name(cls):
    return 'ad_tagging.cluster_telemetry'