Bug 1718535 [wpt PR 29519] - [Credentialless] Fix flaky reporting-subresource-corp...
[gecko.git] / tools / power / mach_commands.py
blobbce8ea5b3bf69b4fe58d9451983799ecf1fbf6bb
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 from __future__ import print_function, absolute_import
7 from distutils.version import StrictVersion
9 from mach.decorators import (
10 Command,
11 CommandArgument,
12 CommandProvider,
14 from mozbuild.base import MachCommandBase
17 def is_osx_10_10_or_greater(cls):
18 import platform
20 release = platform.mac_ver()[0]
21 return release and StrictVersion(release) >= StrictVersion("10.10")
24 @CommandProvider
25 class MachCommands(MachCommandBase):
26 """
27 Get system power consumption and related measurements.
28 """
30 @Command(
31 "power",
32 category="misc",
33 conditions=[is_osx_10_10_or_greater],
34 description="Get system power consumption and related measurements for "
35 "all running browsers. Available only on Mac OS X 10.10 and above. "
36 "Requires root access.",
38 @CommandArgument(
39 "-i",
40 "--interval",
41 type=int,
42 default=30000,
43 help="The sample period, measured in milliseconds. Defaults to 30000.",
45 def power(self, command_context, interval):
46 import os
47 import re
48 import subprocess
50 rapl = os.path.join(self.topobjdir, "dist", "bin", "rapl")
52 interval = str(interval)
54 # Run a trivial command with |sudo| to gain temporary root privileges
55 # before |rapl| and |powermetrics| are called. This ensures that |rapl|
56 # doesn't start measuring while |powermetrics| is waiting for the root
57 # password to be entered.
58 try:
59 subprocess.check_call(["sudo", "true"])
60 except Exception:
61 print("\nsudo failed; aborting")
62 return 1
64 # This runs rapl in the background because nothing in this script
65 # depends on the output. This is good because we want |rapl| and
66 # |powermetrics| to run at the same time.
67 subprocess.Popen([rapl, "-n", "1", "-i", interval])
69 lines = subprocess.check_output(
71 "sudo",
72 "powermetrics",
73 "--samplers",
74 "tasks",
75 "--show-process-coalition",
76 "--show-process-gpu",
77 "-n",
78 "1",
79 "-i",
80 interval,
82 universal_newlines=True,
85 # When run with --show-process-coalition, |powermetrics| groups outputs
86 # into process coalitions, each of which has a leader.
88 # For example, when Firefox runs from the dock, its coalition looks
89 # like this:
91 # org.mozilla.firefox
92 # firefox
93 # plugin-container
95 # When Safari runs from the dock:
97 # com.apple.Safari
98 # Safari
99 # com.apple.WebKit.Networking
100 # com.apple.WebKit.WebContent
101 # com.apple.WebKit.WebContent
103 # When Chrome runs from the dock:
105 # com.google.Chrome
106 # Google Chrome
107 # Google Chrome Helper
108 # Google Chrome Helper
110 # In these cases, we want to print the whole coalition.
112 # Also, when you run any of them from the command line, things are the
113 # same except that the leader is com.apple.Terminal and there may be
114 # non-browser processes in the coalition, e.g.:
116 # com.apple.Terminal
117 # firefox
118 # plugin-container
119 # <and possibly other, non-browser processes>
121 # Also, the WindowServer and kernel coalitions and processes are often
122 # relevant.
124 # We want to print all these but omit uninteresting coalitions. We
125 # could do this by properly parsing powermetrics output, but it's
126 # simpler and more robust to just grep for a handful of identifying
127 # strings.
129 print() # blank line between |rapl| output and |powermetrics| output
131 for line in lines.splitlines():
132 # Search for the following things.
134 # - '^Name' is for the columns headings line.
136 # - 'firefox' and 'plugin-container' are for Firefox
138 # - 'Safari\b' and 'WebKit' are for Safari. The '\b' excludes
139 # SafariCloudHistoryPush, which is a process that always
140 # runs, even when Safari isn't open.
142 # - 'Chrome' is for Chrome.
144 # - 'Terminal' is for the terminal. If no browser is running from
145 # within the terminal, it will show up unnecessarily. This is a
146 # minor disadvantage of this very simple parsing strategy.
148 # - 'WindowServer' is for the WindowServer.
150 # - 'kernel' is for the kernel.
152 if re.search(
153 r"(^Name|firefox|plugin-container|Safari\b|WebKit|Chrome|Terminal|WindowServer|kernel)", # NOQA: E501
154 line,
156 print(line)
158 return 0