tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

perf_trace.py (3719B)


      1 # Copyright 2025 The Chromium Authors
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 """ Retrieves the system metrics and logs them into the monitors system. """
      5 
      6 import json
      7 import os
      8 import subprocess
      9 
     10 from numbers import Number
     11 from typing import Optional
     12 
     13 import monitors
     14 
     15 from common import run_ffx_command, get_host_tool_path
     16 
     17 # Copy to avoid cycle dependency.
     18 TEMP_DIR = os.environ.get('TMPDIR', '/tmp')
     19 
     20 FXT_FILE = os.path.join(TEMP_DIR, 'perf_trace.fxt')
     21 JSON_FILE = os.path.join(TEMP_DIR, 'perf_trace.json')
     22 
     23 METRIC_FILTERS = [
     24    'gfx/ContiguousPooledMemoryAllocator::Allocate/size_bytes',
     25    'gfx/SysmemProtectedPool/size',
     26    'gfx/WindowedFramePredictor::GetPrediction/Predicted frame duration(ms)',
     27    'gfx/WindowedFramePredictor::GetPrediction/Render time(ms)',
     28    'gfx/WindowedFramePredictor::GetPrediction/Update time(ms)',
     29    'memory_monitor/bandwidth_free/value',
     30    'memory_monitor/free/free$',
     31    'system_metrics/cpu_usage/average_cpu_percentage',
     32 ]
     33 
     34 
     35 def start() -> None:
     36    """ Starts the system tracing. """
     37    # TODO(crbug.com/40935291): May include kernel:meta, kernel:sched, magma,
     38    # oemcrypto, media, kernel:syscall
     39    run_ffx_command(cmd=('trace', 'start', '--background', '--categories',
     40                         'gfx,memory_monitor,system_metrics', '--output',
     41                         FXT_FILE))
     42 
     43 
     44 def stop(prefix: Optional[str] = None) -> None:
     45    """ Stops the system tracing and logs the metrics into the monitors system
     46    with an optional prefix as part of the metric names. """
     47    run_ffx_command(cmd=('trace', 'stop'))
     48    _parse_trace(prefix)
     49 
     50 
     51 # pylint: disable=too-many-nested-blocks
     52 def _parse_trace(prefix: Optional[str] = None) -> None:
     53    subprocess.run([
     54        get_host_tool_path('trace2json'), f'--input-file={FXT_FILE}',
     55        f'--output-file={JSON_FILE}'
     56    ],
     57                   check=True)
     58    with open(JSON_FILE, 'r') as file:
     59        recorders = {}
     60        for event in json.load(file)['traceEvents']:
     61            if not 'args' in event:
     62                # Support only the events with args now.
     63                continue
     64            cat_name = [event['cat'], event['name']]
     65            if prefix:
     66                cat_name.insert(0, prefix)
     67            args = event['args']
     68            # Support only the events with str or numeric args now.
     69            for arg in args:
     70                if isinstance(args[arg], str):
     71                    cat_name.append(arg)
     72                    cat_name.append(args[arg])
     73            for arg in args:
     74                # Allows all number types.
     75                if isinstance(args[arg], Number):
     76                    name = cat_name.copy()
     77                    name.append(arg)
     78                    for f in METRIC_FILTERS:
     79                        if f in '/'.join(name) + '$':
     80                            if tuple(name) not in recorders:
     81                                recorders[tuple(name)] = monitors.average(
     82                                    *name)
     83                            recorders[tuple(name)].record(args[arg])
     84 
     85 
     86 # For tests only. To run this test, create a perf_trace.fxt in the /tmp/, run
     87 # this script and inspect /tmp/test_script_metrics.jsonpb.
     88 #
     89 # If nothing needs to be customized, the commands look like,
     90 # $ ffx trace start --background \
     91 #                   --categories 'gfx,memory_monitor,system_metrics' \
     92 #                   --output /tmp/perf_trace.fxt
     93 # -- do something on the fuchsia device --
     94 # $ ffx trace stop
     95 # $ vpython3 build/fuchsia/test/perf_trace.py
     96 #
     97 # Note, reuse the perf_trace.fxt is OK, i.e. running perf_trace.py multiple
     98 # times works.
     99 if __name__ == '__main__':
    100    _parse_trace()
    101    monitors.dump(TEMP_DIR)